From 271b8a7f59f8b59348b28d7ffaf7316aba999eed Mon Sep 17 00:00:00 2001 From: 1wgrumph <1wgrumph@gmail.com> Date: Sat, 19 Sep 2026 23:26:31 -0500 Subject: [PATCH] feat(sdoc): land the SDoc dev bridge from the orphaned bran-dev worktree MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit This work lived in /home/spectre/alphazede/worktrees/bran-dev-bridge-schema-2, a worktree whose parent repository (Alphazedehq/bran-dev) no longer exists. Its .git file still points at that deleted gitdir, so the directory had no reachable history and no branch — the content was recoverable only as files on disk. Recovered as a branch off current origin/main rather than replayed as history, because no history survives to replay. Adds crates/bran-core/src/sdoc.rs (1452 lines) and crates/bran-core/src/graph/sdoc.rs (699 lines), neither of which exists on main, plus the docs/bugs, docs/plans, docs/submissions and docs/integrations/proposals trees. 16 of the 58 files already exist on main and are modified here. The snapshot is from 2026-09-08 and main has advanced since, so those 16 are the ones to review closely: they may reintroduce superseded content. cargo check clean; cargo test 361 passed, 0 failed. Claude-Session: https://claude.ai/code/session_01WVJLGKfpF3QG5PeSiBW4LV --- .bran/policy.yaml | 14 + .closeout.json | 6 + .github/ISSUE_TEMPLATE/config.yml | 4 +- .github/workflows/bran-fast.yml | 2 - AGENTS.md | 133 ++ CLAUDE.md | 97 + CODE_OF_CONDUCT.md | 5 +- CONTRIBUTING.md | 20 +- Cargo.lock | 92 + README.md | 7 - assets/tui/raven-provenance.json | 1 + crates/bran-cli/Cargo.toml | 6 + crates/bran-cli/src/main.rs | 1000 +++++++- crates/bran-core/Cargo.toml | 9 + crates/bran-core/src/graph/mod.rs | 1 + crates/bran-core/src/graph/model.rs | 26 +- crates/bran-core/src/graph/sdoc.rs | 699 ++++++ crates/bran-core/src/lib.rs | 1 + crates/bran-core/src/sdoc.rs | 1452 ++++++++++++ docs/README.md | 29 + ...ires-on-command-tokens-not-target-paths.md | 84 + ...ranking-favors-path-tokens-over-content.md | 108 + .../enterprise-document-evidence-envelope.md | 198 ++ .../google-enterprise-attestation-profile.md | 342 +++ .../proposals/okf-bundle-scan-scope.md | 77 + .../okf-layered-profile-separation.md | 74 + .../2026-07-21-bran-okf-migration/design.md | 601 +++++ .../implementation.md | 341 +++ .../plan-spec.md | 250 ++ .../2026-07-21-bran-okf-migration/review.html | 1492 ++++++++++++ .../2026-07-21-bran-okf-migration/seit.md | 243 ++ .../design.md | 619 +++++ .../implementation.md | 475 ++++ .../plan-spec.md | 631 +++++ .../review.html | 2095 +++++++++++++++++ .../2026-07-22-bran-okf-final-cutover/seit.md | 368 +++ docs/submissions/bran-build-week/README.md | 237 ++ .../bran-build-week/customer-setup/README.md | 199 ++ .../bran-build-week/demo-recording-runbook.md | 124 + .../bran-build-week/demo-video-outline.md | 116 + .../evidence/arena-matrix-20260720.json | 165 ++ .../evidence/connected-smoke-20260720.json | 137 ++ .../evidence/enterprise-live-20260721.json | 156 ++ .../evidence/live-pilot-20260720.json | 81 + .../evidence/namespace-core-20260720.json | 147 ++ .../evidence/obsidian-core-20260720.json | 58 + .../evidence/targeted-multistep-20260721.json | 21 + .../evidence/ua-supply-chain-20260720.json | 89 + .../bran-build-week/research-paper.md | 484 ++++ .../bran-build-week/submission-checklist.md | 166 ++ public-export.json | 67 + tools/ci/enterprise_contract_check.py | 33 - tools/ci/test-budget.json | 1 - tools/cutover/consumer_gate.py | 302 +++ tools/cutover/publish-hygiene.sh | 10 + tools/cutover/retirement_gate.py | 72 + tools/cutover/validate_route.py | 192 ++ tools/cutover/verify_release.py | 114 + 58 files changed, 14512 insertions(+), 61 deletions(-) create mode 100644 .closeout.json create mode 100644 AGENTS.md create mode 100644 CLAUDE.md create mode 100644 crates/bran-core/src/graph/sdoc.rs create mode 100644 crates/bran-core/src/sdoc.rs create mode 100644 docs/README.md create mode 100644 docs/bugs/2026-07-25-hook-fires-on-command-tokens-not-target-paths.md create mode 100644 docs/bugs/2026-07-25-query-ranking-favors-path-tokens-over-content.md create mode 100644 docs/integrations/proposals/enterprise-document-evidence-envelope.md create mode 100644 docs/integrations/proposals/google-enterprise-attestation-profile.md create mode 100644 docs/integrations/proposals/okf-bundle-scan-scope.md create mode 100644 docs/integrations/proposals/okf-layered-profile-separation.md create mode 100644 docs/plans/2026-07-21-bran-okf-migration/design.md create mode 100644 docs/plans/2026-07-21-bran-okf-migration/implementation.md create mode 100644 docs/plans/2026-07-21-bran-okf-migration/plan-spec.md create mode 100644 docs/plans/2026-07-21-bran-okf-migration/review.html create mode 100644 docs/plans/2026-07-21-bran-okf-migration/seit.md create mode 100644 docs/plans/2026-07-22-bran-okf-final-cutover/design.md create mode 100644 docs/plans/2026-07-22-bran-okf-final-cutover/implementation.md create mode 100644 docs/plans/2026-07-22-bran-okf-final-cutover/plan-spec.md create mode 100644 docs/plans/2026-07-22-bran-okf-final-cutover/review.html create mode 100644 docs/plans/2026-07-22-bran-okf-final-cutover/seit.md create mode 100644 docs/submissions/bran-build-week/README.md create mode 100644 docs/submissions/bran-build-week/customer-setup/README.md create mode 100644 docs/submissions/bran-build-week/demo-recording-runbook.md create mode 100644 docs/submissions/bran-build-week/demo-video-outline.md create mode 100644 docs/submissions/bran-build-week/evidence/arena-matrix-20260720.json create mode 100644 docs/submissions/bran-build-week/evidence/connected-smoke-20260720.json create mode 100644 docs/submissions/bran-build-week/evidence/enterprise-live-20260721.json create mode 100644 docs/submissions/bran-build-week/evidence/live-pilot-20260720.json create mode 100644 docs/submissions/bran-build-week/evidence/namespace-core-20260720.json create mode 100644 docs/submissions/bran-build-week/evidence/obsidian-core-20260720.json create mode 100644 docs/submissions/bran-build-week/evidence/targeted-multistep-20260721.json create mode 100644 docs/submissions/bran-build-week/evidence/ua-supply-chain-20260720.json create mode 100644 docs/submissions/bran-build-week/research-paper.md create mode 100644 docs/submissions/bran-build-week/submission-checklist.md create mode 100644 public-export.json create mode 100644 tools/cutover/consumer_gate.py create mode 100755 tools/cutover/publish-hygiene.sh create mode 100644 tools/cutover/retirement_gate.py create mode 100644 tools/cutover/validate_route.py create mode 100644 tools/cutover/verify_release.py diff --git a/.bran/policy.yaml b/.bran/policy.yaml index a1ba652..1a4c7c1 100644 --- a/.bran/policy.yaml +++ b/.bran/policy.yaml @@ -56,6 +56,20 @@ coverage: - unclassified document_coverage: + canonical_documents: + - AGENTS.md + - CLAUDE.md + - docs/README.md + - docs/bugs/2026-07-25-hook-fires-on-command-tokens-not-target-paths.md + - docs/bugs/2026-07-25-query-ranking-favors-path-tokens-over-content.md + - docs/integrations/proposals/okf-bundle-scan-scope.md + - docs/integrations/proposals/okf-layered-profile-separation.md + - docs/submissions/bran-build-week/README.md + - docs/submissions/bran-build-week/customer-setup/README.md + - docs/submissions/bran-build-week/demo-recording-runbook.md + - docs/submissions/bran-build-week/demo-video-outline.md + - docs/submissions/bran-build-week/research-paper.md + - docs/submissions/bran-build-week/submission-checklist.md legacy_documents: - README.md - docs/integrations/agent-setup.md diff --git a/.closeout.json b/.closeout.json new file mode 100644 index 0000000..59cc1a7 --- /dev/null +++ b/.closeout.json @@ -0,0 +1,6 @@ +{ + "commands": [ + { "id": "fast", "run": "./tools/ci/check.sh --fast", "blocking": true }, + { "id": "drift-guard", "run": "python3 tools/ci/public_export.py check --public-dir ../../bran", "blocking": true } + ] +} diff --git a/.github/ISSUE_TEMPLATE/config.yml b/.github/ISSUE_TEMPLATE/config.yml index 9d42d68..42609ae 100644 --- a/.github/ISSUE_TEMPLATE/config.yml +++ b/.github/ISSUE_TEMPLATE/config.yml @@ -1,5 +1,5 @@ blank_issues_enabled: true contact_links: - name: Security issue - url: https://github.com/alphazede/bran/security/advisories/new - about: Don't file security problems publicly. Use a private GitHub security advisory. + url: https://github.com/alphazede/bran/blob/main/CONTRIBUTING.md#security + about: Don't file security problems publicly. See CONTRIBUTING for how to report them. diff --git a/.github/workflows/bran-fast.yml b/.github/workflows/bran-fast.yml index dec1ed1..46b0ecb 100644 --- a/.github/workflows/bran-fast.yml +++ b/.github/workflows/bran-fast.yml @@ -4,14 +4,12 @@ on: pull_request: push: branches: [main] - workflow_dispatch: permissions: contents: read jobs: fast: - if: ${{ !(github.event_name == 'push' && github.repository == 'alphazede/bran-dev' && github.event.repository.private == true && github.event.repository.custom_properties.delivery_profile == 'private-owner-direct') }} runs-on: ubuntu-24.04 timeout-minutes: 30 steps: diff --git a/AGENTS.md b/AGENTS.md new file mode 100644 index 0000000..2dbbb6d --- /dev/null +++ b/AGENTS.md @@ -0,0 +1,133 @@ +--- +type: agent-instructions +title: BRAN Internal Repository Instructions +okf_status: active +status: stable +tags: + - internal + - bran +freshness: "2026-08-18" +resource: https://github.com/alphazede/bran-dev +public_boundary: private +--- + +# BRAN Agent Instructions + +This is BRAN's main development workspace. Make every source, test, +documentation, planning, and research change here first. Send exported changes +to `alphazede/bran` only as reviewed snapshots through the approved export and +pull-request sync process; do not develop or manually edit BRAN in that +checkout. + +The exporter builds a reviewed snapshot from a committed revision. That +snapshot must never run ahead of this repository or include private plans, +submission evidence, unpublished proposals, agent instructions, or local +`.bran` data. + +## Repository map + +See the [documentation index](docs/README.md) for integration guides, plans, +and submissions. + +- `crates/`: Rust source for Core, CLI, and TUI. +- `schemas/`, `fixtures/`, `examples/`, and `benches/`: schemas, test data, + examples, and benchmarks. +- `docs/integrations/`: integration guides that may ship with BRAN. +- `docs/plans/`: internal BRAN plans. Follow its path-specific `AGENTS.md`. +- `docs/submissions/`: private research and submission evidence. Keep it out of + exports unless the owner approves a scrubbed artifact. +- `skill/use-bran/`: the BRAN skill for agent integrations. + +The separate Arena harness lives at +`/home/spectre/alphazede/agentic-eval-arena`; keep harness implementation and +hidden evaluation material there. + +## Working rules + +1. Make BRAN source changes here. Use `alphazede/bran` only to receive an + approved exported snapshot through a pull request; do not develop or + manually edit BRAN there. +2. Keep scanning, ranking, packet generation, and offline browsing usable + without a provider account. +3. Never add credentials, raw authentication state, private corpora, hidden + grader truth, or unsanitized provider traces. +4. Report requested, effective, and attested capabilities separately. If + something is unavailable, say so. +5. Treat exporting, syncing, tagging, releasing, and publishing as separate + actions. Each requires owner approval. +6. Preserve unrelated user changes. Remove a temporary branch or worktree only + after proving it is clean and reachable from its integration branch. + +## Validation + +Run the smallest relevant test while you work. For most integrated changes, +run: + +```sh +./tools/cutover/publish-hygiene.sh +./tools/ci/check.sh --fast +``` + +`./tools/cutover/publish-hygiene.sh` calls the shared workspace guard and derives the +public surface from `public-export.json`. It fails closed when `okf_status` or +`public_boundary` frontmatter would be exported. A bare `type:` remains valid. +For `SKILL.md`, this is also a correctness check because agent hosts parse its +frontmatter. + +A packaged release binary must be built through `build/build-pinned.sh`, which +compiles the StrictDoc bridge pins in and re-hashes every pinned file first. See +[`build/README.md`](build/README.md); a bare `cargo build --release` produces a +binary whose `sdoc` command fails closed as `sdoc_runtime_unavailable`. + +Reserve `./tools/ci/check.sh --full` for changes that affect release, security, +conformance, or performance behavior. Do not install missing tools or contact +live providers solely to validate a local source change. + +`okf-v0.1` remains a supported selectable compatibility profile. `okf-v0.2` is +additive and does not replace it. Native policy keeps the BRAN producer +extensions `okf_status`, `freshness`, and `public_boundary`. When a document +also carries the OKF v0.2 `status` field, the mapping is `draft` → `draft`, +`active` → `stable`, and `deprecated` → `deprecated`. Optional v0.2 +`stale_after` is allowed only when a real expiry date exists; it is not a +rename of `freshness` and is not required. + +## Preparing a clean snapshot + +`public-export.json` lists what may and may not ship. Every tracked path must be +classified, and any unclassified path stops the export. The exporter reads +committed Git blobs, never files from an uncommitted working tree. + +From a clean committed `bran-dev` checkout, create a new scrubbed snapshot in +an absent or empty directory: + +```sh +python3 tools/ci/public_export.py snapshot --output /path/to/empty/snapshot +``` + +After committing the snapshot, compare its contents and file modes, export +receipt, Git state, and configured remote: + +```sh +python3 tools/ci/public_export.py check --public-dir /path/to/bran +``` + +Before pushing, inspect every exported file for private or sensitive data. Then +run the hygiene gate. + +The source is a reviewed committed bran-dev revision and the checked snapshot +was produced by the approved exporter. Push that committed checked snapshot to +a generic non-default branch in `alphazede/bran`. Open a draft PR targeting +public main. The PR body must name the exact bran-dev source commit, the exact +public export commit, and validation evidence. Public `main` is protected and +cannot be pushed to directly. Wait for the required fast and CodeQL checks to +pass. Owner review of the exact exported diff and separate authorization to +merge are required; only then merge the pull request with a merge commit. Never +squash-merge an export: squashing discards the reviewed export commits and +rewrites the published snapshot into a commit no reviewer approved. The exporter +does not open pull requests. Passing the export checks does not authorize tagging or +publishing a package. + + +## Fixable review findings + +Never pass or accept `ACCEPT_WITH_FINDINGS` while a fixable bug remains. If an actionable review finding can be repaired without causing a regression or violating the approved contract, the verdict is `REPAIR_REQUIRED`; fix it in the authorized repair round and rerun deterministic verification. `ACCEPT_WITH_FINDINGS` is reserved for owner-approved residual risk or a finding that cannot be repaired within the approved contract without causing a regression. diff --git a/CLAUDE.md b/CLAUDE.md new file mode 100644 index 0000000..04e62b2 --- /dev/null +++ b/CLAUDE.md @@ -0,0 +1,97 @@ +--- +type: repository-guide +title: BRAN Claude Code Guide +okf_status: active +status: stable +tags: + - internal + - bran +freshness: "2026-08-18" +resource: https://github.com/alphazede/bran-dev +public_boundary: private +--- + +# CLAUDE.md — BRAN + +**You are Claude Code** — implementer and reviewer for BRAN. + +> Claude Code does **not** auto-load `AGENTS.md`. Open [`AGENTS.md`](AGENTS.md) +> on session start (and the path-specific `docs/plans/AGENTS.md` inside a plan +> dir). [`AGENTS.md`](AGENTS.md) is canonical; this file is the Claude-Code +> lens over it. + +This private `alphazede/bran-dev` repository is the canonical workspace for +BRAN source, planning, and research. The public `alphazede/bran` repository is +a downstream product export, **not** the place to develop or manually edit +BRAN. It receives approved exported snapshots only through pull requests. Use +`$use-bran` for architecture, terminology, and knowledge questions when the OKF +overlay is present. + +## Repository map + +- `crates/` — Rust source for Core, CLI, and TUI. +- `schemas/`, `fixtures/`, `examples/`, `benches/` — contracts and evidence. +- `docs/integrations/` — public-compatible integration guidance. +- `docs/plans/` — internal BRAN plans (follow its path-specific `AGENTS.md`). +- `docs/submissions/` — private research/submission evidence; never copy into a + public repo without an explicit scrub and owner approval. +- `skill/use-bran/` — the public agent-facing BRAN skill. +- Arena harness lives separately at `/home/spectre/alphazede/agentic-eval-arena` + — keep harness implementation and hidden evaluation material there. + +## Working rules (full detail in `AGENTS.md`) + +1. Make BRAN source changes **here**; use `alphazede/bran` only for approved + pull-request syncs of exported snapshots. +2. Keep deterministic scanning, ranking, packets, and offline operation usable + without a provider account. +3. Never add credentials, raw auth state, private corpora, hidden grader truth, + or unsanitized provider traces. No AI model coauthor lines in commits. +4. Keep requested capability separate from effective/attested capability; + unavailable behavior must remain visible. +5. Treat public export, public-repository sync, release, tag creation, and + publication as separate owner-authorized actions. +6. Preserve unrelated user changes. Remove a temporary branch/worktree only + after proving it is clean and reachable from its integration branch. + +## Validation + +Use the narrowest relevant test while working. Normal integrated check: + +```sh +./tools/cutover/publish-hygiene.sh +./tools/ci/check.sh --fast +``` + +Build a packaged release binary with `build/build-pinned.sh`, not a bare +`cargo build --release`; see [`build/README.md`](build/README.md). + +The publish-hygiene command uses the shared `Alphazedehq` implementation and +derives BRAN's public files from `public-export.json`; any reported +classification metadata blocks export readiness. + +Use `./tools/ci/check.sh --full` only when the change affects the full release, +security, conformance, or performance surface. Do not install missing tools or +run live provider evaluations merely to satisfy a local source change. + +Public snapshots are governed by `public-export.json` and produced only from a +clean committed source with `python3 tools/ci/public_export.py snapshot`. Use +the tool's `check` command against the public checkout before any sync or +release action; it fails closed on content, mode, receipt, worktree, or remote +drift. Inspect every exported file for private or sensitive data, then run the +hygiene gate. The source is a reviewed committed bran-dev revision and the +checked snapshot was produced by the approved exporter. Push that committed +checked snapshot to a generic non-default branch. Open a draft PR targeting +public main. The PR body must name the exact bran-dev source commit, the exact +public export commit, and validation evidence. Public `main` is protected and +cannot be pushed to directly. Wait for the required fast and CodeQL checks to +pass. Owner review of the exact exported diff and separate authorization to +merge are required; only then merge it with a merge commit. Never squash-merge +an export: squashing discards the reviewed export commits and rewrites the +published snapshot into a commit no reviewer approved. The exporter does not +open pull requests. + + +## Fixable review findings + +Never pass or accept `ACCEPT_WITH_FINDINGS` while a fixable bug remains. If an actionable review finding can be repaired without causing a regression or violating the approved contract, the verdict is `REPAIR_REQUIRED`; fix it in the authorized repair round and rerun deterministic verification. `ACCEPT_WITH_FINDINGS` is reserved for owner-approved residual risk or a finding that cannot be repaired within the approved contract without causing a regression. diff --git a/CODE_OF_CONDUCT.md b/CODE_OF_CONDUCT.md index f71e54e..3262dcb 100644 --- a/CODE_OF_CONDUCT.md +++ b/CODE_OF_CONDUCT.md @@ -29,9 +29,8 @@ any public space where you're speaking for BRAN. ## Reporting -Report privately through -[GitHub Security Advisories](https://github.com/alphazede/bran/security/advisories/new) -and state that it is a code of conduct report. Do not open a public issue. +Email 1wgrumph@gmail.com. Reports stay private, and I'll respond as quickly as +I reasonably can. I'll decide what action to take, up to and including blocking someone from the project. If your behaviour makes the project worse for other people, you'll be diff --git a/CONTRIBUTING.md b/CONTRIBUTING.md index 63bf321..9f13c21 100644 --- a/CONTRIBUTING.md +++ b/CONTRIBUTING.md @@ -4,13 +4,18 @@ Thanks for taking a look. Bug reports are genuinely useful, and the ranking heuristics are where I've been wrong most often, so that's a good place to push. -## This repository +## First, a note about this repository -This is the canonical BRAN source. Issues and pull requests belong here. +This repository is a published snapshot. BRAN is developed somewhere else, and +the code here is exported from there and signed. -Open a branch, send a PR against `main`, and keep `./tools/ci/check.sh --fast` -green. Please don't include anything private in issues or PRs. Repository -paths, source excerpts, and query text often carry more than you'd expect. +**That means pull requests opened here can't be merged.** Not because they +aren't welcome, but because the next export would overwrite them. Sorry. If you +want to change something, open an issue and we'll work out the shape of it +first. If a change is worth making, I'll carry it upstream and credit you in +the commit. + +Issues, questions, and bug reports are all in the right place here. ## Building and testing @@ -61,9 +66,8 @@ reported separately, on purpose. ## Security -Don't open a public issue for a security problem. Report it privately through -[GitHub Security Advisories](https://github.com/alphazede/bran/security/advisories/new). -See [SECURITY.md](SECURITY.md). +Don't open a public issue for a security problem. Email 1wgrumph@gmail.com +instead and I'll deal with it. ## Licence diff --git a/Cargo.lock b/Cargo.lock index 65fb6db..ca47348 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -26,6 +26,9 @@ dependencies = [ [[package]] name = "bran-core" version = "0.1.0" +dependencies = [ + "serde_json", +] [[package]] name = "bran-tui" @@ -123,6 +126,12 @@ dependencies = [ "hashbrown", ] +[[package]] +name = "itoa" +version = "1.0.18" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8f42a60cbdf9a97f5d2305f08a87dc4e09308d1276d28c869c684d7777685682" + [[package]] name = "libc" version = "0.2.186" @@ -207,6 +216,24 @@ dependencies = [ "windows-link", ] +[[package]] +name = "proc-macro2" +version = "1.0.107" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "985e7ec9bb745e6ce6535b544d84d6cd6f7ad8bd711c398938ae983b91a766d9" +dependencies = [ + "unicode-ident", +] + +[[package]] +name = "quote" +version = "1.0.47" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1fbf4db142a473a8d80c26bbf18454ed458bf8d26c8219c331daecfdbd079001" +dependencies = [ + "proc-macro2", +] + [[package]] name = "redox_syscall" version = "0.5.18" @@ -235,6 +262,48 @@ version = "1.2.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "94143f37725109f92c262ed2cf5e59bce7498c01bcc1502d7b9afe439a4e9f49" +[[package]] +name = "serde" +version = "1.0.229" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "4148590afebada386688f18773da617792bf2ef03ffc1e4cbd2b1d45b023e0ba" +dependencies = [ + "serde_core", +] + +[[package]] +name = "serde_core" +version = "1.0.229" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "67dca2c9c51e58a4791a4b1ed58308b39c64224d349a935ab5039aa360942a48" +dependencies = [ + "serde_derive", +] + +[[package]] +name = "serde_derive" +version = "1.0.229" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e7a5d71263a5a7d47b41f6b3f06ba276f10cc18b0931f1799f710578e2309348" +dependencies = [ + "proc-macro2", + "quote", + "syn", +] + +[[package]] +name = "serde_json" +version = "1.0.151" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c841b55ecdae098c80dcae9cf767f6f8a0c2cdb3416bbef72181df4d0fe73f14" +dependencies = [ + "itoa", + "memchr", + "serde", + "serde_core", + "zmij", +] + [[package]] name = "signal-hook" version = "0.3.18" @@ -278,12 +347,29 @@ version = "1.15.2" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "8ed6a63f02c8539c91a8685a86f4099661ba3da017932f6ebbea6de3f0fa7c90" +[[package]] +name = "syn" +version = "3.0.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "53e9bae58849f64dfa4f5d5ae372c8341f7305f82a3868709269343628b659a3" +dependencies = [ + "proc-macro2", + "quote", + "unicode-ident", +] + [[package]] name = "typed-path" version = "0.12.3" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "8e28f89b80c87b8fb0cf04ab448d5dd0dd0ade2f8891bae878de66a75a28600e" +[[package]] +name = "unicode-ident" +version = "1.0.24" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e6e4313cd5fcd3dad5cafa179702e2b244f760991f45397d14d4ebf38247da75" + [[package]] name = "wasi" version = "0.11.1+wasi-snapshot-preview1" @@ -346,3 +432,9 @@ dependencies = [ "memchr", "typed-path", ] + +[[package]] +name = "zmij" +version = "1.0.23" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "29666d0abbfad1e3dc4dcf6144730dd3a3ab225bbbdac83319345b1b44ccfc1b" diff --git a/README.md b/README.md index bf6ff8c..9ef1dd1 100644 --- a/README.md +++ b/README.md @@ -225,13 +225,6 @@ bran -p --agent --offline --no-session "offline return proof" If a capability is unavailable, BRAN says `unavailable` rather than pretending it worked. Requested and effective capability are always reported separately. -## Development - -This repository is the BRAN source. See [CONTRIBUTING.md](CONTRIBUTING.md) to -build, test, and open a pull request. Report vulnerabilities privately through -[GitHub Security Advisories](https://github.com/alphazede/bran/security/advisories/new); -do not open a public issue. - ## Use it with an agent Giving an agent access is not enough. Without a reminder it reaches for diff --git a/assets/tui/raven-provenance.json b/assets/tui/raven-provenance.json index 33a40ee..585e08a 100644 --- a/assets/tui/raven-provenance.json +++ b/assets/tui/raven-provenance.json @@ -1,4 +1,5 @@ { + "source_reference_path": "/tmp/codex-clipboard-60aMGz.png", "source_reference_sha256": "763b8d9bd431ece3e83bc0f8ef6544c6472fd214571956965e0bdc589df5286f", "creation_method": "agent-authored character artwork", "converter": "not_used", diff --git a/crates/bran-cli/Cargo.toml b/crates/bran-cli/Cargo.toml index 21b25cc..fe0551f 100644 --- a/crates/bran-cli/Cargo.toml +++ b/crates/bran-cli/Cargo.toml @@ -9,6 +9,12 @@ bran-core = { path = "../bran-core", version = "0.1.0" } bran-tui = { path = "../bran-tui", version = "0.1.0" } crossterm = { version = "=0.29.0", default-features = false, features = ["events", "windows"] } +# Test-only: enables `SdocBridgeConfig::new` for the CLI's fixture-bridge tests. +# Cargo unifies this with the normal dependency when building tests, and leaves +# it off for `cargo build --release`, which builds no dev-dependency. +[dev-dependencies] +bran-core = { path = "../bran-core", version = "0.1.0", features = ["test-fixtures"] } + [[bin]] name = "bran" path = "src/main.rs" diff --git a/crates/bran-cli/src/main.rs b/crates/bran-cli/src/main.rs index b978745..767d20e 100644 --- a/crates/bran-cli/src/main.rs +++ b/crates/bran-cli/src/main.rs @@ -53,6 +53,7 @@ use bran_core::profile::BRAN_STRICT; use bran_core::profile::{Diagnostic, ProfileValidator, ValidationStatus}; use bran_core::repair::{MaintainerAuthority, RepairCoordinator, RepairReceipt, RepairTerminal}; use bran_core::scan::{is_knowledge_document_path, RepositoryScanner, ScanConfig, ScanSnapshot}; +use bran_core::sdoc::{SdocBridgeConfig, SdocError, SdocReceipt, SdocScanner}; use bran_core::view::{ Presentation, ViewCompiler, ViewField, ViewFilter, ViewGrouping, ViewSort, ViewSource, ViewSpec, }; @@ -68,6 +69,8 @@ const SMOKE_OUTPUT: &str = r#"{"schema_version":"1.0.0","command":"smoke","statu const MISSING_COMMAND_ERROR: &str = r#"{"schema_version":"1.0.0","command":"","status":"error","data":null,"warnings":[],"failures":["missing_command"],"provenance":{},"metrics":{}}"#; const UNKNOWN_COMMAND_ERROR: &str = r#"{"schema_version":"1.0.0","command":"","status":"error","data":null,"warnings":[],"failures":["unknown_command"],"provenance":{},"metrics":{}}"#; const VERSION_OUTPUT: &str = concat!("bran ", env!("CARGO_PKG_VERSION")); +const SDOC_POLICY_CATALOG_SHA256: &str = + "3b21593cf0f11f4cebd3a72903768016e92805b7dccc1cbf54b8f7ab0abbeed7"; const HELP_OUTPUT: &str = "BRAN repository evidence CLI Usage: bran [arguments] @@ -80,6 +83,7 @@ Commands: query --add-dir --record packet check [--policy-stdin] + sdoc [request] maintain ... evidence tui @@ -454,6 +458,7 @@ impl CliApp { )), } } + "sdoc" => do_sdoc_command(&mut it), "maintain" => { // Smallest model-neutral headless maintainer adapter over bran_core::repair::RepairCoordinator. // Positional args per MVP contract. All responses use ordered envelope. @@ -2330,6 +2335,610 @@ fn do_query(root: String, query_text: String, record: bool) -> QueryPacketResult Ok(("ok", data, warns, vec![], provenance, metrics)) } +#[derive(Clone, Copy)] +enum SdocCommand { + Check, + Query, +} + +struct SdocCommandArgs { + command: SdocCommand, + root: String, + query: String, +} + +struct SdocFinding { + kind: &'static str, + code: String, + locators: Vec, +} + +fn do_sdoc_command(arguments: &mut I) -> CliResult +where + I: Iterator, + I::Item: AsRef, +{ + let subcommand = match arguments + .next() + .and_then(|value| value.as_ref().to_str().map(str::to_owned)) + { + Some(value) if value == "check" => SdocCommand::Check, + Some(value) if value == "query" => SdocCommand::Query, + Some(_) => return CliResult::usage(make_sdoc_error("unknown_subcommand")), + None => return CliResult::usage(make_sdoc_error("missing_subcommand")), + }; + let values = match arguments + .map(|value| value.as_ref().to_str().map(str::to_owned)) + .collect::>>() + { + Some(values) => values, + None => return CliResult::usage(make_sdoc_error("invalid_utf8")), + }; + let args = match parse_sdoc_args(subcommand, values) { + Ok(args) => args, + Err(code) => return CliResult::usage(make_sdoc_error(code)), + }; + let bridge = match SdocBridgeConfig::pinned_installation() { + Ok(config) => config, + Err(error) => return sdoc_operation_error(sdoc_error_code(&error)), + }; + run_sdoc(&args, bridge) +} + +/// Runs one parsed SDoc request against an already-resolved bridge. Production +/// callers reach this only through [`do_sdoc_command`], which supplies +/// `SdocBridgeConfig::pinned_installation`; tests inject a fixture bridge so +/// the reporting behaviour is exercised without production pins. +fn run_sdoc(args: &SdocCommandArgs, bridge: SdocBridgeConfig) -> CliResult { + let scanner = match SdocScanner::new(&args.root, bridge) { + Ok(scanner) => scanner, + Err(error) => return sdoc_operation_error(sdoc_error_code(&error)), + }; + let mut receipts = match scanner.scan() { + Ok(receipts) => receipts, + Err(error) => return sdoc_operation_error(sdoc_error_code(&error)), + }; + normalize_sdoc_receipts(&mut receipts); + match args.command { + SdocCommand::Check => sdoc_check_result(&args.root, &receipts), + SdocCommand::Query => sdoc_query_result(&args.root, &args.query, &receipts), + } +} + +fn parse_sdoc_args( + command: SdocCommand, + values: Vec, +) -> Result { + let Some(root) = values.first().filter(|value| !value.starts_with('-')) else { + return Err("missing_root"); + }; + let query = values[1..].join(" "); + if matches!(command, SdocCommand::Check) && !query.is_empty() { + return Err("unexpected_argument"); + } + if matches!(command, SdocCommand::Query) && query.trim().is_empty() { + return Err("missing_query"); + } + Ok(SdocCommandArgs { + command, + root: root.clone(), + query, + }) +} + +fn sdoc_check_result(root: &str, receipts: &[SdocReceipt]) -> CliResult { + let mut findings = sdoc_document_findings(receipts); + match bran_core::graph::sdoc::graph_input(receipts) { + Ok(_) => {} + Err(error) => findings.push(sdoc_graph_finding(&error)), + } + let data = sdoc_check_json(root, receipts, &findings); + if findings.is_empty() { + CliResult::success(make_envelope( + "sdoc", + "ok", + &data, + &[], + &[], + "{\"sources\":[\"strictdoc-bridge\",\"bran-core\"]}", + &sdoc_metrics_json(receipts), + )) + } else { + CliResult { + output: make_envelope( + "sdoc", + "failed", + &data, + &[], + &findings + .iter() + .map(|finding| finding.code.clone()) + .collect::>(), + "{\"sources\":[\"strictdoc-bridge\",\"bran-core\"]}", + &sdoc_metrics_json(receipts), + ), + exit_code: TypedExit::Validation.code(), + is_error: true, + is_interactive: false, + } + } +} + +fn sdoc_query_result(root: &str, query: &str, receipts: &[SdocReceipt]) -> CliResult { + let input = match bran_core::graph::sdoc::graph_input(receipts) { + Ok(input) => input, + Err(error) => return sdoc_operation_error(&sdoc_graph_error_code(&error)), + }; + let limits = match GraphLimits::new(input.nodes().len().max(1), input.edges().len().max(1)) { + Ok(limits) => limits, + Err(_) => return sdoc_operation_error("sdoc_graph_limits"), + }; + let graph = match KnowledgeGraph::build(input, limits) { + Ok(graph) => graph, + Err(_) => return sdoc_operation_error("sdoc_graph_invalid"), + }; + let ranked = bran_core::graph::sdoc::rank(&graph, query, QUERY_RESULT_LIMIT); + let evidence_state = if ranked.is_empty() { "miss" } else { "hit" }; + let data = format!( + "{{\"root\":\"{}\",\"query\":\"{}\",\"evidence_state\":\"{}\",\"coverage\":{},\"results\":[{}],\"findings\":[{}]}}", + json_escape(root), + json_escape(query), + evidence_state, + sdoc_coverage_json(receipts), + ranked.iter().map(sdoc_ranked_json).collect::>().join(","), + sdoc_findings_json(&sdoc_document_findings(receipts)), + ); + CliResult::success(make_envelope( + "sdoc", + "ok", + &data, + &[], + &[], + "{\"sources\":[\"strictdoc-bridge\",\"bran-core\"]}", + &sdoc_metrics_json(receipts), + )) +} + +fn make_sdoc_error(detail: &str) -> String { + make_envelope( + "sdoc", + "error", + "null", + &[], + &[detail.to_owned()], + "{}", + "{}", + ) +} + +fn sdoc_operation_error(code: &str) -> CliResult { + CliResult::operation(make_sdoc_error(code)) +} + +fn sdoc_error_code(error: &SdocError) -> &'static str { + match error { + SdocError::InvalidRoot(_) => "sdoc_invalid_root", + SdocError::RelativeBridgeProgram => "relative_program", + SdocError::RelativeBridgeInput => "relative_bridge_input", + SdocError::PinnedRuntimeUnavailable => "sdoc_runtime_unavailable", + SdocError::QualifiedRuntimeMismatch => "sdoc_runtime_mismatch", + SdocError::UnpinnedRuntimeContent => "sdoc_runtime_unpinned_content", + SdocError::ScanLimit => "sdoc_scan_limit", + SdocError::Scan(_) => "sdoc_scan_failed", + SdocError::SourceMissing(_) => "sdoc_source_missing", + SdocError::SourceEscape(_) => "sdoc_source_escape", + SdocError::SourceChanged(_) => "sdoc_source_changed", + SdocError::BridgeTransport => "sdoc_bridge_transport", + SdocError::BridgeExit(_) => "sdoc_bridge_exit", + SdocError::MalformedJson => "sdoc_malformed_json", + SdocError::Protocol => "sdoc_protocol_mismatch", + SdocError::SchemaVersion => "sdoc_schema_mismatch", + SdocError::ModeMismatch => "sdoc_mode_mismatch", + SdocError::EngineMismatch => "sdoc_engine_mismatch", + SdocError::SourceReceiptMismatch => "sdoc_source_receipt_mismatch", + SdocError::UnsafeLocator => "sdoc_unsafe_locator", + SdocError::BridgeStatus { .. } => "sdoc_bridge_rejected", + SdocError::InvalidEnvelope(_) => "sdoc_invalid_envelope", + } +} + +fn sdoc_graph_error_code(error: &bran_core::graph::sdoc::SdocGraphError) -> String { + match error { + bran_core::graph::sdoc::SdocGraphError::DuplicateMid { .. } => "sdoc_duplicate_mid", + bran_core::graph::sdoc::SdocGraphError::DuplicateUid { .. } => "sdoc_duplicate_uid", + bran_core::graph::sdoc::SdocGraphError::DuplicateRelationMid(_) => { + "sdoc_duplicate_relation_mid" + } + bran_core::graph::sdoc::SdocGraphError::UnresolvedRelation { .. } => { + "sdoc_unresolved_relation" + } + bran_core::graph::sdoc::SdocGraphError::Graph(_) => "sdoc_graph_invalid", + } + .to_owned() +} + +fn sdoc_graph_finding(error: &bran_core::graph::sdoc::SdocGraphError) -> SdocFinding { + let code = sdoc_graph_error_code(error); + let locators = match error { + bran_core::graph::sdoc::SdocGraphError::DuplicateMid { + first_locator, + second_locator, + .. + } => vec![first_locator.clone(), second_locator.clone()], + _ => Vec::new(), + }; + let kind = if code.contains("duplicate") { + "duplicate" + } else if code.contains("unresolved") { + "unresolved" + } else { + "parse" + }; + SdocFinding { + kind, + code, + locators, + } +} + +fn sdoc_document_findings(receipts: &[SdocReceipt]) -> Vec { + let mut findings = Vec::new(); + for receipt in receipts { + let metadata = &receipt.document.metadata; + for field in [ + "type", + "title", + "okf_status", + "tags", + "resource", + "freshness", + "public_boundary", + "grammar_version", + "published_revision", + ] { + if metadata + .get(field) + .is_none_or(|value| value.trim().is_empty()) + { + findings.push(sdoc_finding( + "policy", + "sdoc_metadata_required", + &receipt.source_locator, + receipt.document.line_range.start, + )); + } + } + if !metadata.get("type").is_some_and(|value| { + matches!( + value.as_str(), + "architecture-specification" | "requirement-library" + ) + }) { + findings.push(sdoc_finding( + "policy", + "sdoc_metadata_type", + &receipt.source_locator, + receipt.document.line_range.start, + )); + } + if !valid_sdoc_mid(&receipt.document.mid) { + findings.push(sdoc_finding( + "policy", + "sdoc_invalid_mid", + &receipt.source_locator, + receipt.document.line_range.start, + )); + } + for node in &receipt.nodes { + if node.node_type.eq_ignore_ascii_case("requirement") { + for field in [ + "MID", + "UID", + "TITLE", + "STATUS", + "SOURCE", + "OWNER", + "STATEMENT", + "RATIONALE", + "ASSUMPTIONS", + "CONSTRAINTS", + "VERIFICATION_METHOD", + "VERIFICATION_LEVEL", + "VERIFICATION_ENVIRONMENT", + "SUCCESS_CRITERIA", + "VALIDATION_METHOD", + "VERIFICATION_CASE", + "EXPECTED_RESULT", + "ACTUAL_RESULT", + "ANOMALY", + "CORRECTIVE_ACTION", + "WAIVER", + "CLOSURE", + ] { + if node + .fields + .get(field) + .is_none_or(|value| value.trim().is_empty()) + { + findings.push(sdoc_finding( + "policy", + "sdoc_requirement_required", + &receipt.source_locator, + node.line_range.start, + )); + } + } + if !matches!( + node.fields.get("STATUS").map(String::as_str), + Some("Draft" | "Published" | "Superseded" | "Retired") + ) { + findings.push(sdoc_finding( + "policy", + "sdoc_requirement_status", + &receipt.source_locator, + node.line_range.start, + )); + } + if !valid_sdoc_mid(&node.mid) { + findings.push(sdoc_finding( + "policy", + "sdoc_invalid_mid", + &receipt.source_locator, + node.line_range.start, + )); + } + } + } + for relation in &receipt.relations { + if !valid_sdoc_mid(&relation.mid) + || !valid_sdoc_mid(&relation.source_mid) + || !valid_sdoc_mid(&relation.target_mid) + { + findings.push(sdoc_finding( + "policy", + "sdoc_relation_mid", + &receipt.source_locator, + relation.line_range.start, + )); + } + if !matches!( + relation.relation_type.as_str(), + "derives-from" + | "references-shared-library" + | "maps-to-sysml" + | "implemented-by" + | "verified-by" + | "validated-by" + | "evidenced-by" + | "tracked-by-issue" + ) { + findings.push(sdoc_finding( + "policy", + "sdoc_relation_type", + &receipt.source_locator, + relation.line_range.start, + )); + } + // StrictDoc native relation syntax carries no owner/revision. The + // bridge reports them from the source node's OWNER and the + // document's published_revision when the document has them; a + // relation without both has no semantic record, and refusing it is + // safer than inventing one from grammar syntax. + if relation.owner.is_none() || relation.revision.is_none() { + findings.push(sdoc_finding( + "policy", + "sdoc_relation_semantic_record", + &receipt.source_locator, + relation.line_range.start, + )); + } + } + if metadata + .get("freshness") + .or_else(|| metadata.get("status")) + .is_some_and(|value| value.eq_ignore_ascii_case("stale")) + { + findings.push(SdocFinding { + kind: "stale", + code: "sdoc_stale".to_owned(), + locators: vec![receipt.source_locator.clone()], + }); + } + let boundary = metadata + .get("public_boundary") + .or_else(|| metadata.get("boundary")); + if !boundary.is_some_and(|value| { + matches!( + value.to_ascii_lowercase().as_str(), + "internal" | "private" | "public" + ) + }) { + findings.push(SdocFinding { + kind: "boundary", + code: "sdoc_boundary".to_owned(), + locators: vec![receipt.source_locator.clone()], + }); + } + } + findings.sort_by(|left, right| { + left.kind + .cmp(right.kind) + .then_with(|| left.code.cmp(&right.code)) + .then_with(|| left.locators.cmp(&right.locators)) + }); + findings +} + +fn sdoc_finding(kind: &'static str, code: &str, locator: &str, line: usize) -> SdocFinding { + SdocFinding { + kind, + code: code.to_owned(), + locators: vec![format!("{locator}:{line}")], + } +} + +fn valid_sdoc_mid(value: &str) -> bool { + (value.len() == 32 && value.bytes().all(|byte| byte.is_ascii_hexdigit())) + || (value.starts_with("MID-") + && value.len() >= 12 + && value[4..] + .bytes() + .all(|byte| byte.is_ascii_uppercase() || byte.is_ascii_digit() || byte == b'-')) +} + +fn normalize_sdoc_receipts(receipts: &mut [SdocReceipt]) { + for receipt in receipts.iter_mut() { + receipt + .nodes + .sort_by(|left, right| left.mid.cmp(&right.mid)); + receipt + .relations + .sort_by(|left, right| left.mid.cmp(&right.mid)); + } + receipts.sort_by(|left, right| left.source_locator.cmp(&right.source_locator)); +} + +fn sdoc_check_json(root: &str, receipts: &[SdocReceipt], findings: &[SdocFinding]) -> String { + format!( + "{{\"root\":\"{}\",\"policy_catalog_sha256\":\"{}\",\"coverage\":{},\"receipts\":[{}],\"findings\":[{}]}}", + json_escape(root), + SDOC_POLICY_CATALOG_SHA256, + sdoc_coverage_json(receipts), + receipts + .iter() + .map(sdoc_receipt_json) + .collect::>() + .join(","), + sdoc_findings_json(findings), + ) +} + +fn sdoc_coverage_json(receipts: &[SdocReceipt]) -> String { + format!( + "{{\"documents\":{},\"nodes\":{},\"relations\":{}}}", + receipts.len(), + receipts + .iter() + .map(|receipt| receipt.nodes.len()) + .sum::(), + receipts + .iter() + .map(|receipt| receipt.relations.len()) + .sum::(), + ) +} + +fn sdoc_metrics_json(receipts: &[SdocReceipt]) -> String { + format!("{{\"coverage\":{}}}", sdoc_coverage_json(receipts)) +} + +fn sdoc_receipt_json(receipt: &SdocReceipt) -> String { + format!( + "{{\"source\":{{\"locator\":\"{}\",\"sha256\":\"{}\"}},\"validation\":\"valid\",\"engine\":{{\"api\":\"{}\",\"version\":\"{}\",\"artifact_sha256\":\"{}\",\"requirements_sha256\":\"{}\"}},\"document\":{},\"nodes\":[{}],\"relations\":[{}]}}", + json_escape(&receipt.source_locator), + json_escape(&receipt.source_sha256), + json_escape(&receipt.engine.api), + json_escape(&receipt.engine.version), + json_escape(&receipt.engine.artifact_sha256), + json_escape(&receipt.engine.requirements_sha256), + sdoc_document_json(receipt), + receipt.nodes.iter().map(sdoc_node_json).collect::>().join(","), + receipt.relations.iter().map(sdoc_relation_json).collect::>().join(","), + ) +} + +fn sdoc_document_json(receipt: &SdocReceipt) -> String { + let document = &receipt.document; + format!( + "{{\"mid\":\"{}\",\"uid\":\"{}\",\"title\":\"{}\",\"metadata\":{},\"line_range\":{{\"start\":{},\"end\":{}}}}}", + json_escape(&document.mid), + json_escape(&document.uid), + json_escape(&document.title), + sdoc_string_map_json(&document.metadata), + document.line_range.start, + document.line_range.end, + ) +} + +fn sdoc_node_json(node: &bran_core::sdoc::SdocNode) -> String { + format!( + "{{\"mid\":\"{}\",\"uid\":\"{}\",\"node_type\":\"{}\",\"fields\":{},\"line_range\":{{\"start\":{},\"end\":{}}}}}", + json_escape(&node.mid), + json_escape(&node.uid), + json_escape(&node.node_type), + sdoc_string_map_json(&node.fields), + node.line_range.start, + node.line_range.end, + ) +} + +fn sdoc_relation_json(relation: &bran_core::sdoc::SdocRelation) -> String { + format!( + "{{\"mid\":\"{}\",\"type\":\"{}\",\"relation_type\":\"{}\",\"source_mid\":\"{}\",\"target_mid\":\"{}\",\"line_range\":{{\"start\":{},\"end\":{}}}}}", + json_escape(&relation.mid), + json_escape(&relation.relation_type), + json_escape(&relation.reference_type), + json_escape(&relation.source_mid), + json_escape(&relation.target_mid), + relation.line_range.start, + relation.line_range.end, + ) +} + +fn sdoc_string_map_json(values: &BTreeMap) -> String { + format!( + "{{{}}}", + values + .iter() + .map(|(key, value)| format!("\"{}\":\"{}\"", json_escape(key), json_escape(value))) + .collect::>() + .join(",") + ) +} + +fn sdoc_findings_json(findings: &[SdocFinding]) -> String { + findings + .iter() + .map(|finding| { + format!( + "{{\"kind\":\"{}\",\"code\":\"{}\",\"locators\":[{}]}}", + finding.kind, + json_escape(&finding.code), + finding + .locators + .iter() + .map(|locator| format!("\"{}\"", json_escape(locator))) + .collect::>() + .join(","), + ) + }) + .collect::>() + .join(",") +} + +fn sdoc_ranked_json(ranked: &bran_core::graph::sdoc::SdocRankedNode) -> String { + let node = &ranked.node; + let fact = |key| { + node.facts() + .values(key) + .and_then(|values| values.first()) + .map(String::as_str) + .unwrap_or("") + }; + format!( + "{{\"mid\":\"{}\",\"uid\":\"{}\",\"title\":\"{}\",\"source_locator\":\"{}\",\"source_sha256\":\"{}\",\"line_locator\":\"{}\",\"exact_mid\":{},\"exact_uid_or_alias\":{},\"content_match\":{}}}", + json_escape(node.id().as_str()), + json_escape(fact("sdoc.uid")), + json_escape(fact("sdoc.title")), + json_escape(fact("sdoc.source_locator")), + json_escape(fact("sdoc.source_sha256")), + json_escape(node.provenance().locator()), + ranked.rank_key.exact_mid, + ranked.rank_key.exact_uid_or_alias, + ranked.rank_key.content_match, + ) +} + struct ScannedQueryRoot { requested: String, snapshot: ScanSnapshot, @@ -6649,15 +7258,19 @@ impl CliResult { #[cfg(test)] mod tests { use super::{ - derive_bundle_from_snapshot, AgentFailure, AgentRuntime, AgentRuntimeAuthority, - AgentRuntimeConfig, AgentSqzAdapter, CliApp, ExitCode, InvocationOutcome, - MemoryResultStore, RuntimePorts, SqzPolicy, TypedExit, MISSING_COMMAND_ERROR, SMOKE_OUTPUT, + derive_bundle_from_snapshot, parse_sdoc_args, run_sdoc, sdoc_document_findings, + AgentFailure, AgentRuntime, AgentRuntimeAuthority, AgentRuntimeConfig, AgentSqzAdapter, + CliApp, CliResult, ExitCode, InvocationOutcome, MemoryResultStore, RuntimePorts, + SdocBridgeConfig, SdocCommand, SqzPolicy, TypedExit, MISSING_COMMAND_ERROR, SMOKE_OUTPUT, UNKNOWN_COMMAND_ERROR, }; use bran_core::bundle::ParseStatus; use bran_core::metadata::MetadataReport; use bran_core::policy::MAX_POLICY_BYTES; use bran_core::scan::{ContentIdentity, ScanEntry, ScanSnapshot}; + use bran_core::sdoc::SdocReceipt; + use std::collections::BTreeMap; + #[cfg(unix)] use std::sync::Arc; struct RequestRecorder { @@ -11003,4 +11616,385 @@ mod tests { let _ = std::fs::remove_dir_all(root); } + + #[cfg(unix)] + struct SdocFixture { + root: std::path::PathBuf, + bridge: String, + } + + /// Policy-clean identities for the CLI bridge fixture. The check path + /// rejects anything that is not a 32-hex MID, so the fixture uses real + /// shapes and each test varies only what it is about. + #[cfg(unix)] + const SDOC_DOC_MID: &str = "a7e9c2d8f41b5a7390ce6d2b8f13a4c6"; + #[cfg(unix)] + const SDOC_REQ_MID: &str = "f9cbb2050ef541ffae88e67dc9eea43e"; + #[cfg(unix)] + const SDOC_UNKNOWN_MID: &str = "1111111111111111111111111111ffff"; + #[cfg(unix)] + const SDOC_CLEAN_METADATA: &str = concat!( + "\"type\":\"architecture-specification\",\"title\":\"CLI fixture\",", + "\"okf_status\":\"active\",\"tags\":\"internal\",\"resource\":\"local\",", + "\"freshness\":\"2026-09-05\",\"public_boundary\":\"internal\",", + "\"grammar_version\":\"1.0.0\",\"published_revision\":\"REV-1\"" + ); + + #[cfg(unix)] + fn sdoc_fixture(prefix: &str, metadata: &str, node_mid: &str, target_mid: &str) -> SdocFixture { + let root = std::env::temp_dir().join(format!( + "bran-cli-sdoc-{prefix}-{}-{}", + std::process::id(), + std::thread::current().name().unwrap_or("main") + )); + let _ = std::fs::remove_dir_all(&root); + std::fs::create_dir_all(root.join("docs")).unwrap(); + let source = "[DOCUMENT]\nTITLE: CLI fixture\n"; + std::fs::write(root.join("docs/spec.sdoc"), source).unwrap(); + let digest = bran_core::agent::result_store::ResultId::sha256(source.as_bytes()) + .value() + .to_owned(); + let required = [ + "MID", + "UID", + "TITLE", + "STATUS", + "SOURCE", + "OWNER", + "STATEMENT", + "RATIONALE", + "ASSUMPTIONS", + "CONSTRAINTS", + "VERIFICATION_METHOD", + "VERIFICATION_LEVEL", + "VERIFICATION_ENVIRONMENT", + "SUCCESS_CRITERIA", + "VALIDATION_METHOD", + "VERIFICATION_CASE", + "EXPECTED_RESULT", + "ACTUAL_RESULT", + "ANOMALY", + "CORRECTIVE_ACTION", + "WAIVER", + "CLOSURE", + ]; + let fields = required + .iter() + .map(|field| match *field { + "MID" => format!("\"MID\":\"{node_mid}\""), + "UID" => "\"UID\":\"REQ-CLI\"".to_owned(), + "TITLE" => "\"TITLE\":\"Configure SDoc query\"".to_owned(), + "STATUS" => "\"STATUS\":\"Published\"".to_owned(), + "STATEMENT" => { + "\"STATEMENT\":\"CLI query must preserve exact source evidence.\"".to_owned() + } + other => format!("\"{other}\":\"recorded\""), + }) + .collect::>() + .join(","); + let envelope = format!( + concat!( + "{{\"protocol\":\"alphazede.strictdoc.bridge\",\"schema_version\":\"2\",\"mode\":\"sdoc\",\"status\":\"ok\",", + "\"validation\":{{\"status\":\"valid\"}},\"engine\":{{\"api\":\"strictdoc.api\",\"version\":\"0.29.0\",", + "\"artifact_sha256\":\"fae511b228952ee5e1ff765650ac2701526ce39e32a6686f53ef384621486a90\",", + "\"requirements_sha256\":\"77b879886d9856ca748e181b592e78efa377d432953ec52d6e61803cf10ef9c8\"}},", + "\"source\":{{\"locator\":\"docs/spec.sdoc\",\"sha256\":\"{digest}\"}},", + "\"document\":{{\"mid\":\"{doc_mid}\",\"uid\":\"DOC-CLI\",\"title\":\"CLI fixture\",\"metadata\":{{{metadata}}},\"line_range\":{{\"start\":1,\"end\":2}}}},", + "\"nodes\":[{{\"mid\":\"{node_mid}\",\"uid\":\"REQ-CLI\",\"node_type\":\"REQUIREMENT\",\"fields\":{{{fields}}},\"line_range\":{{\"start\":4,\"end\":8}}}}],", + "\"relations\":[{{\"mid\":\"0a46bb7e28b7e206f84fee642f7b398e\",\"type\":\"derives-from\",\"relation_type\":\"Verification\",", + "\"owner\":\"CLI fixture\",\"revision\":\"REV-1\",", + "\"source_mid\":\"{doc_mid}\",\"target_mid\":\"{target_mid}\",\"line_range\":{{\"start\":9,\"end\":9}}}}]}}" + ), + digest = digest, + doc_mid = SDOC_DOC_MID, + metadata = metadata, + node_mid = node_mid, + target_mid = target_mid, + fields = fields, + ); + // Written as a `/bin/sh` argument, never as the executed program: an + // executable a sibling test thread's fork still holds open makes `exec` + // fail with ETXTBSY, which surfaced here as a flaky + // `sdoc_bridge_transport`. + let bridge = root.join("bridge.sh"); + std::fs::write( + &bridge, + format!("#!/bin/sh\nprintf '%s\\n' '{}'\n", envelope), + ) + .unwrap(); + SdocFixture { + root, + bridge: bridge.to_string_lossy().into_owned(), + } + } + + #[cfg(unix)] + fn sdoc_args(fixture: &SdocFixture, subcommand: &str, request: Option<&str>) -> Vec { + let mut args = vec![ + "sdoc".to_owned(), + subcommand.to_owned(), + fixture.root.to_string_lossy().into_owned(), + ]; + if let Some(request) = request { + args.push(request.to_owned()); + } + args + } + + /// Runs the internal SDoc path against the fixture bridge. `CliApp::run` + /// stays pinned to the packaged installation, so these behaviour tests + /// inject the fixture here instead of depending on production pins. + #[cfg(unix)] + fn sdoc_run(fixture: &SdocFixture, subcommand: &str, request: Option<&str>) -> CliResult { + let command = match subcommand { + "check" => SdocCommand::Check, + _ => SdocCommand::Query, + }; + let values = sdoc_args(fixture, subcommand, request)[2..].to_vec(); + let args = parse_sdoc_args(command, values).unwrap(); + let bridge = SdocBridgeConfig::new( + "/bin/sh", + &fixture.bridge, + fixture.root.join("strictdoc.whl"), + ) + .unwrap(); + run_sdoc(&args, bridge) + } + + #[test] + #[cfg(unix)] + fn sdoc_check_and_query_preserve_receipts_and_keep_miss_successful() { + let fixture = sdoc_fixture( + "check-query", + SDOC_CLEAN_METADATA, + SDOC_REQ_MID, + SDOC_REQ_MID, + ); + let check = sdoc_run(&fixture, "check", None); + assert_eq!(check.exit_code, ExitCode::SUCCESS, "{}", check.output); + assert!( + check.output.contains("\"status\":\"ok\""), + "{}", + check.output + ); + // The receipt is preserved verbatim, not re-derived from the source. + assert!( + check.output.contains("\"locator\":\"docs/spec.sdoc\""), + "{}", + check.output + ); + assert!( + check.output.contains("\"uid\":\"REQ-CLI\""), + "{}", + check.output + ); + assert!(check.output.contains("\"findings\":[]"), "{}", check.output); + + let exact = sdoc_run(&fixture, "query", Some("REQ-CLI")); + assert_eq!(exact.exit_code, ExitCode::SUCCESS, "{}", exact.output); + assert!( + exact.output.contains("\"evidence_state\":\"hit\""), + "{}", + exact.output + ); + + // A miss is a successful answer, not an error. + let miss = sdoc_run(&fixture, "query", Some("REQ-NOT-PRESENT-ANYWHERE")); + assert_eq!(miss.exit_code, ExitCode::SUCCESS, "{}", miss.output); + assert!( + miss.output.contains("\"evidence_state\":\"miss\""), + "{}", + miss.output + ); + assert!(miss.output.contains("\"results\":[]"), "{}", miss.output); + let _ = std::fs::remove_dir_all(fixture.root); + } + + #[test] + #[cfg(unix)] + fn sdoc_check_reports_stale_boundary_and_unresolved_findings() { + let fixture = sdoc_fixture( + "findings", + concat!( + "\"type\":\"architecture-specification\",\"title\":\"CLI fixture\",", + "\"okf_status\":\"deprecated\",\"tags\":\"internal\",\"resource\":\"local\",", + "\"freshness\":\"stale\",\"public_boundary\":\"unknown\",", + "\"grammar_version\":\"1.0.0\",\"published_revision\":\"REV-1\"" + ), + SDOC_REQ_MID, + SDOC_UNKNOWN_MID, + ); + let result = sdoc_run(&fixture, "check", None); + assert_eq!( + result.exit_code, + TypedExit::Validation.code(), + "{}", + result.output + ); + assert!(result.output.contains("sdoc_stale"), "{}", result.output); + assert!(result.output.contains("sdoc_boundary"), "{}", result.output); + assert!( + result.output.contains("sdoc_unresolved_relation"), + "{}", + result.output + ); + let _ = std::fs::remove_dir_all(fixture.root); + } + + #[test] + #[cfg(unix)] + fn sdoc_check_reports_duplicate_mid_and_rejects_relative_inputs() { + // The requirement reuses the document's MID, so identity is ambiguous. + let fixture = sdoc_fixture("duplicate", SDOC_CLEAN_METADATA, SDOC_DOC_MID, SDOC_DOC_MID); + let duplicate = sdoc_run(&fixture, "check", None); + assert_eq!( + duplicate.exit_code, + TypedExit::Validation.code(), + "{}", + duplicate.output + ); + assert!( + duplicate.output.contains("sdoc_duplicate_mid"), + "{}", + duplicate.output + ); + + let relative = CliApp::run(vec![ + "sdoc", + "check", + fixture.root.to_str().unwrap(), + "--program", + "sh", + ]); + assert_eq!(relative.exit_code, TypedExit::Usage.code()); + assert!(relative.output.contains("unexpected_argument")); + let _ = std::fs::remove_dir_all(fixture.root); + } + + #[test] + #[cfg(unix)] + fn sdoc_malformed_bridge_is_an_operation_error_not_an_empty_success() { + let fixture = sdoc_fixture("malformed", SDOC_CLEAN_METADATA, SDOC_REQ_MID, SDOC_REQ_MID); + std::fs::write(&fixture.bridge, "#!/bin/sh\nprintf '%s\\n' not-json\n").unwrap(); + let result = sdoc_run(&fixture, "check", None); + assert_eq!(result.exit_code, TypedExit::Operation.code()); + assert!( + result.output.contains("\"status\":\"error\""), + "{}", + result.output + ); + assert!( + result.output.contains("sdoc_malformed_json"), + "{}", + result.output + ); + assert!(!result.output.contains("\"coverage\":{\"documents\":0")); + let _ = std::fs::remove_dir_all(fixture.root); + } + + /// The shipped CLI resolves only the packaged installation, so without + /// production pins every `sdoc` invocation fails closed. + #[test] + #[cfg(unix)] + fn sdoc_cli_without_pins_fails_closed_as_runtime_unavailable() { + let fixture = sdoc_fixture("unpinned", SDOC_CLEAN_METADATA, SDOC_REQ_MID, SDOC_REQ_MID); + let result = CliApp::run(sdoc_args(&fixture, "check", None)); + assert_eq!( + result.exit_code, + TypedExit::Operation.code(), + "{}", + result.output + ); + assert!( + result.output.contains("sdoc_runtime_unavailable") + || result.output.contains("sdoc_runtime_mismatch"), + "{}", + result.output + ); + let _ = std::fs::remove_dir_all(fixture.root); + } + + #[test] + fn sdoc_policy_requires_full_core_without_parsing_source_text() { + let metadata = BTreeMap::from([ + ("type".to_owned(), "architecture-specification".to_owned()), + ("title".to_owned(), "Spec".to_owned()), + ("okf_status".to_owned(), "active".to_owned()), + ("tags".to_owned(), "internal".to_owned()), + ("resource".to_owned(), "local".to_owned()), + ("freshness".to_owned(), "current".to_owned()), + ("public_boundary".to_owned(), "internal".to_owned()), + ("grammar_version".to_owned(), "0.29".to_owned()), + ("published_revision".to_owned(), "draft".to_owned()), + ]); + let fields = [ + "MID", + "UID", + "TITLE", + "STATUS", + "SOURCE", + "OWNER", + "STATEMENT", + "RATIONALE", + "ASSUMPTIONS", + "CONSTRAINTS", + "VERIFICATION_METHOD", + "VERIFICATION_LEVEL", + "VERIFICATION_ENVIRONMENT", + "SUCCESS_CRITERIA", + "VALIDATION_METHOD", + "VERIFICATION_CASE", + "EXPECTED_RESULT", + "ACTUAL_RESULT", + "ANOMALY", + "CORRECTIVE_ACTION", + "WAIVER", + "CLOSURE", + ] + .into_iter() + .map(|field| { + ( + field.to_owned(), + if field == "STATUS" { "Draft" } else { "x" }.to_owned(), + ) + }) + .collect(); + let receipt = SdocReceipt { + source_locator: "docs/spec.sdoc".to_owned(), + source_sha256: "0".repeat(64), + validation: bran_core::sdoc::SdocValidation::Valid, + engine: bran_core::sdoc::SdocEngine { + api: "strictdoc.api".to_owned(), + version: "0.29.0".to_owned(), + artifact_sha256: "0".repeat(64), + requirements_sha256: "0".repeat(64), + }, + document: bran_core::sdoc::SdocDocument { + mid: "MID-DOC-0001".to_owned(), + uid: "DOC-1".to_owned(), + title: "Spec".to_owned(), + metadata, + line_range: bran_core::sdoc::SdocLineRange { start: 1, end: 2 }, + }, + nodes: vec![bran_core::sdoc::SdocNode { + mid: "MID-REQ-0001".to_owned(), + uid: "REQ-1".to_owned(), + node_type: "REQUIREMENT".to_owned(), + fields, + line_range: bran_core::sdoc::SdocLineRange { start: 3, end: 4 }, + }], + relations: vec![], + }; + assert!(sdoc_document_findings(std::slice::from_ref(&receipt)).is_empty()); + let mut invalid = receipt; + invalid.document.mid = "bad".to_owned(); + invalid.document.metadata.remove("title"); + let findings = sdoc_document_findings(&[invalid]); + assert!(findings + .iter() + .any(|finding| finding.code == "sdoc_invalid_mid")); + assert!(findings + .iter() + .any(|finding| finding.code == "sdoc_metadata_required")); + } } diff --git a/crates/bran-core/Cargo.toml b/crates/bran-core/Cargo.toml index f6431dd..e5fa7e9 100644 --- a/crates/bran-core/Cargo.toml +++ b/crates/bran-core/Cargo.toml @@ -7,6 +7,15 @@ license = "MIT OR Apache-2.0" [lib] path = "src/lib.rs" +[features] +# Exposes `SdocBridgeConfig::new`, the unpinned test-fixture constructor, to +# dependants' test builds only. `bran-cli` enables it through a dev-dependency, +# so no shipped binary can construct a bridge that skips the pinned identity. +test-fixtures = [] + +[dependencies] +serde_json = "=1.0.151" + [[bench]] name = "repository_scan" path = "../../benches/repository_scan.rs" diff --git a/crates/bran-core/src/graph/mod.rs b/crates/bran-core/src/graph/mod.rs index b17a4e8..a91dcff 100644 --- a/crates/bran-core/src/graph/mod.rs +++ b/crates/bran-core/src/graph/mod.rs @@ -2,6 +2,7 @@ pub mod model; pub mod query; +pub mod sdoc; pub use model::{ Confidence, EdgeCertainty, EdgeId, EdgeInput, EdgeRelationship, GraphError, GraphInput, diff --git a/crates/bran-core/src/graph/model.rs b/crates/bran-core/src/graph/model.rs index 787842f..e32a4aa 100644 --- a/crates/bran-core/src/graph/model.rs +++ b/crates/bran-core/src/graph/model.rs @@ -63,8 +63,10 @@ pub struct NodeFacts { } impl NodeFacts { - /// Maximum number of distinct semantic keys carried by one node. - pub const MAX_FIELDS: usize = 32; + /// Maximum number of distinct semantic keys carried by one node. This + /// admits the 32-key SDoc core projection plus up to 32 project-extension + /// keys while retaining a finite graph-input bound. + pub const MAX_FIELDS: usize = 64; /// Maximum UTF-8 byte length of one semantic key. pub const MAX_FIELD_KEY_BYTES: usize = 64; /// Maximum Unicode scalar count of one semantic key. @@ -207,6 +209,26 @@ impl NodeFacts { } } +#[cfg(test)] +mod node_facts_tests { + use super::*; + + #[test] + fn field_limit_is_finite_and_overflow_is_typed() { + let facts = (0..NodeFacts::MAX_FIELDS) + .try_fold(NodeFacts::default(), |facts, index| { + facts.with_field_value(format!("field-{index}"), "value") + }) + .unwrap(); + assert!(matches!( + facts.with_field_value("one-too-many", "value"), + Err(GraphError::FactFieldLimitExceeded { + limit: NodeFacts::MAX_FIELDS + }) + )); + } +} + /// Scanner evidence carried through graph construction without interpretation. #[derive(Clone, Debug, Eq, PartialEq)] pub struct Provenance { diff --git a/crates/bran-core/src/graph/sdoc.rs b/crates/bran-core/src/graph/sdoc.rs new file mode 100644 index 0000000..dbb14cd --- /dev/null +++ b/crates/bran-core/src/graph/sdoc.rs @@ -0,0 +1,699 @@ +//! Validated SDoc receipt projection and SDoc-specific ranking. +//! +//! This adapter deliberately uses MID, rather than a path, for graph identity. +//! It accepts only bridge-validated receipts and never parses or rewrites SDoc. + +use super::{ + Confidence, EdgeCertainty, EdgeId, EdgeInput, EdgeRelationship, GraphError, GraphInput, + KnowledgeGraph, NodeFacts, NodeId, NodeInput, NodeRole, Provenance, +}; +use crate::sdoc::{SdocDocument, SdocLineRange, SdocNode, SdocReceipt}; +use std::collections::{BTreeMap, BTreeSet}; +use std::fmt; + +/// Failure while projecting already-validated StrictDoc data into graph facts. +#[derive(Clone, Debug, Eq, PartialEq)] +pub enum SdocGraphError { + Graph(GraphError), + DuplicateMid { + mid: String, + first_locator: String, + second_locator: String, + }, + DuplicateUid { + uid: String, + first_mid: String, + second_mid: String, + }, + DuplicateRelationMid(String), + UnresolvedRelation { + relation_mid: String, + target_mid: String, + }, +} + +impl From for SdocGraphError { + fn from(value: GraphError) -> Self { + Self::Graph(value) + } +} + +impl fmt::Display for SdocGraphError { + fn fmt(&self, formatter: &mut fmt::Formatter<'_>) -> fmt::Result { + match self { + Self::Graph(error) => error.fmt(formatter), + Self::DuplicateMid { mid, .. } => write!(formatter, "duplicate SDoc MID: {mid}"), + Self::DuplicateUid { uid, .. } => write!(formatter, "duplicate SDoc UID: {uid}"), + Self::DuplicateRelationMid(mid) => { + write!(formatter, "duplicate SDoc relation MID: {mid}") + } + Self::UnresolvedRelation { + relation_mid, + target_mid, + } => write!( + formatter, + "SDoc relation {relation_mid} has unresolved target MID: {target_mid}" + ), + } + } +} + +impl std::error::Error for SdocGraphError {} + +/// Projects validated receipts to the scanner-neutral graph input contract. +/// +/// Node identity is the native MID. Source paths are retained only as facts and +/// provenance, so a relocation does not create a new graph node. +pub fn graph_input(receipts: &[SdocReceipt]) -> Result { + let mut mids = BTreeMap::new(); + let mut uids = BTreeMap::new(); + let mut relation_mids = BTreeSet::new(); + let mut nodes = Vec::new(); + let mut edges = Vec::new(); + let mut relations = BTreeMap::new(); + let mut relation_facts = BTreeMap::>::new(); + + for receipt in receipts { + for relation in &receipt.relations { + if !relation_mids.insert(relation.mid.clone()) { + return Err(SdocGraphError::DuplicateRelationMid(relation.mid.clone())); + } + relation_facts + .entry(relation.source_mid.clone()) + .or_default() + .push(format!( + "{}:{}:{}", + relation.mid, relation.relation_type, relation.target_mid + )); + relations.insert(relation.mid.clone(), (receipt, relation)); + } + } + for receipt in receipts { + let inherited = inherited_facts(&receipt.document); + insert_node( + &mut nodes, + &mut mids, + &mut uids, + &receipt.source_locator, + &receipt.source_sha256, + &receipt.document.mid, + &receipt.document.uid, + NodeRole::Document, + "DOCUMENT", + &receipt.document.title, + &receipt.document.metadata, + &receipt.document.line_range, + &inherited, + relation_facts + .get(&receipt.document.mid) + .map(Vec::as_slice) + .unwrap_or(&[]), + )?; + for node in &receipt.nodes { + insert_sdoc_node( + &mut nodes, + &mut mids, + &mut uids, + receipt, + node, + &inherited, + relation_facts + .get(&node.mid) + .map(Vec::as_slice) + .unwrap_or(&[]), + )?; + } + } + + let known: BTreeSet<_> = mids.keys().cloned().collect(); + for (mid, (receipt, relation)) in relations { + if !known.contains(&relation.source_mid) { + return Err(SdocGraphError::UnresolvedRelation { + relation_mid: mid, + target_mid: relation.source_mid.clone(), + }); + } + if !known.contains(&relation.target_mid) { + return Err(SdocGraphError::UnresolvedRelation { + relation_mid: mid, + target_mid: relation.target_mid.clone(), + }); + } + edges.push( + EdgeInput::new( + EdgeId::parse(mid.clone())?, + NodeId::parse(relation.source_mid.clone())?, + NodeId::parse(relation.target_mid.clone())?, + Provenance::new( + "strictdoc-bridge", + line_locator(&receipt.source_locator, &relation.line_range, &mid), + )?, + Confidence::new(100)?, + EdgeCertainty::Known, + ) + .with_relationship(relationship(&relation.relation_type)), + ); + } + Ok(GraphInput::new(nodes, edges)) +} + +fn insert_sdoc_node( + nodes: &mut Vec, + mids: &mut BTreeMap, + uids: &mut BTreeMap, + receipt: &SdocReceipt, + node: &SdocNode, + inherited: &BTreeMap, + relation_facts: &[String], +) -> Result<(), SdocGraphError> { + // A [TEXT] node has no TITLE field; its heading is the first statement + // line (the architecture-specification floor encoding), so that is its + // title before the UID is. + let heading = field_value(&node.fields, "statement") + .and_then(|statement| statement.lines().next()) + .filter(|line| !line.trim().is_empty()); + let title = field_value(&node.fields, "title") + .or(heading) + .unwrap_or(&node.uid); + insert_node( + nodes, + mids, + uids, + &receipt.source_locator, + &receipt.source_sha256, + &node.mid, + &node.uid, + NodeRole::Section, + &node.node_type, + title, + &node.fields, + &node.line_range, + inherited, + relation_facts, + ) +} + +#[allow(clippy::too_many_arguments)] +fn insert_node( + nodes: &mut Vec, + mids: &mut BTreeMap, + uids: &mut BTreeMap, + source_locator: &str, + source_sha256: &str, + mid: &str, + uid: &str, + role: NodeRole, + node_type: &str, + title: &str, + fields: &BTreeMap, + line_range: &SdocLineRange, + inherited: &BTreeMap, + relation_facts: &[String], +) -> Result<(), SdocGraphError> { + if let Some(first_locator) = mids.insert(mid.to_owned(), source_locator.to_owned()) { + return Err(SdocGraphError::DuplicateMid { + mid: mid.to_owned(), + first_locator, + second_locator: source_locator.to_owned(), + }); + } + if let Some(first_mid) = uids.insert(uid.to_owned(), mid.to_owned()) { + return Err(SdocGraphError::DuplicateUid { + uid: uid.to_owned(), + first_mid, + second_mid: mid.to_owned(), + }); + } + let mut facts = NodeFacts::default() + .with_field_value("sdoc.mid", mid)? + .with_field_value("sdoc.uid", uid)? + .with_field_value("sdoc.alias", uid)? + .with_field_value("sdoc.node_type", node_type)? + .with_field_value("title", title)? + .with_field_value("sdoc.title", title)? + .with_field_value("sdoc.source_locator", source_locator)? + .with_field_value("sdoc.source_sha256", source_sha256)? + .with_field_value( + "sdoc.line_range", + format!("{}-{}", line_range.start, line_range.end), + )? + .with_field_value("sdoc.authority", "canonical")? + .with_field_value("canonical", "true")?; + for (key, value) in inherited + .iter() + .filter(|(key, _)| !fields.keys().any(|field| field.eq_ignore_ascii_case(key))) + .chain(fields) + { + let value = fact_excerpt(value); + facts = facts.with_field_value(format!("sdoc.{}", key.to_ascii_lowercase()), value)?; + if key.eq_ignore_ascii_case("tag") || key.eq_ignore_ascii_case("tags") { + facts = facts.with_tag(value)?; + } + if key.eq_ignore_ascii_case("statement") { + facts = facts.with_field_value("sdoc.statement", value)?; + } + if key.eq_ignore_ascii_case("alias") || key.eq_ignore_ascii_case("aliases") { + facts = facts.with_field_value("sdoc.alias", value)?; + } + } + for relation in relation_facts { + facts = facts.with_field_value("sdoc.relation", relation)?; + } + nodes.push( + NodeInput::new( + NodeId::parse(mid)?, + role, + Provenance::new( + "strictdoc-bridge", + line_locator(source_locator, line_range, mid), + )?, + Confidence::new(100)?, + ) + .with_facts(facts), + ); + Ok(()) +} + +fn inherited_facts(document: &SdocDocument) -> BTreeMap { + document + .metadata + .iter() + .filter(|(key, _)| { + key.eq_ignore_ascii_case("status") + || key.eq_ignore_ascii_case("freshness") + || key.eq_ignore_ascii_case("public_boundary") + || key.eq_ignore_ascii_case("boundary") + }) + .map(|(key, value)| (key.clone(), value.clone())) + .collect() +} + +/// Facts are search evidence, never canonical content. A field longer than +/// the per-value fact limit (a prose section carried as a [TEXT] statement) +/// is carried as its leading bytes, cut at a character boundary, rather than +/// refusing the whole document. The canonical text stays in the SDoc. +fn fact_excerpt(value: &str) -> &str { + if value.len() <= NodeFacts::MAX_VALUE_BYTES { + return value; + } + let mut end = NodeFacts::MAX_VALUE_BYTES; + while !value.is_char_boundary(end) { + end -= 1; + } + &value[..end] +} + +fn field_value<'a>(fields: &'a BTreeMap, name: &str) -> Option<&'a str> { + fields + .iter() + .find_map(|(key, value)| key.eq_ignore_ascii_case(name).then_some(value.as_str())) +} + +fn line_locator(source: &str, range: &SdocLineRange, identity: &str) -> String { + format!("{source}:{}-{}:{identity}", range.start, range.end) +} + +fn relationship(value: &str) -> EdgeRelationship { + let value = value.to_ascii_lowercase(); + if value.contains("verif") || value.contains("valid") || value.contains("test") { + EdgeRelationship::Validation + } else if value.contains("implement") || value.contains("satisf") || value.contains("alloc") { + EdgeRelationship::Implementation + } else { + EdgeRelationship::Dependency + } +} + +/// SDoc query ranking inputs, in the approved order after identity and content. +#[derive(Clone, Debug, Eq, PartialEq)] +pub struct SdocRankKey { + pub exact_mid: bool, + pub exact_uid_or_alias: bool, + pub content_match: bool, + pub active_or_published: bool, + pub canonical: bool, + pub boundary: SdocBoundaryKey, + pub confidence: u8, + pub freshness: String, + pub mid: String, +} + +#[derive(Clone, Copy, Debug, Eq, Ord, PartialEq, PartialOrd)] +pub enum SdocBoundaryKey { + Unknown, + Public, + Internal, +} + +/// One deterministically ordered SDoc graph result. +#[derive(Clone, Debug, Eq, PartialEq)] +pub struct SdocRankedNode { + pub node: NodeInput, + pub rank_key: SdocRankKey, +} + +/// Ranks only nodes projected by [`graph_input`]. Exact MID and UID/alias win +/// before content. Locator text is intentionally not a query input or tie-breaker. +pub fn rank(graph: &KnowledgeGraph, needle: &str, max_results: usize) -> Vec { + let mut ranked: Vec<_> = graph + .node_ids() + .into_iter() + .filter_map(|id| graph.node(&id)) + .filter(|node| node.facts().contains_value("sdoc.mid", node.id().as_str())) + .filter_map(|node| rank_node(node, needle)) + .collect(); + ranked.sort_by(|left, right| compare_rank(&left.rank_key, &right.rank_key)); + ranked.truncate(max_results); + ranked +} + +fn rank_node(node: &NodeInput, needle: &str) -> Option { + let exact_mid = node.id().as_str() == needle; + let exact_uid_or_alias = values(node, &["sdoc.uid", "sdoc.alias"]) + .into_iter() + .any(|value| value == needle); + let content_match = values(node, &["title", "sdoc.title", "sdoc.statement", "tags"]) + .into_iter() + .any(|value| contains_case_insensitive(value, needle)); + (exact_mid || exact_uid_or_alias || content_match).then(|| SdocRankedNode { + node: node.clone(), + rank_key: SdocRankKey { + exact_mid, + exact_uid_or_alias, + content_match, + active_or_published: values(node, &["sdoc.status"]) + .into_iter() + .any(|value| matches!(value.to_ascii_lowercase().as_str(), "active" | "published")), + canonical: node.facts().contains_value("canonical", "true"), + boundary: boundary_key( + values(node, &["sdoc.public_boundary", "sdoc.boundary"]).into_iter(), + ), + confidence: node.confidence().value(), + freshness: values(node, &["sdoc.freshness"]) + .into_iter() + .max() + .unwrap_or_default() + .to_owned(), + mid: node.id().as_str().to_owned(), + }, + }) +} + +fn values<'a>(node: &'a NodeInput, keys: &[&str]) -> Vec<&'a str> { + keys.iter() + .filter_map(|key| node.facts().values(key)) + .flatten() + .map(String::as_str) + .collect() +} + +fn boundary_key(values: impl Iterator>) -> SdocBoundaryKey { + values.fold(SdocBoundaryKey::Unknown, |best, value| { + let candidate = match value.as_ref().to_ascii_lowercase().as_str() { + "internal" | "private" => SdocBoundaryKey::Internal, + "public" => SdocBoundaryKey::Public, + _ => SdocBoundaryKey::Unknown, + }; + best.max(candidate) + }) +} + +fn contains_case_insensitive(haystack: &str, needle: &str) -> bool { + !needle.is_empty() + && haystack + .to_ascii_lowercase() + .contains(&needle.to_ascii_lowercase()) +} + +fn compare_rank(left: &SdocRankKey, right: &SdocRankKey) -> std::cmp::Ordering { + right + .exact_mid + .cmp(&left.exact_mid) + .then_with(|| right.exact_uid_or_alias.cmp(&left.exact_uid_or_alias)) + .then_with(|| right.content_match.cmp(&left.content_match)) + .then_with(|| right.active_or_published.cmp(&left.active_or_published)) + .then_with(|| right.canonical.cmp(&left.canonical)) + .then_with(|| right.boundary.cmp(&left.boundary)) + .then_with(|| right.confidence.cmp(&left.confidence)) + .then_with(|| right.freshness.cmp(&left.freshness)) + .then_with(|| left.mid.cmp(&right.mid)) +} + +#[cfg(test)] +mod tests { + use super::*; + use crate::graph::GraphLimits; + use crate::sdoc::{SdocEngine, SdocRelation, SdocValidation}; + + fn receipt(locator: &str, document_mid: &str, requirement_mid: &str, uid: &str) -> SdocReceipt { + SdocReceipt { + source_locator: locator.to_owned(), + source_sha256: "a".repeat(64), + validation: SdocValidation::Valid, + engine: SdocEngine { + api: "strictdoc.api".to_owned(), + version: "0.29.0".to_owned(), + artifact_sha256: "b".repeat(64), + requirements_sha256: "c".repeat(64), + }, + document: SdocDocument { + mid: document_mid.to_owned(), + uid: format!("UID-{document_mid}"), + title: "Architecture".to_owned(), + metadata: BTreeMap::from([ + ("STATUS".to_owned(), "Published".to_owned()), + ("PUBLIC_BOUNDARY".to_owned(), "internal".to_owned()), + ("FRESHNESS".to_owned(), "2026-09-02".to_owned()), + ]), + line_range: range(1), + }, + nodes: vec![SdocNode { + mid: requirement_mid.to_owned(), + uid: uid.to_owned(), + node_type: "Requirement".to_owned(), + fields: BTreeMap::from([ + ( + "STATEMENT".to_owned(), + "The system shall retain traceability.".to_owned(), + ), + ("TAGS".to_owned(), "traceability".to_owned()), + ]), + line_range: range(2), + }], + relations: vec![SdocRelation { + mid: format!("REL-{requirement_mid}"), + relation_type: "VERIFIES".to_owned(), + reference_type: "Reference".to_owned(), + source_mid: requirement_mid.to_owned(), + target_mid: document_mid.to_owned(), + line_range: range(3), + owner: None, + revision: None, + }], + } + } + + fn range(line: usize) -> SdocLineRange { + SdocLineRange { + start: line, + end: line, + } + } + + fn graph(receipts: &[SdocReceipt]) -> KnowledgeGraph { + KnowledgeGraph::build( + graph_input(receipts).unwrap(), + GraphLimits::new(64, 64).unwrap(), + ) + .unwrap() + } + + fn full_core_requirement_fields() -> BTreeMap { + BTreeMap::from([ + ( + "STATEMENT".to_owned(), + "The system shall retain traceability.".to_owned(), + ), + ("TAGS".to_owned(), "traceability".to_owned()), + ("ALIASES".to_owned(), "REQ-1-LEGACY".to_owned()), + ("RATIONALE".to_owned(), "Required for review.".to_owned()), + ( + "VERIFICATION_CRITERIA".to_owned(), + "Trace exists.".to_owned(), + ), + ("VERIFICATION_METHOD".to_owned(), "Inspection".to_owned()), + ("SOURCE".to_owned(), "AlphaZede".to_owned()), + ("OWNER".to_owned(), "systems".to_owned()), + ("PRIORITY".to_owned(), "high".to_owned()), + ("RISK".to_owned(), "medium".to_owned()), + ("ASSUMPTION".to_owned(), "baseline".to_owned()), + ("CONSTRAINT".to_owned(), "stable-identity".to_owned()), + ("DERIVATION".to_owned(), "portfolio".to_owned()), + ("SATISFACTION".to_owned(), "model".to_owned()), + ("ALLOCATION".to_owned(), "system".to_owned()), + ("VALIDATION".to_owned(), "planned".to_owned()), + ("TEST_EVIDENCE".to_owned(), "pending".to_owned()), + ]) + } + + #[test] + fn relocation_keeps_mid_identity_and_locator_is_only_a_fact() { + let old = graph(&[receipt("docs/old.sdoc", "MID-DOC", "MID-REQ", "REQ-1")]); + let new = graph(&[receipt( + "architecture/new.sdoc", + "MID-DOC", + "MID-REQ", + "REQ-1", + )]); + let old_node = old.node(&NodeId::parse("MID-REQ").unwrap()).unwrap(); + let new_node = new.node(&NodeId::parse("MID-REQ").unwrap()).unwrap(); + assert_eq!(old_node.id(), new_node.id()); + assert_ne!( + old_node.provenance().locator(), + new_node.provenance().locator() + ); + assert!(old_node + .facts() + .contains_value("sdoc.relation", "REL-MID-REQ:VERIFIES:MID-DOC")); + } + + /// A prose section carried as a [TEXT] statement (azedge#74) is longer + /// than one fact value may be. The graph carries an excerpt as evidence + /// and titles the node by its heading; it never refuses the document. + #[test] + fn long_text_statement_projects_as_an_excerpt_titled_by_its_heading() { + let mut receipt = receipt("architecture.sdoc", "MID-DOC", "MID-SEC", "SEC-1"); + let body = "Baselines\n\n".to_owned() + &"| Boundary | Current | Target |\n".repeat(80); + assert!(body.len() > NodeFacts::MAX_VALUE_BYTES); + receipt.nodes[0].node_type = "TEXT".to_owned(); + receipt.nodes[0].fields = BTreeMap::from([("STATEMENT".to_owned(), body.clone())]); + receipt.relations.clear(); + let input = graph_input(&[receipt]).unwrap(); + let section = input + .nodes() + .iter() + .find(|node| node.id().as_str() == "MID-SEC") + .unwrap(); + assert!(section.facts().contains_value("title", "Baselines")); + let excerpt = §ion.facts().values("sdoc.statement").unwrap()[0]; + assert_eq!(excerpt.len(), NodeFacts::MAX_VALUE_BYTES); + assert!(body.starts_with(excerpt.as_str())); + } + + #[test] + fn full_core_requirement_plus_project_extension_projects_without_truncation() { + let mut receipt = receipt("architecture.sdoc", "MID-DOC", "MID-REQ", "REQ-1"); + receipt.nodes[0].fields = full_core_requirement_fields(); + receipt.nodes[0] + .fields + .insert("PROJECT_EXTENSION".to_owned(), "portfolio-a".to_owned()); + let input = graph_input(&[receipt]).unwrap(); + let requirement = input + .nodes() + .iter() + .find(|node| node.id().as_str() == "MID-REQ") + .unwrap(); + assert!(requirement + .facts() + .contains_value("sdoc.project_extension", "portfolio-a")); + assert!(requirement + .facts() + .contains_value("sdoc.relation", "REL-MID-REQ:VERIFIES:MID-DOC")); + } + + #[test] + fn exact_identity_beats_content_and_path_noise_with_stable_ties() { + let exact = receipt("noise/path.sdoc", "MID-DOC", "MID-REQ", "REQ-1"); + let mut content = receipt( + "MID-REQ/looks-like-a-path.sdoc", + "MID-DOC-2", + "MID-REQ-2", + "REQ-2", + ); + content.nodes[0] + .fields + .insert("STATEMENT".to_owned(), "MID-REQ".to_owned()); + let forward = graph(&[content.clone(), exact.clone()]); + let reverse = graph(&[exact, content]); + let forward_ids: Vec<_> = rank(&forward, "MID-REQ", 8) + .into_iter() + .map(|item| item.rank_key.mid) + .collect(); + let reverse_ids: Vec<_> = rank(&reverse, "MID-REQ", 8) + .into_iter() + .map(|item| item.rank_key.mid) + .collect(); + assert_eq!(forward_ids, vec!["MID-REQ", "MID-REQ-2"]); + assert_eq!(forward_ids, reverse_ids); + + let mut uid_content = receipt("another/path.sdoc", "MID-DOC-3", "MID-REQ-3", "REQ-3"); + uid_content.nodes[0] + .fields + .insert("STATEMENT".to_owned(), "REQ-1".to_owned()); + let uid_graph = graph(&[ + receipt("noise/path.sdoc", "MID-DOC", "MID-REQ", "REQ-1"), + uid_content, + ]); + let uid_ids: Vec<_> = rank(&uid_graph, "REQ-1", 8) + .into_iter() + .map(|item| item.rank_key.mid) + .collect(); + assert_eq!(uid_ids, vec!["MID-REQ", "MID-REQ-3"]); + } + + #[test] + fn state_then_authority_boundary_confidence_and_freshness_order_content_matches() { + let mut draft = receipt("b.sdoc", "MID-DOC", "MID-REQ-1", "REQ-1"); + draft.nodes[0] + .fields + .insert("STATEMENT".to_owned(), "needle".to_owned()); + draft + .document + .metadata + .insert("STATUS".to_owned(), "Draft".to_owned()); + draft + .document + .metadata + .insert("PUBLIC_BOUNDARY".to_owned(), "public".to_owned()); + let mut published = receipt("a.sdoc", "MID-DOC-2", "MID-REQ-2", "REQ-2"); + published.nodes[0] + .fields + .insert("STATEMENT".to_owned(), "needle".to_owned()); + let graph = graph(&[draft, published]); + let ids: Vec<_> = rank(&graph, "needle", 8) + .into_iter() + .map(|item| item.rank_key.mid) + .collect(); + assert_eq!(ids, vec!["MID-REQ-2", "MID-REQ-1"]); + } + + #[test] + fn duplicate_identity_and_unresolved_relation_fail_closed() { + let mut duplicate_node = receipt("b.sdoc", "MID-DOC-2", "MID-REQ", "REQ-2"); + duplicate_node.relations[0].mid = "REL-OTHER".to_owned(); + let duplicate = vec![ + receipt("a.sdoc", "MID-DOC", "MID-REQ", "REQ-1"), + duplicate_node, + ]; + assert!(matches!( + graph_input(&duplicate), + Err(SdocGraphError::DuplicateMid { .. }) + )); + let mut duplicate_uid_node = receipt("b.sdoc", "MID-DOC-2", "MID-REQ-2", "REQ-1"); + duplicate_uid_node.relations[0].mid = "REL-OTHER".to_owned(); + let duplicate_uid = vec![ + receipt("a.sdoc", "MID-DOC", "MID-REQ", "REQ-1"), + duplicate_uid_node, + ]; + assert!(matches!( + graph_input(&duplicate_uid), + Err(SdocGraphError::DuplicateUid { .. }) + )); + let mut unresolved = receipt("a.sdoc", "MID-DOC", "MID-REQ", "REQ-1"); + unresolved.relations[0].target_mid = "MID-MISSING".to_owned(); + assert!(matches!( + graph_input(&[unresolved]), + Err(SdocGraphError::UnresolvedRelation { target_mid, .. }) if target_mid == "MID-MISSING" + )); + } +} diff --git a/crates/bran-core/src/lib.rs b/crates/bran-core/src/lib.rs index 504b395..46c9aa4 100644 --- a/crates/bran-core/src/lib.rs +++ b/crates/bran-core/src/lib.rs @@ -16,6 +16,7 @@ pub mod profile; pub mod repair; pub mod scan; pub mod schema; +pub mod sdoc; pub mod view; // Profile validation exports (Slice 1.2 wiring only) diff --git a/crates/bran-core/src/sdoc.rs b/crates/bran-core/src/sdoc.rs new file mode 100644 index 0000000..cc972a4 --- /dev/null +++ b/crates/bran-core/src/sdoc.rs @@ -0,0 +1,1452 @@ +//! StrictDoc bridge v2 consumer for read-only `.sdoc` discovery. +//! +//! StrictDoc remains the SDoc grammar authority. This module invokes only an +//! explicitly configured absolute bridge command and validates its versioned +//! JSON receipt before exposing it to later graph and ranking work. + +use crate::agent::result_store::ResultId; +use crate::scan::ScanFailure; +use serde_json::{Map, Value}; +use std::collections::BTreeMap; +use std::fmt; +use std::fs; +use std::path::{Path, PathBuf}; +use std::process::Command; + +const MAX_SDOC_FILES: usize = 10_000; +const MAX_SDOC_FILE_BYTES: usize = 1024 * 1024; +const MAX_SDOC_TOTAL_BYTES: usize = 64 * 1024 * 1024; + +pub const BRIDGE_PROTOCOL: &str = "alphazede.strictdoc.bridge"; +pub const BRIDGE_SCHEMA_VERSION: &str = "2"; +pub const BRIDGE_MODE: &str = "sdoc"; +pub const STRICTDOC_API: &str = "strictdoc.api"; +pub const STRICTDOC_VERSION: &str = "0.29.0"; +pub const STRICTDOC_ARTIFACT_SHA256: &str = + "fae511b228952ee5e1ff765650ac2701526ce39e32a6686f53ef384621486a90"; +pub const STRICTDOC_REQUIREMENTS_SHA256: &str = + "77b879886d9856ca748e181b592e78efa377d432953ec52d6e61803cf10ef9c8"; + +/// Fixed startup bootstrap for the pinned interpreter, invoked under `-I -S -B`. +/// +/// `-I -S` starts the interpreter isolated and without `site`, so no +/// `sitecustomize`, `usercustomize`, `.pth`, inherited `PYTHONPATH`, or user +/// site-packages code can run before BRAN's verification. `-B` stops the +/// interpreter writing `__pycache__/*.pyc` back into the pinned import root: +/// BRAN must never mutate the tree whose closure it just verified, and a `.pyc` +/// written there would be unpinned executable input on the next run. +/// This constant then appends the pinned site-packages directory (appending +/// keeps the standard library ahead of it) and executes the hashed bridge, +/// which verifies every locked distribution RECORD before importing StrictDoc. +/// The directory and bridge arrive on `argv`, never interpolated into this +/// source. +const BRIDGE_BOOTSTRAP: &str = concat!( + "import sys\n", + "sys.path.append(sys.argv[1])\n", + "sys.argv = sys.argv[2:]\n", + "exec(compile(open(sys.argv[0], \"rb\").read(), sys.argv[0], \"exec\"), ", + "{\"__name__\": \"__main__\", \"__file__\": sys.argv[0]})\n", +); + +#[derive(Clone, Debug, Eq, PartialEq)] +pub struct SdocBridgeConfig { + program: PathBuf, + /// The real interpreter file the packaged `program` launcher execs. BRAN + /// runs this path directly so startup is isolated, and hashes it here so + /// the pin is independent of anything the interpreter reports about itself. + interpreter: PathBuf, + bridge: PathBuf, + wheel: PathBuf, + wheelhouse: PathBuf, + /// The pinned import root appended by [`BRIDGE_BOOTSTRAP`] after startup. + /// The hashed bridge verifies the files a locked distribution RECORD + /// claims; [`site_closure_digest`] independently rejects everything under + /// this root that no pin claims, so nothing unpinned can be imported. + site_packages: PathBuf, + hashes: PathBuf, + python_sha256: String, + interpreter_sha256: String, + bridge_sha256: String, + wheelhouse_sha256: String, + site_packages_sha256: String, + hashes_sha256: String, +} + +impl SdocBridgeConfig { + /// Production configuration is compiled into the packaged `.deb`; callers + /// cannot select an interpreter, bridge, wheel, or expected identity. + pub fn pinned_installation() -> Result { + let config = Self { + program: pinned_path(option_env!("AZREQ_STRICTDOC_PYTHON"))?, + interpreter: pinned_path(option_env!("AZREQ_STRICTDOC_INTERPRETER"))?, + bridge: pinned_path(option_env!("AZREQ_STRICTDOC_BRIDGE"))?, + wheel: pinned_path(option_env!("AZREQ_STRICTDOC_WHEEL"))?, + wheelhouse: pinned_path(option_env!("AZREQ_STRICTDOC_WHEELHOUSE"))?, + site_packages: pinned_path(option_env!("AZREQ_STRICTDOC_SITE_PACKAGES"))?, + hashes: pinned_path(option_env!("AZREQ_STRICTDOC_HASHES"))?, + python_sha256: pinned_digest(option_env!("AZREQ_STRICTDOC_PYTHON_SHA256"))?, + interpreter_sha256: pinned_digest(option_env!("AZREQ_STRICTDOC_INTERPRETER_SHA256"))?, + bridge_sha256: pinned_digest(option_env!("AZREQ_STRICTDOC_BRIDGE_SHA256"))?, + wheelhouse_sha256: pinned_digest(option_env!("AZREQ_STRICTDOC_WHEELHOUSE_SHA256"))?, + site_packages_sha256: pinned_digest(option_env!( + "AZREQ_STRICTDOC_SITE_PACKAGES_SHA256" + ))?, + hashes_sha256: pinned_digest(option_env!("AZREQ_STRICTDOC_HASHES_SHA256"))?, + }; + config.verify()?; + Ok(config) + } + + /// Test-only construction of an unpinned bridge, so behaviour tests can run + /// a fixture without production pins. The dedicated `test-fixtures` feature + /// keeps it out of every shipped binary — `bran-cli` enables it only through + /// its dev-dependency — while staying available in `--release` test builds, + /// which `debug_assertions` was not. + #[cfg(any(test, feature = "test-fixtures"))] + #[doc(hidden)] + pub fn new( + program: impl Into, + bridge: impl Into, + wheel: impl Into, + ) -> Result { + let config = Self { + program: program.into(), + interpreter: PathBuf::new(), + bridge: bridge.into(), + wheel: wheel.into(), + wheelhouse: PathBuf::new(), + site_packages: PathBuf::new(), + hashes: PathBuf::new(), + python_sha256: String::new(), + interpreter_sha256: String::new(), + bridge_sha256: String::new(), + wheelhouse_sha256: String::new(), + site_packages_sha256: String::new(), + hashes_sha256: String::new(), + }; + if !config.program.is_absolute() { + return Err(SdocError::RelativeBridgeProgram); + } + if !config.bridge.is_absolute() || !config.wheel.is_absolute() { + return Err(SdocError::RelativeBridgeInput); + } + Ok(config) + } + + fn verify(&self) -> Result<(), SdocError> { + // BRAN hashes every executed byte itself, before the interpreter runs. + // The bridge's self-reported engine digests are cross-checked later as + // defence in depth, never as the source of truth. + let checks: [(&Path, &str); 5] = [ + (&self.program, &self.python_sha256), + (&self.interpreter, &self.interpreter_sha256), + (&self.bridge, &self.bridge_sha256), + (&self.wheel, STRICTDOC_ARTIFACT_SHA256), + (&self.hashes, &self.hashes_sha256), + ]; + if checks.iter().any(|(path, expected)| { + !path.is_file() || sha256(&fs::read(path).unwrap_or_default()) != *expected + }) || !self.wheelhouse.is_dir() + || wheelhouse_digest(&self.wheelhouse)? != self.wheelhouse_sha256 + { + return Err(SdocError::QualifiedRuntimeMismatch); + } + // The bootstrap appends `site_packages` to `sys.path`, so every byte + // under it is executable input, not just the files a RECORD claims. + // Verifying the whole closure here is what stops an added package from + // running while the receipt still matches (W6.1-P1-05). + if !self.site_packages.is_dir() + || site_closure_digest(&self.site_packages)? != self.site_packages_sha256 + { + return Err(SdocError::UnpinnedRuntimeContent); + } + Ok(()) + } +} + +#[derive(Clone, Debug, Eq, PartialEq)] +pub struct SdocEngine { + pub api: String, + pub version: String, + pub artifact_sha256: String, + pub requirements_sha256: String, +} + +#[derive(Clone, Debug, Eq, PartialEq)] +pub struct SdocLineRange { + pub start: usize, + pub end: usize, +} + +#[derive(Clone, Debug, Eq, PartialEq)] +pub struct SdocDocument { + pub mid: String, + pub uid: String, + pub title: String, + pub metadata: BTreeMap, + pub line_range: SdocLineRange, +} + +#[derive(Clone, Debug, Eq, PartialEq)] +pub struct SdocNode { + pub mid: String, + pub uid: String, + pub node_type: String, + pub fields: BTreeMap, + pub line_range: SdocLineRange, +} + +#[derive(Clone, Debug, Eq, PartialEq)] +pub struct SdocRelation { + pub mid: String, + pub relation_type: String, + pub reference_type: String, + pub source_mid: String, + pub target_mid: String, + pub line_range: SdocLineRange, + /// The source node's declared OWNER, when the bridge reported one. + pub owner: Option, + /// The document's published revision, when the bridge reported one. + pub revision: Option, +} + +#[derive(Clone, Debug, Eq, PartialEq)] +pub struct SdocReceipt { + pub source_locator: String, + pub source_sha256: String, + pub validation: SdocValidation, + pub engine: SdocEngine, + pub document: SdocDocument, + pub nodes: Vec, + pub relations: Vec, +} + +#[derive(Clone, Copy, Debug, Eq, PartialEq)] +pub enum SdocValidation { + Valid, +} + +#[derive(Clone, Debug)] +pub struct SdocScanner { + root: PathBuf, + bridge: SdocBridgeConfig, +} + +impl SdocScanner { + pub fn new(root: impl AsRef, bridge: SdocBridgeConfig) -> Result { + let requested = root.as_ref().to_path_buf(); + let root = fs::canonicalize(&requested).map_err(|_| SdocError::InvalidRoot(requested))?; + if !root.is_dir() { + return Err(SdocError::InvalidRoot(root)); + } + Ok(Self { root, bridge }) + } + + /// Discovers `.sdoc` sources and invokes the bridge for each source only. + /// Markdown and generated views are intentionally not candidates here. + pub fn scan(&self) -> Result, SdocError> { + let mut sources = Vec::new(); + collect_sdoc_files(&self.root, &self.root, &mut sources)?; + if sources.len() > MAX_SDOC_FILES + || sources.iter().map(|(_, bytes)| bytes.len()).sum::() > MAX_SDOC_TOTAL_BYTES + { + return Err(SdocError::ScanLimit); + } + sources + .iter() + .map(|(locator, bytes)| self.scan_one(locator, bytes)) + .collect() + } + + fn scan_one(&self, locator: &str, expected_source: &[u8]) -> Result { + validate_locator(locator)?; + let source_path = self.root.join(locator); + let metadata = fs::symlink_metadata(&source_path) + .map_err(|_| SdocError::SourceMissing(locator.to_owned()))?; + if metadata.file_type().is_symlink() || !metadata.is_file() { + return Err(SdocError::SourceEscape(locator.to_owned())); + } + let source = fs::canonicalize(&source_path) + .map_err(|_| SdocError::SourceMissing(locator.to_owned()))?; + if !source.starts_with(&self.root) || !source.is_file() { + return Err(SdocError::SourceEscape(locator.to_owned())); + } + let before = fs::read(&source).map_err(|_| SdocError::SourceMissing(locator.to_owned()))?; + if before.as_slice() != expected_source { + return Err(SdocError::SourceChanged(locator.to_owned())); + } + let expected_digest = sha256(&before); + if !self.bridge.python_sha256.is_empty() { + self.bridge.verify()?; + } + let mut command = if self.bridge.python_sha256.is_empty() { + Command::new(&self.bridge.program) + } else { + // Run the hashed interpreter directly rather than the packaged + // launcher: the launcher exports PYTHONPATH, which would let a + // `sitecustomize` in that directory execute before verification. + let mut command = Command::new(&self.bridge.interpreter); + command + .arg("-I") + .arg("-S") + .arg("-B") + .arg("-c") + .arg(BRIDGE_BOOTSTRAP) + .arg(&self.bridge.site_packages); + command + }; + let output = command + .arg(&self.bridge.bridge) + .arg("--protocol") + .arg(BRIDGE_PROTOCOL) + .arg("--schema-version") + .arg(BRIDGE_SCHEMA_VERSION) + .arg("--mode") + .arg(BRIDGE_MODE) + .arg("--root") + .arg(&self.root) + .arg("--source") + .arg(&source) + .arg("--wheel") + .arg(&self.bridge.wheel) + .env_clear() + .env("LC_ALL", "C"); + let output = if self.bridge.python_sha256.is_empty() { + output.output() + } else { + output + .arg("--wheelhouse") + .arg(&self.bridge.wheelhouse) + .arg("--hashes") + .arg(&self.bridge.hashes) + .arg("--python-sha256") + .arg(&self.bridge.interpreter_sha256) + .arg("--bridge-sha256") + .arg(&self.bridge.bridge_sha256) + .arg("--artifact-sha256") + .arg(STRICTDOC_ARTIFACT_SHA256) + .arg("--requirements-sha256") + .arg(&self.bridge.hashes_sha256) + .arg("--wheelhouse-sha256") + .arg(&self.bridge.wheelhouse_sha256) + .output() + } + .map_err(|_| SdocError::BridgeTransport)?; + let after = fs::read(&source).map_err(|_| SdocError::SourceMissing(locator.to_owned()))?; + if after != before { + return Err(SdocError::SourceChanged(locator.to_owned())); + } + if !output.status.success() && output.stdout.is_empty() { + return Err(SdocError::BridgeExit(output.status.code())); + } + let receipt = parse_bridge_envelope(&output.stdout, locator, &expected_digest); + if output.status.success() { + let receipt = receipt?; + if !self.bridge.python_sha256.is_empty() + && !runtime_receipt_matches(&output.stdout, &self.bridge) + { + return Err(SdocError::QualifiedRuntimeMismatch); + } + return Ok(receipt); + } + match receipt { + Err(error) => Err(error), + Ok(_) => Err(SdocError::BridgeExit(output.status.code())), + } + } +} + +pub fn parse_bridge_envelope( + bytes: &[u8], + expected_locator: &str, + expected_source_sha256: &str, +) -> Result { + validate_locator(expected_locator)?; + let value = serde_json::from_slice(bytes).map_err(|_| SdocError::MalformedJson)?; + let top = closed_object( + &value, + &["protocol", "schema_version", "status"], + &[ + "protocol", + "schema_version", + "status", + "mode", + "validation", + "engine", + "source", + "document", + "nodes", + "relations", + "error", + ], + "envelope", + )?; + exact_string(top, "protocol", BRIDGE_PROTOCOL, SdocError::Protocol)?; + exact_string( + top, + "schema_version", + BRIDGE_SCHEMA_VERSION, + SdocError::SchemaVersion, + )?; + let status = string(top, "status", "envelope")?; + if status != "ok" { + return bridge_failure(top, status); + } + reject_present(top, "error", "envelope")?; + exact_string(top, "mode", BRIDGE_MODE, SdocError::ModeMismatch)?; + let validation = closed_object( + field(top, "validation", "envelope")?, + &["status"], + &["status"], + "validation", + )?; + exact_string( + validation, + "status", + "valid", + SdocError::InvalidEnvelope("validation status"), + )?; + let engine = parse_engine(field(top, "engine", "envelope")?)?; + let (source_locator, source_sha256) = parse_source(field(top, "source", "envelope")?)?; + if source_locator != expected_locator || source_sha256 != expected_source_sha256 { + return Err(SdocError::SourceReceiptMismatch); + } + let document = parse_document(field(top, "document", "envelope")?)?; + let nodes = array(field(top, "nodes", "envelope")?, "nodes")? + .iter() + .map(parse_node) + .collect::, _>>()?; + let relations = array(field(top, "relations", "envelope")?, "relations")? + .iter() + .map(parse_relation) + .collect::, _>>()?; + Ok(SdocReceipt { + source_locator, + source_sha256, + validation: SdocValidation::Valid, + engine, + document, + nodes, + relations, + }) +} + +fn bridge_failure(top: &Map, status: &str) -> Result { + if !matches!( + status, + "invalid_request" + | "engine_missing" + | "engine_mismatch" + | "parse_error" + | "validation_error" + | "source_changed" + | "bridge_error" + ) { + return Err(SdocError::InvalidEnvelope("unknown status")); + } + if top + .keys() + .any(|key| !["protocol", "schema_version", "status", "error"].contains(&key.as_str())) + { + return Err(SdocError::InvalidEnvelope("failure envelope")); + } + let error = closed_object( + field(top, "error", "envelope")?, + &["code"], + &["code"], + "error", + )?; + Err(SdocError::BridgeStatus { + status: status.to_owned(), + code: nonempty(string(error, "code", "error")?, "error code")?.to_owned(), + }) +} + +fn parse_engine(value: &Value) -> Result { + let engine = closed_object( + value, + &["api", "version", "artifact_sha256", "requirements_sha256"], + &[ + "api", + "version", + "artifact_sha256", + "requirements_sha256", + "python_sha256", + "bridge_sha256", + "wheelhouse_sha256", + ], + "engine", + )?; + exact_string(engine, "api", STRICTDOC_API, SdocError::EngineMismatch)?; + exact_string( + engine, + "version", + STRICTDOC_VERSION, + SdocError::EngineMismatch, + )?; + exact_string( + engine, + "artifact_sha256", + STRICTDOC_ARTIFACT_SHA256, + SdocError::EngineMismatch, + )?; + exact_string( + engine, + "requirements_sha256", + STRICTDOC_REQUIREMENTS_SHA256, + SdocError::EngineMismatch, + )?; + Ok(SdocEngine { + api: STRICTDOC_API.to_owned(), + version: STRICTDOC_VERSION.to_owned(), + artifact_sha256: STRICTDOC_ARTIFACT_SHA256.to_owned(), + requirements_sha256: STRICTDOC_REQUIREMENTS_SHA256.to_owned(), + }) +} + +/// Cross-checks the bridge's self-reported engine digests against the pins. +/// This is defence in depth only; [`SdocBridgeConfig::verify`] has already +/// hashed the interpreter, bridge, wheel, and lock in Rust before execution. +fn runtime_receipt_matches(bytes: &[u8], config: &SdocBridgeConfig) -> bool { + serde_json::from_slice::(bytes) + .ok() + .and_then(|value| value.get("engine")?.as_object().cloned()) + .is_some_and(|engine| { + engine.get("python_sha256").and_then(Value::as_str) == Some(&config.interpreter_sha256) + && engine.get("bridge_sha256").and_then(Value::as_str) + == Some(&config.bridge_sha256) + && engine.get("wheelhouse_sha256").and_then(Value::as_str) + == Some(&config.wheelhouse_sha256) + }) +} + +fn parse_source(value: &Value) -> Result<(String, String), SdocError> { + let source = closed_object( + value, + &["locator", "sha256"], + &["locator", "sha256"], + "source", + )?; + let locator = nonempty(string(source, "locator", "source")?, "source locator")?; + validate_locator(locator)?; + let digest = nonempty(string(source, "sha256", "source")?, "source digest")?; + if !is_sha256(digest) { + return Err(SdocError::InvalidEnvelope("source digest")); + } + Ok((locator.to_owned(), digest.to_owned())) +} + +fn parse_document(value: &Value) -> Result { + let document = closed_object( + value, + &["mid", "uid", "title", "metadata", "line_range"], + &["mid", "uid", "title", "metadata", "line_range"], + "document", + )?; + Ok(SdocDocument { + mid: identifier(document, "mid", "document")?, + uid: identifier(document, "uid", "document")?, + title: nonempty(string(document, "title", "document")?, "document title")?.to_owned(), + metadata: string_map( + field(document, "metadata", "document")?, + "document metadata", + )?, + line_range: line_range( + field(document, "line_range", "document")?, + "document line range", + )?, + }) +} + +fn parse_node(value: &Value) -> Result { + let node = closed_object( + value, + &["mid", "uid", "node_type", "fields", "line_range"], + &["mid", "uid", "node_type", "fields", "line_range"], + "node", + )?; + Ok(SdocNode { + mid: identifier(node, "mid", "node")?, + uid: identifier(node, "uid", "node")?, + node_type: nonempty(string(node, "node_type", "node")?, "node type")?.to_owned(), + fields: string_map(field(node, "fields", "node")?, "node fields")?, + line_range: line_range(field(node, "line_range", "node")?, "node line range")?, + }) +} + +fn parse_relation(value: &Value) -> Result { + let relation = closed_object( + value, + &[ + "mid", + "type", + "relation_type", + "source_mid", + "target_mid", + "line_range", + ], + &[ + "mid", + "type", + "relation_type", + "source_mid", + "target_mid", + "line_range", + "owner", + "revision", + ], + "relation", + )?; + Ok(SdocRelation { + mid: identifier(relation, "mid", "relation")?, + relation_type: nonempty(string(relation, "type", "relation")?, "relation type")?.to_owned(), + reference_type: nonempty( + string(relation, "relation_type", "relation")?, + "relation reference type", + )? + .to_owned(), + source_mid: identifier(relation, "source_mid", "relation")?, + target_mid: identifier(relation, "target_mid", "relation")?, + line_range: line_range( + field(relation, "line_range", "relation")?, + "relation line range", + )?, + owner: optional_nonempty(relation, "owner", "relation owner")?, + revision: optional_nonempty(relation, "revision", "relation revision")?, + }) +} + +/// An optional string member that, when present, must be a non-empty string. +fn optional_nonempty( + object: &Map, + key: &str, + label: &'static str, +) -> Result, SdocError> { + match object.get(key) { + None => Ok(None), + Some(value) => { + let text = value.as_str().ok_or(SdocError::InvalidEnvelope(label))?; + Ok(Some(nonempty(text, label)?.to_owned())) + } + } +} + +fn closed_object<'a>( + value: &'a Value, + required: &[&str], + allowed: &[&str], + label: &'static str, +) -> Result<&'a Map, SdocError> { + let object = value.as_object().ok_or(SdocError::InvalidEnvelope(label))?; + if required.iter().any(|key| !object.contains_key(*key)) + || object.keys().any(|key| !allowed.contains(&key.as_str())) + { + return Err(SdocError::InvalidEnvelope(label)); + } + Ok(object) +} + +fn field<'a>( + object: &'a Map, + key: &str, + label: &'static str, +) -> Result<&'a Value, SdocError> { + object.get(key).ok_or(SdocError::InvalidEnvelope(label)) +} + +fn string<'a>( + object: &'a Map, + key: &str, + label: &'static str, +) -> Result<&'a str, SdocError> { + field(object, key, label)? + .as_str() + .ok_or(SdocError::InvalidEnvelope(label)) +} + +fn exact_string( + object: &Map, + key: &str, + expected: &str, + error: SdocError, +) -> Result<(), SdocError> { + (string(object, key, "envelope")? == expected) + .then_some(()) + .ok_or(error) +} + +fn reject_present( + object: &Map, + key: &str, + label: &'static str, +) -> Result<(), SdocError> { + (!object.contains_key(key)) + .then_some(()) + .ok_or(SdocError::InvalidEnvelope(label)) +} + +fn array<'a>(value: &'a Value, label: &'static str) -> Result<&'a Vec, SdocError> { + value.as_array().ok_or(SdocError::InvalidEnvelope(label)) +} + +fn string_map(value: &Value, label: &'static str) -> Result, SdocError> { + let map = value.as_object().ok_or(SdocError::InvalidEnvelope(label))?; + map.iter() + .map(|(key, value)| { + let value = value.as_str().ok_or(SdocError::InvalidEnvelope(label))?; + nonempty(key, label)?; + Ok((key.clone(), value.to_owned())) + }) + .collect() +} + +fn line_range(value: &Value, label: &'static str) -> Result { + let range = closed_object(value, &["start", "end"], &["start", "end"], label)?; + let start = positive_line(field(range, "start", label)?, label)?; + let end = positive_line(field(range, "end", label)?, label)?; + (start <= end) + .then_some(SdocLineRange { start, end }) + .ok_or(SdocError::InvalidEnvelope(label)) +} + +fn positive_line(value: &Value, label: &'static str) -> Result { + value + .as_u64() + .and_then(|line| usize::try_from(line).ok()) + .filter(|line| *line > 0) + .ok_or(SdocError::InvalidEnvelope(label)) +} + +fn identifier( + object: &Map, + key: &str, + label: &'static str, +) -> Result { + let value = nonempty(string(object, key, label)?, label)?; + (!value.chars().any(char::is_control)) + .then(|| value.to_owned()) + .ok_or(SdocError::InvalidEnvelope(label)) +} + +fn nonempty<'a>(value: &'a str, label: &'static str) -> Result<&'a str, SdocError> { + (!value.trim().is_empty()) + .then_some(value) + .ok_or(SdocError::InvalidEnvelope(label)) +} + +fn validate_locator(locator: &str) -> Result<(), SdocError> { + if locator.is_empty() + || locator.contains(['\\', '\0']) + || Path::new(locator).is_absolute() + || locator.as_bytes().get(0..3).is_some_and(|prefix| { + prefix[0].is_ascii_alphabetic() && prefix[1] == b':' && prefix[2] == b'/' + }) + || locator + .split('/') + .any(|part| part.is_empty() || matches!(part, "." | ".." | ".git")) + { + return Err(SdocError::UnsafeLocator); + } + Ok(()) +} + +fn is_sha256(value: &str) -> bool { + value.len() == 64 + && value + .bytes() + .all(|byte| byte.is_ascii_digit() || matches!(byte, b'a'..=b'f')) +} + +fn sha256(bytes: &[u8]) -> String { + ResultId::sha256(bytes).value().to_owned() +} + +fn pinned_path(value: Option<&'static str>) -> Result { + value + .map(PathBuf::from) + .filter(|path| path.is_absolute()) + .ok_or(SdocError::PinnedRuntimeUnavailable) +} + +fn pinned_digest(value: Option<&'static str>) -> Result { + value + .filter(|digest| is_sha256(digest)) + .map(str::to_owned) + .ok_or(SdocError::PinnedRuntimeUnavailable) +} + +fn wheelhouse_digest(wheelhouse: &Path) -> Result { + let mut entries = fs::read_dir(wheelhouse) + .map_err(|_| SdocError::QualifiedRuntimeMismatch)? + .filter_map(Result::ok) + .filter_map(|entry| { + let path = entry.path(); + path.extension() + .is_some_and(|ext| ext == "whl") + .then(|| { + fs::read(&path) + .ok() + .map(|bytes| (entry.file_name(), sha256(&bytes))) + }) + .flatten() + }) + .collect::>(); + entries.sort(); + (!entries.is_empty()) + .then(|| { + sha256( + entries + .iter() + .map(|(name, digest)| format!("{}:{digest}", name.to_string_lossy())) + .collect::>() + .join("\n") + .as_bytes(), + ) + }) + .ok_or(SdocError::QualifiedRuntimeMismatch) +} + +/// Deterministic digest of the complete pinned import root. +/// +/// Every regular file under `root` contributes one `relative/path:size:sha256` +/// line; the lines are sorted bytewise, joined by `\n`, and hashed. +/// `build/build-pinned.sh` computes the identical value, so a pin that no +/// longer describes the installed tree fails the build gate as well as this +/// check. +/// +/// This is preferred over a RECORD-coverage set difference because it is one +/// definition both Rust and the build gate can compute identically: it needs no +/// RECORD parsing or quoting rules, no judgement about which file extensions +/// the interpreter can import, and it rejects edited and deleted files as well +/// as added ones. A path that is not a regular file, or whose name holds a +/// newline, cannot be described by that manifest and is rejected outright. +/// +/// The cost is one full read of the import root per verification — 0.85s for +/// the 264 MiB 0.1.0-12 tree — and [`SdocScanner::scan_one`] verifies once per +/// source, so a scan of many `.sdoc` files pays it repeatedly. That is +/// deliberate: re-reading is what makes the check hold at the moment of +/// execution rather than at startup. +fn site_closure_digest(root: &Path) -> Result { + let mut lines = Vec::new(); + collect_site_closure(root, root, &mut lines)?; + lines.sort(); + (!lines.is_empty()) + .then(|| sha256(lines.join("\n").as_bytes())) + .ok_or(SdocError::UnpinnedRuntimeContent) +} + +fn collect_site_closure( + root: &Path, + directory: &Path, + lines: &mut Vec, +) -> Result<(), SdocError> { + for entry in fs::read_dir(directory).map_err(|_| SdocError::UnpinnedRuntimeContent)? { + let path = entry.map_err(|_| SdocError::UnpinnedRuntimeContent)?.path(); + let metadata = + fs::symlink_metadata(&path).map_err(|_| SdocError::UnpinnedRuntimeContent)?; + if metadata.is_dir() { + collect_site_closure(root, &path, lines)?; + continue; + } + // A symlink, device, or socket on `sys.path` supplies executable input + // this manifest cannot describe by content, so it is never pinnable. + if !metadata.is_file() { + return Err(SdocError::UnpinnedRuntimeContent); + } + let relative = path + .strip_prefix(root) + .ok() + .and_then(|relative| relative.to_str()) + .filter(|relative| !relative.contains('\n')) + .ok_or(SdocError::UnpinnedRuntimeContent)?; + let bytes = fs::read(&path).map_err(|_| SdocError::UnpinnedRuntimeContent)?; + lines.push(format!("{relative}:{}:{}", bytes.len(), sha256(&bytes))); + } + Ok(()) +} + +fn collect_sdoc_files( + root: &Path, + directory: &Path, + output: &mut Vec<(String, Vec)>, +) -> Result<(), SdocError> { + let mut entries = fs::read_dir(directory) + .map_err(|_| SdocError::ScanLimit)? + .collect::, _>>() + .map_err(|_| SdocError::ScanLimit)?; + entries.sort_by_key(|entry| entry.file_name()); + for entry in entries { + let path = entry.path(); + let metadata = fs::symlink_metadata(&path).map_err(|_| SdocError::ScanLimit)?; + if metadata.file_type().is_symlink() { + continue; + } + if metadata.is_dir() { + collect_sdoc_files(root, &path, output)?; + continue; + } + if !metadata.is_file() || path.extension().is_none_or(|ext| ext != "sdoc") { + continue; + } + let bytes = fs::read(&path).map_err(|_| SdocError::ScanLimit)?; + if bytes.len() > MAX_SDOC_FILE_BYTES { + return Err(SdocError::ScanLimit); + } + let locator = path + .strip_prefix(root) + .map_err(|_| SdocError::SourceEscape(path.display().to_string()))? + .to_string_lossy() + .replace('\\', "/"); + validate_locator(&locator)?; + output.push((locator, bytes)); + } + Ok(()) +} + +#[derive(Debug)] +pub enum SdocError { + InvalidRoot(PathBuf), + RelativeBridgeProgram, + RelativeBridgeInput, + PinnedRuntimeUnavailable, + QualifiedRuntimeMismatch, + UnpinnedRuntimeContent, + ScanLimit, + Scan(ScanFailure), + SourceMissing(String), + SourceEscape(String), + SourceChanged(String), + BridgeTransport, + BridgeExit(Option), + MalformedJson, + Protocol, + SchemaVersion, + ModeMismatch, + EngineMismatch, + SourceReceiptMismatch, + UnsafeLocator, + BridgeStatus { status: String, code: String }, + InvalidEnvelope(&'static str), +} + +impl fmt::Display for SdocError { + fn fmt(&self, formatter: &mut fmt::Formatter<'_>) -> fmt::Result { + match self { + Self::InvalidRoot(_) => formatter.write_str("invalid SDoc scanner root"), + Self::RelativeBridgeProgram => formatter.write_str("bridge program must be absolute"), + Self::RelativeBridgeInput => formatter.write_str("bridge inputs must be absolute"), + Self::PinnedRuntimeUnavailable => { + formatter.write_str("packaged StrictDoc runtime is unavailable") + } + Self::QualifiedRuntimeMismatch => { + formatter.write_str("packaged StrictDoc runtime identity mismatches") + } + Self::UnpinnedRuntimeContent => { + formatter.write_str("packaged StrictDoc import root holds unpinned content") + } + Self::ScanLimit => formatter.write_str("SDoc discovery limit exceeded"), + Self::Scan(_) => formatter.write_str("SDoc discovery scan failed"), + Self::SourceMissing(_) => formatter.write_str("SDoc source is missing"), + Self::SourceEscape(_) => formatter.write_str("SDoc source escapes scanner root"), + Self::SourceChanged(_) => formatter.write_str("SDoc source changed during bridge scan"), + Self::BridgeTransport => formatter.write_str("SDoc bridge could not run"), + Self::BridgeExit(_) => formatter.write_str("SDoc bridge returned nonzero"), + Self::MalformedJson => formatter.write_str("SDoc bridge returned malformed JSON"), + Self::Protocol => formatter.write_str("unsupported SDoc bridge protocol"), + Self::SchemaVersion => formatter.write_str("unsupported SDoc bridge schema version"), + Self::ModeMismatch => formatter.write_str("unsupported SDoc bridge mode"), + Self::EngineMismatch => formatter.write_str("unqualified StrictDoc bridge engine"), + Self::SourceReceiptMismatch => { + formatter.write_str("SDoc bridge receipt mismatches source") + } + Self::UnsafeLocator => formatter.write_str("unsafe SDoc source locator"), + Self::BridgeStatus { .. } => formatter.write_str("SDoc bridge rejected source"), + Self::InvalidEnvelope(_) => formatter.write_str("invalid SDoc bridge envelope"), + } + } +} + +impl std::error::Error for SdocError {} + +#[cfg(test)] +mod tests { + use super::*; + use std::os::unix::fs::PermissionsExt; + + fn root() -> PathBuf { + let path = std::env::temp_dir().join(format!( + "bran-sdoc-{}-{}", + std::process::id(), + std::thread::current().name().unwrap_or("test") + )); + let _ = fs::remove_dir_all(&path); + fs::create_dir_all(&path).unwrap(); + path + } + + fn envelope(locator: &str, source: &[u8]) -> String { + format!( + r#"{{"document":{{"line_range":{{"end":3,"start":1}},"metadata":{{"type":"architecture"}},"mid":"MID-DOCUMENT-001","title":"Spec","uid":"DOC-001"}},"engine":{{"api":"{STRICTDOC_API}","artifact_sha256":"{STRICTDOC_ARTIFACT_SHA256}","requirements_sha256":"{STRICTDOC_REQUIREMENTS_SHA256}","version":"{STRICTDOC_VERSION}"}},"mode":"{BRIDGE_MODE}","nodes":[{{"fields":{{"STATUS":"Draft"}},"line_range":{{"end":3,"start":2}},"mid":"MID-REQ-001","node_type":"Requirement","uid":"REQ-001"}}],"protocol":"{BRIDGE_PROTOCOL}","relations":[{{"line_range":{{"end":3,"start":3}},"mid":"MID-REL-001","relation_type":"Reference","source_mid":"MID-REQ-001","target_mid":"MID-DOCUMENT-001","type":"relates"}}],"schema_version":"{BRIDGE_SCHEMA_VERSION}","source":{{"locator":"{locator}","sha256":"{}"}},"status":"ok","validation":{{"status":"valid"}}}}"#, + sha256(source) + ) + } + + fn bridge(root: &Path, body: &str) -> SdocBridgeConfig { + let script = root.join("bridge.sh"); + let wheel = root.join("strictdoc.whl"); + fs::write(&script, body).unwrap(); + fs::set_permissions(&script, fs::Permissions::from_mode(0o700)).unwrap(); + fs::write(&wheel, b"qualified test wheel").unwrap(); + SdocBridgeConfig::new("/bin/sh", script, wheel).unwrap() + } + + #[test] + fn discovers_sdoc_with_absolute_bridge_and_preserves_exact_records() { + let root = root(); + fs::create_dir_all(root.join("docs")).unwrap(); + let source = b"[DOCUMENT]\nTITLE: Spec\n"; + fs::write(root.join("docs/spec.sdoc"), source).unwrap(); + fs::write(root.join("docs/generated.md"), b"generated view").unwrap(); + let json = envelope("docs/spec.sdoc", source); + let config = bridge(&root, &format!("#!/bin/sh\nprintf '%s' '{json}'\n")); + let scanner = SdocScanner::new(&root, config).unwrap(); + let receipts = scanner.scan().unwrap(); + assert_eq!(receipts.len(), 1); + assert_eq!(receipts[0].source_locator, "docs/spec.sdoc"); + assert_eq!(receipts[0].document.mid, "MID-DOCUMENT-001"); + assert_eq!(receipts[0].nodes[0].fields["STATUS"], "Draft"); + assert_eq!(receipts[0].relations[0].target_mid, "MID-DOCUMENT-001"); + assert_eq!(fs::read(root.join("docs/spec.sdoc")).unwrap(), source); + assert!(matches!( + SdocBridgeConfig::new("bridge", "/tmp/bridge", "/tmp/wheel"), + Err(SdocError::RelativeBridgeProgram) + )); + fs::remove_dir_all(root).unwrap(); + } + + /// W6.1-P1-01: the pinned invocation must not let a `sitecustomize` on the + /// bridge's own import root execute before the bridge verifies anything. + /// The packaged launcher exported `PYTHONPATH`, which did exactly that, so + /// this pins the replacement shape: `-I -S` plus [`BRIDGE_BOOTSTRAP`]. + #[test] + fn pinned_startup_never_executes_site_customisation_before_the_bridge() { + let Ok(interpreter) = which_python3() else { + return; + }; + let root = root(); + let site = root.join("site-packages"); + fs::create_dir_all(&site).unwrap(); + fs::write(site.join("sitecustomize.py"), b"print('SITE_CUSTOMIZE')\n").unwrap(); + fs::write(site.join("usercustomize.py"), b"print('USER_CUSTOMIZE')\n").unwrap(); + // Imported from the appended root, so a missing `-B` would leave a + // `__pycache__` entry behind and move the closure digest. + fs::write(site.join("pinned_module.py"), b"VALUE = 1\n").unwrap(); + let script = root.join("bridge.py"); + fs::write( + &script, + b"import sys\nimport pinned_module\nprint('BRIDGE', sys.argv[1])\n", + ) + .unwrap(); + let pinned_closure = site_closure_digest(&site).unwrap(); + + let output = Command::new(&interpreter) + .arg("-I") + .arg("-S") + .arg("-B") + .arg("-c") + .arg(BRIDGE_BOOTSTRAP) + .arg(&site) + .arg(&script) + .arg("--mode") + .env_clear() + .env("LC_ALL", "C") + // A hostile inherited PYTHONPATH must be ignored as well. + .env("PYTHONPATH", &site) + .output() + .unwrap(); + + let stdout = String::from_utf8_lossy(&output.stdout).into_owned(); + assert!(!stdout.contains("SITE_CUSTOMIZE"), "{stdout}"); + assert!(!stdout.contains("USER_CUSTOMIZE"), "{stdout}"); + assert!(stdout.contains("BRIDGE --mode"), "{stdout}"); + // Without `-B` the run writes `__pycache__` into the import root, so + // the closure BRAN just verified would no longer match its pin on the + // next run wherever site-packages is writable. + assert_eq!(site_closure_digest(&site).unwrap(), pinned_closure); + fs::remove_dir_all(root).unwrap(); + } + + /// Builds a small stand-in for the pinned import root: a top-level module, + /// a package, and a compiled artifact, mirroring what a wheel installs. + fn site_fixture(root: &Path) -> PathBuf { + let site = root.join("site-packages"); + fs::create_dir_all(site.join("strictdoc/__pycache__")).unwrap(); + fs::create_dir_all(site.join("strictdoc-0.29.0.dist-info")).unwrap(); + fs::write(site.join("typing_extensions.py"), b"VERSION = 1\n").unwrap(); + fs::write(site.join("strictdoc/__init__.py"), b"import sys\n").unwrap(); + fs::write(site.join("strictdoc/__pycache__/__init__.pyc"), b"\x00pyc").unwrap(); + fs::write( + site.join("strictdoc-0.29.0.dist-info/RECORD"), + b"strictdoc/__init__.py,,\n", + ) + .unwrap(); + site + } + + /// W6.1-P1-05: the bridge verifies only the files a locked RECORD claims, + /// so an *added* importable file shadowed a pinned distribution and still + /// produced a fully matching receipt. Everything under the appended import + /// root is executable input, so the closure digest must move for any added, + /// edited, or removed byte, and must refuse content it cannot describe. + #[test] + fn unpinned_content_in_the_import_root_breaks_the_site_closure_digest() { + let root = root(); + let site = site_fixture(&root); + let pinned = site_closure_digest(&site).unwrap(); + assert!(is_sha256(&pinned)); + assert_eq!(site_closure_digest(&site).unwrap(), pinned); + + // The reviewer's reproduction: an untracked package that no RECORD + // claims, shadowing the pinned top-level `typing_extensions` module. + let extra = site.join("typing_extensions"); + fs::create_dir_all(&extra).unwrap(); + fs::write(extra.join("__init__.py"), b"import os\n").unwrap(); + let shadowed = site_closure_digest(&site).unwrap(); + assert_ne!(shadowed, pinned); + fs::remove_dir_all(&extra).unwrap(); + assert_eq!(site_closure_digest(&site).unwrap(), pinned); + + // An edited pinned file and a removed one move the digest too, which a + // RECORD-coverage check alone would not catch. + fs::write(site.join("strictdoc/__init__.py"), b"import os\n").unwrap(); + assert_ne!(site_closure_digest(&site).unwrap(), pinned); + fs::remove_file(site.join("strictdoc/__init__.py")).unwrap(); + assert_ne!(site_closure_digest(&site).unwrap(), pinned); + + // A symlink and an empty root are unpinnable rather than merely + // different, so neither can be made to match by choosing a pin. + let bare = root.join("bare"); + fs::create_dir_all(&bare).unwrap(); + assert!(matches!( + site_closure_digest(&bare), + Err(SdocError::UnpinnedRuntimeContent) + )); + std::os::unix::fs::symlink(root.join("elsewhere.py"), site.join("linked.py")).unwrap(); + assert!(matches!( + site_closure_digest(&site), + Err(SdocError::UnpinnedRuntimeContent) + )); + fs::remove_dir_all(root).unwrap(); + } + + /// The build gate must reject a drifted pin *before* cargo runs, so its + /// shell definition has to produce the byte-identical digest this module + /// recomputes at run time. A silent divergence would ship a binary that + /// fails closed on the user's machine, so the two are compared here. + #[test] + fn site_closure_digest_matches_the_build_gate_definition() { + let gate = Path::new(env!("CARGO_MANIFEST_DIR")).join("../../build/closure-digest.sh"); + let root = root(); + let site = site_fixture(&root); + let output = Command::new("/bin/sh") + .arg("-c") + .arg(". \"$1\"; site_closure_digest \"$2\"") + .arg("sh") + .arg(&gate) + .arg(&site) + .output() + .unwrap(); + let shell = String::from_utf8_lossy(&output.stdout).trim().to_owned(); + if shell.is_empty() { + // No GNU find or sha256sum here; the gate itself is not exercised. + fs::remove_dir_all(root).unwrap(); + return; + } + assert_eq!(shell, site_closure_digest(&site).unwrap()); + fs::remove_dir_all(root).unwrap(); + } + + /// Resolves a system `python3` the way `sys.executable` would, or reports + /// its absence so the startup regression skips rather than installs one. + fn which_python3() -> Result { + ["/usr/bin/python3", "/bin/python3", "/usr/local/bin/python3"] + .into_iter() + .map(PathBuf::from) + .find(|path| path.is_file()) + .map(|path| fs::canonicalize(&path).unwrap_or(path)) + .ok_or(()) + } + + /// The requirements-system bridge reports a relation's owner and revision + /// when the document carries them (azedge#74). They are optional: an + /// older bridge omits them, a present value must be a non-empty string. + #[test] + fn relation_owner_and_revision_are_optional_but_never_blank() { + let source = b"[DOCUMENT]\n"; + let valid = envelope("spec.sdoc", source); + let digest = sha256(source); + let bare = parse_bridge_envelope(valid.as_bytes(), "spec.sdoc", &digest).unwrap(); + assert_eq!(bare.relations[0].owner, None); + assert_eq!(bare.relations[0].revision, None); + + let mut value: Value = serde_json::from_str(&valid).unwrap(); + let relation = value["relations"][0].as_object_mut().unwrap(); + relation.insert("owner".to_owned(), Value::from("Pipeline specification")); + relation.insert("revision".to_owned(), Value::from("draft-unpublished")); + let carried = + parse_bridge_envelope(value.to_string().as_bytes(), "spec.sdoc", &digest).unwrap(); + assert_eq!( + carried.relations[0].owner.as_deref(), + Some("Pipeline specification") + ); + assert_eq!( + carried.relations[0].revision.as_deref(), + Some("draft-unpublished") + ); + + value["relations"][0]["owner"] = Value::from(" "); + assert!(matches!( + parse_bridge_envelope(value.to_string().as_bytes(), "spec.sdoc", &digest), + Err(SdocError::InvalidEnvelope("relation owner")) + )); + } + + /// Captured verbatim from the packaged requirements-system bridge + /// (0.1.0-12) run with `--schema-version 2 --mode sdoc` over the qualified + /// wheelhouse, so the parse and the runtime receipt are checked against + /// what the engine actually emits rather than a hand-written shape. + const SCHEMA_TWO_RUN: &str = r#"{"document":{"line_range":{"end":38,"start":1},"metadata":{"published_revision":"REV-1"},"mid":"b9a2890f72ad4c3da988648417e33ad4","title":"Bridge Fixture","uid":"FIXTURE-DOC"},"engine":{"api":"strictdoc.api","artifact_sha256":"fae511b228952ee5e1ff765650ac2701526ce39e32a6686f53ef384621486a90","bridge_sha256":"267a2225fe821921e13fcbaba33b3dc332fa6506ccc60b10ea246536dbd8d676","python_sha256":"a92f0f95e883390c7256b2e441484aac06b1002dbe1d924141a77c8d82f96223","requirements_sha256":"77b879886d9856ca748e181b592e78efa377d432953ec52d6e61803cf10ef9c8","version":"0.29.0","wheelhouse_sha256":"aa961f820c4a3d8fd3646e5dadb0f3993051e028a9ce8ab977e1db74619872a9"},"mode":"sdoc","nodes":[{"fields":{"OWNER":"Bridge fixture","STATEMENT":"The bridge reports a schema 2 envelope.","UID":"REQ-1"},"line_range":{"end":29,"start":25},"mid":"f9cbb2050ef541ffae88e67dc9eea43e","node_type":"REQUIREMENT","uid":"REQ-1"},{"fields":{"OWNER":"Bridge fixture","STATEMENT":"The consumer accepts it.","UID":"REQ-2"},"line_range":{"end":38,"start":30},"mid":"726c9e0c95ee400c915b7f73233571da","node_type":"REQUIREMENT","uid":"REQ-2"}],"protocol":"alphazede.strictdoc.bridge","relations":[{"line_range":{"end":38,"start":35},"mid":"0a46bb7e28b7e206f84fee642f7b398e","owner":"Bridge fixture","relation_type":"Parent","revision":"REV-1","source_mid":"726c9e0c95ee400c915b7f73233571da","target_mid":"f9cbb2050ef541ffae88e67dc9eea43e","type":"derives-from"}],"schema_version":"2","source":{"locator":"spec.sdoc","sha256":"0e1e16250e6052cf33edf4745330e3ae47a4f956892813e522140da071c3d4e7"},"status":"ok","validation":{"status":"valid"}}"#; + const RUN_INTERPRETER_SHA256: &str = + "a92f0f95e883390c7256b2e441484aac06b1002dbe1d924141a77c8d82f96223"; + const RUN_BRIDGE_SHA256: &str = + "267a2225fe821921e13fcbaba33b3dc332fa6506ccc60b10ea246536dbd8d676"; + const RUN_WHEELHOUSE_SHA256: &str = + "aa961f820c4a3d8fd3646e5dadb0f3993051e028a9ce8ab977e1db74619872a9"; + const RUN_SOURCE_SHA256: &str = + "0e1e16250e6052cf33edf4745330e3ae47a4f956892813e522140da071c3d4e7"; + + fn qualified_config() -> SdocBridgeConfig { + SdocBridgeConfig { + program: PathBuf::from("/usr/lib/engine/bin/python"), + interpreter: PathBuf::from("/usr/bin/python3.12"), + bridge: PathBuf::from("/usr/lib/engine/strictdoc_bridge.py"), + wheel: PathBuf::from("/usr/lib/engine/wheels/strictdoc.whl"), + wheelhouse: PathBuf::from("/usr/lib/engine/wheels"), + site_packages: PathBuf::from("/usr/lib/engine/site-packages"), + hashes: PathBuf::from("/usr/lib/engine/hashes.txt"), + // The launcher file digest is local-only; it is deliberately not + // the interpreter digest the bridge reports. + python_sha256: "1".repeat(64), + interpreter_sha256: RUN_INTERPRETER_SHA256.to_owned(), + bridge_sha256: RUN_BRIDGE_SHA256.to_owned(), + wheelhouse_sha256: RUN_WHEELHOUSE_SHA256.to_owned(), + site_packages_sha256: "2".repeat(64), + hashes_sha256: STRICTDOC_REQUIREMENTS_SHA256.to_owned(), + } + } + + #[test] + fn parses_a_real_schema_two_bridge_run() { + let receipt = + parse_bridge_envelope(SCHEMA_TWO_RUN.as_bytes(), "spec.sdoc", RUN_SOURCE_SHA256) + .unwrap(); + assert_eq!(receipt.engine.version, STRICTDOC_VERSION); + assert_eq!(receipt.document.uid, "FIXTURE-DOC"); + assert_eq!(receipt.document.metadata["published_revision"], "REV-1"); + assert_eq!(receipt.nodes.len(), 2); + assert_eq!(receipt.nodes[1].fields["UID"], "REQ-2"); + assert_eq!(receipt.relations.len(), 1); + assert_eq!(receipt.relations[0].relation_type, "derives-from"); + assert_eq!(receipt.relations[0].reference_type, "Parent"); + assert_eq!( + receipt.relations[0].owner.as_deref(), + Some("Bridge fixture") + ); + assert_eq!(receipt.relations[0].revision.as_deref(), Some("REV-1")); + } + + /// The schema-2 engine block echoes the qualified runtime identity it + /// verified. Any drift in it, or an engine block that omits it, stays a + /// runtime mismatch rather than a receipt. + #[test] + fn runtime_receipt_matches_only_the_pinned_qualified_runtime() { + let config = qualified_config(); + assert!(runtime_receipt_matches(SCHEMA_TWO_RUN.as_bytes(), &config)); + + for key in ["python_sha256", "bridge_sha256", "wheelhouse_sha256"] { + let mut value: Value = serde_json::from_str(SCHEMA_TWO_RUN).unwrap(); + value["engine"][key] = Value::String("0".repeat(64)); + assert!( + !runtime_receipt_matches(value.to_string().as_bytes(), &config), + "{key} drift" + ); + let mut value: Value = serde_json::from_str(SCHEMA_TWO_RUN).unwrap(); + value["engine"].as_object_mut().unwrap().remove(key); + assert!( + !runtime_receipt_matches(value.to_string().as_bytes(), &config), + "{key} absent" + ); + } + + // The launcher file digest is never what the bridge reports. + let mut launcher_only = config.clone(); + launcher_only.interpreter_sha256 = launcher_only.python_sha256.clone(); + assert!(!runtime_receipt_matches( + SCHEMA_TWO_RUN.as_bytes(), + &launcher_only + )); + assert!(!runtime_receipt_matches(b"not-json", &config)); + } + + #[test] + fn rejects_malformed_and_unqualified_envelopes() { + let source = b"[DOCUMENT]\n"; + let valid = envelope("spec.sdoc", source); + let mut cases = vec![("malformed", "not-json".to_owned(), SdocError::MalformedJson)]; + let mut value: Value = serde_json::from_str(&valid).unwrap(); + value.as_object_mut().unwrap().remove("validation"); + cases.push(( + "missing", + value.to_string(), + SdocError::InvalidEnvelope("envelope"), + )); + let mut value: Value = serde_json::from_str(&valid).unwrap(); + value + .as_object_mut() + .unwrap() + .insert("status".to_owned(), Value::from(7)); + cases.push(( + "wrong-type", + value.to_string(), + SdocError::InvalidEnvelope("envelope"), + )); + let mut value: Value = serde_json::from_str(&valid).unwrap(); + value + .as_object_mut() + .unwrap() + .insert("extra".to_owned(), Value::Bool(true)); + cases.push(( + "unknown", + value.to_string(), + SdocError::InvalidEnvelope("envelope"), + )); + let mut value: Value = serde_json::from_str(&valid).unwrap(); + value.as_object_mut().unwrap().insert( + "protocol".to_owned(), + Value::String("wrong.protocol".to_owned()), + ); + cases.push(("protocol", value.to_string(), SdocError::Protocol)); + let mut value: Value = serde_json::from_str(&valid).unwrap(); + value + .as_object_mut() + .unwrap() + .insert("schema_version".to_owned(), Value::String("3".to_owned())); + cases.push(("schema", value.to_string(), SdocError::SchemaVersion)); + let mut value: Value = serde_json::from_str(&valid).unwrap(); + value.as_object_mut().unwrap().remove("mode"); + cases.push(( + "missing-mode", + value.to_string(), + SdocError::InvalidEnvelope("envelope"), + )); + let mut value: Value = serde_json::from_str(&valid).unwrap(); + value + .as_object_mut() + .unwrap() + .insert("mode".to_owned(), Value::String("foreign-reqif".to_owned())); + cases.push(("mode", value.to_string(), SdocError::ModeMismatch)); + let mut value: Value = serde_json::from_str(&valid).unwrap(); + value["engine"]["version"] = Value::String("0.28.0".to_owned()); + cases.push(("engine", value.to_string(), SdocError::EngineMismatch)); + let mut value: Value = serde_json::from_str(&valid).unwrap(); + value["source"]["locator"] = Value::String("../spec.sdoc".to_owned()); + cases.push(("locator", value.to_string(), SdocError::UnsafeLocator)); + let mut value: Value = serde_json::from_str(&valid).unwrap(); + value["source"]["sha256"] = Value::String("0".repeat(64)); + cases.push(( + "digest", + value.to_string(), + SdocError::SourceReceiptMismatch, + )); + let mut value: Value = serde_json::from_str(&valid).unwrap(); + value.as_object_mut().unwrap().remove("engine"); + cases.push(( + "missing-engine", + value.to_string(), + SdocError::InvalidEnvelope("envelope"), + )); + let mut value: Value = serde_json::from_str(&valid).unwrap(); + value["document"].as_object_mut().unwrap().remove("mid"); + cases.push(( + "missing-document-mid", + value.to_string(), + SdocError::InvalidEnvelope("document"), + )); + let mut value: Value = serde_json::from_str(&valid).unwrap(); + value["nodes"][0] + .as_object_mut() + .unwrap() + .insert("extra".to_owned(), Value::Bool(true)); + cases.push(( + "unknown-node-field", + value.to_string(), + SdocError::InvalidEnvelope("node"), + )); + let mut value: Value = serde_json::from_str(&valid).unwrap(); + value["relations"][0]["line_range"]["start"] = Value::String("one".to_owned()); + cases.push(( + "wrong-line-type", + value.to_string(), + SdocError::InvalidEnvelope("relation line range"), + )); + for (name, input, expected) in cases { + assert!( + matches!( + parse_bridge_envelope(input.as_bytes(), "spec.sdoc", &sha256(source)), + Err(actual) if std::mem::discriminant(&actual) == std::mem::discriminant(&expected) + ), + "{name}" + ); + } + assert!(matches!( + validate_locator("C:/not-relative"), + Err(SdocError::UnsafeLocator) + )); + } + + #[test] + fn nonzero_and_source_mutation_fail_closed() { + let root = root(); + let source = b"[DOCUMENT]\nTITLE: Spec\n"; + fs::write(root.join("spec.sdoc"), source).unwrap(); + let nonzero = SdocScanner::new(&root, bridge(&root, "#!/bin/sh\nexit 7\n")).unwrap(); + assert!(matches!( + nonzero.scan(), + Err(SdocError::BridgeExit(Some(7))) + )); + + let typed_failure = SdocScanner::new( + &root, + bridge( + &root, + "#!/bin/sh\nprintf '%s' '{\"error\":{\"code\":\"STRICTDOC_REJECTED\"},\"protocol\":\"alphazede.strictdoc.bridge\",\"schema_version\":\"2\",\"status\":\"parse_error\"}'\nexit 2\n", + ), + ) + .unwrap(); + assert!(matches!( + typed_failure.scan(), + Err(SdocError::BridgeStatus { status, code }) + if status == "parse_error" && code == "STRICTDOC_REJECTED" + )); + + let json = envelope("spec.sdoc", source); + let mutating = format!( + "#!/bin/sh\nprevious=\nfor value in \"$@\"; do\n if [ \"$previous\" = \"--source\" ]; then printf changed > \"$value\"; break; fi\n previous=\"$value\"\ndone\nprintf '%s' '{json}'\n" + ); + let scanner = SdocScanner::new(&root, bridge(&root, &mutating)).unwrap(); + assert!( + matches!(scanner.scan(), Err(SdocError::SourceChanged(path)) if path == "spec.sdoc") + ); + fs::remove_dir_all(root).unwrap(); + } +} diff --git a/docs/README.md b/docs/README.md new file mode 100644 index 0000000..57038c5 --- /dev/null +++ b/docs/README.md @@ -0,0 +1,29 @@ +--- +type: documentation-index +title: BRAN Documentation +okf_status: active +status: stable +tags: + - internal + - bran +freshness: "2026-08-18" +resource: https://github.com/alphazede/bran-dev +public_boundary: private +--- + +# BRAN documentation + +- [Integration guides](./integrations/) document public-compatible setup and + operation. +- [Plans](./plans/) hold internal product and research planning. +- [Build Week research](./submissions/bran-build-week/) contains private + measured evidence and publication drafts. + +The completed OKF, SQZ, workspace-metrics, and enterprise-evaluation plan was +imported from AlphaZedeHQ so future amendments and follow-on plans can be made +from this repository. + +Public documentation may be exported to `alphazede/bran` only through the +deterministic public-export boundary and after an explicit data-spill review. +Internal plans, raw evidence, unpublished proposals, and submission material +stay here unless the owner approves publication. diff --git a/docs/bugs/2026-07-25-hook-fires-on-command-tokens-not-target-paths.md b/docs/bugs/2026-07-25-hook-fires-on-command-tokens-not-target-paths.md new file mode 100644 index 0000000..cb57731 --- /dev/null +++ b/docs/bugs/2026-07-25-hook-fires-on-command-tokens-not-target-paths.md @@ -0,0 +1,84 @@ +--- +type: bug-report +title: BRAN advisory hook fires on command tokens rather than target paths +okf_status: draft +status: draft +tags: + - developer + - internal +freshness: "2026-07-25" +resource: https://github.com/alphazede/bran-dev/blob/main/docs/bugs/2026-07-25-hook-fires-on-command-tokens-not-target-paths.md +public_boundary: private +--- + +# BRAN advisory hook fires on command tokens rather than target paths + +Status: open, needs investigation. Found 2026-07-25 during an unrelated task in +`bearing-dev`. + +## Symptom + +The `PreToolUse:Bash` BRAN advisory fires whenever a command *string* contains +`grep` or `find`, regardless of what the command actually reads. It then names +the session's current working directory as the search target, even when no +argument points anywhere near a BRAN-covered repository. + +## Observed false positives + +All four fired the advisory. None touched a repository. + +| Command | What it actually read | +|---|---| +| `gh auth status 2>&1 \| grep -i "scopes"` | GitHub CLI token scopes | +| `pgrep -a -f "chrome" \| grep -o "user-data-dir=[^ ]*"` | process table | +| `ls ~/.config/google-chrome/*/Extensions/` | a home-directory config path | +| `find "$e" -name manifest.json` inside `~/.config/google-chrome` | Chrome extension manifests | + +Each time the advisory read: + +> A raw grep repository search is about to run in +> `/home/spectre/alphazede/Alphazedehq/bearing-dev`, which has native BRAN +> coverage. + +The shell's cwd was `bearing-dev/docs/plans`, so the hook reported the cwd as +the target. The commands' actual targets were `~/.config`, the process table, +and `gh` output. + +## Hypothesis + +Detection appears to be a token scan of the command string for `grep` / `find`, +with the target inferred from cwd rather than parsed from the command's path +arguments. Things to confirm: + +1. Is the trigger a substring match on the command text? Does `grep` appearing + only in a pipeline stage (never as the repo-reading step) still match? +2. Is the reported target ever derived from the command's actual arguments, or + always from cwd? +3. Should a command whose path arguments all resolve outside any BRAN-covered + root suppress the advisory entirely? +4. Do other tools in the same class (`rg`, `ls`, `cat`, `awk`) trigger it, and + should they? + +## Why this matters + +The advisory is a guard. A guard that fires on process listings and CLI auth +output trains the reader to skim past it, which is precisely when it will be +ignored on the call that genuinely bypasses BRAN. Precision is the whole value. + +## Related + +Same root shape as +[`2026-07-25-query-ranking-favors-path-tokens-over-content.md`](./2026-07-25-query-ranking-favors-path-tokens-over-content.md): +matching on a surface token instead of on what the target actually is. Worth +checking whether both share a matching helper. + +## Reproduction + +From any cwd inside a BRAN-covered repository, run a command that pipes +unrelated output through `grep`: + +```sh +gh auth status 2>&1 | grep -i scopes +``` + +The advisory fires and names the cwd as the search target. diff --git a/docs/bugs/2026-07-25-query-ranking-favors-path-tokens-over-content.md b/docs/bugs/2026-07-25-query-ranking-favors-path-tokens-over-content.md new file mode 100644 index 0000000..fb4f895 --- /dev/null +++ b/docs/bugs/2026-07-25-query-ranking-favors-path-tokens-over-content.md @@ -0,0 +1,108 @@ +--- +type: bug-report +title: BRAN query ranking favors path-token matches over canonical content +okf_status: draft +status: draft +tags: + - developer + - internal +freshness: "2026-07-25" +resource: https://github.com/alphazede/bran-dev/blob/main/docs/bugs/2026-07-25-query-ranking-favors-path-tokens-over-content.md +public_boundary: private +--- + +# Query ranking favors path-token matches over canonical content + +Status: open, needs investigation. Found 2026-07-25 while using `bran query` +for ordinary product-knowledge retrieval in two repositories. + +## Symptom + +`bran query` ranks files whose **path** happens to contain a query token above +the documents that actually answer the question. Content is not what wins. In +both observations below the correct answer lived in a `README.md` that the +query either ranked low or did not select at all. + +This is the core retrieval promise, so it matters more than an ordinary +ranking nit: precedence is what BRAN sells over grep. See the product +[README](../../README.md) for the stated ranking promise. + +## Observation 1 — canonical README never selected + +```sh +bran query /Alphazedehq/bearing-dev \ + "What is Bearing as a product, who is it for, and what problem does it solve?" +``` + +Ranking returned (all eight): + +| Rank | Locator | match_reason | confidence | +|---|---|---|---| +| 1 | `test/bearing-store.test.ts` | `exact:path` | 50 | +| 2 | `src/store/bearing-store.ts` | `exact:path` | 50 | +| 3 | `plugin-skills/bearing/SKILL.md` | `exact:path` | 50 | +| 4 | `.github/workflows/bearing-quality.yml` | `exact:path` | 40 | +| 5 | `.github/workflows/bearing-publish.yml` | `exact:path` | 40 | +| 6 | `.bran/tags.md` | `partial:title` | 50 | +| 7 | `.bran/index.md` | `partial:title` | 50 | +| 8 | `skills/set-bearings/SKILL.md` | `partial:title` | 50 | + +`README.md` does not appear in `selected_locators` at all — yet it answers the +question verbatim in its opening line. A test file outranked it because the +path contains the token `bearing`. + +Note also that `.bran/index.md` and `.bran/tags.md` carry `canonical: 1` and +`active: 3` and still lost to files scoring `exact: 1` with no canonical or +active signal. + +## Observation 2 — semantically unrelated top three + +```sh +bran query /Alphazedehq/bran-dev \ + "Where are bugs, defects, and known issues recorded in this repository?" +``` + +| Rank | Locator | match_reason | +|---|---|---| +| 1 | `benches/repository_scan.rs` | `exact:path` | +| 2 | `schemas/repository-scan-snapshot.schema.json` | `exact:path` | +| 3 | `assets/brand/bran-repository-raven.provenance.json` | `exact:path` | + +All three matched on the token `repository` in the path. None relates to bugs, +defects, or issues. The correct answer — that no bug-tracking location exists +in this repository — was not derivable from the ranking; it took raw discovery +to establish. + +## Hypothesis + +Scoring appears to be dominated by the `exact` component, which is computed +against path and title tokens rather than document content. An `exact: 1` +path-token hit outranks a document carrying `canonical: 1` and `active: 3` +that only scores `partial: title`. Effects to confirm: + +1. Does any scoring input read document body content, or only path and title? +2. What are the relative weights of `exact`, `partial`, `active`, `canonical`, + `public_safe`? Can a canonical active document ever beat a path-token match? +3. Are common structural tokens (`repository`, `store`, `test`, `index`) worth + suppressing as ranking signal, or down-weighted by document role? +4. Should `README.md` and other role-bearing documents carry an intrinsic + floor so they are always at least *selected*? + +## Reproduction + +Both queries above reproduce against the pinned runtime: + +``` +version: bran 0.1.0 +source_commit: 99cd22e07c075dba2f24cc7ef6349fcd60edc1eb +sha256: 71f282da26d3c9a3601ed9ddedd6489b02c9f76b54e7e266ae8ba7e3f73f533d +``` + +Binary verified against `tools/bran/runtime/bran-release-pin.json` before both +runs. `bran check bran-strict` was `ok` with no failures or +warnings at the time of observation. + +## Not in scope of this report + +Context reduction worked as advertised in both runs (~1.9 MB and ~2.5 MB of +candidate bytes avoided). The defect is ordering and selection, not volume. diff --git a/docs/integrations/proposals/enterprise-document-evidence-envelope.md b/docs/integrations/proposals/enterprise-document-evidence-envelope.md new file mode 100644 index 0000000..f046f76 --- /dev/null +++ b/docs/integrations/proposals/enterprise-document-evidence-envelope.md @@ -0,0 +1,198 @@ +--- +type: design-contract +proposal_id: BRAN-ENTERPRISE-DOCUMENT-EVIDENCE +kind: evidence-envelope-v1 +title: "Enterprise Document Evidence Envelope" +okf_status: draft +status: draft +tags: + - internal + - bran +freshness: "2026-08-18" +resource: https://github.com/alphazede/bran-dev/issues/5 +public_boundary: private +--- + +# Enterprise Document Evidence Envelope + +V1 design contract for [GitHub issue #5](https://github.com/alphazede/bran-dev/issues/5). +Google Document AI or another owner-approved managed parser owns native +DOCX, XLSX, PPTX, PDF, OCR, and layout extraction. BRAN owns only the +deterministic evidence envelope, fidelity and attestation receipts, policy +checks, and packet admission. BRAN stays offline and dependency-free by +default. This contract does not add a parser, archive, provider adapter, or +live integration. + +## Product boundary + +Managed tooling is responsible for reading the original file, extracting +text and structure, and reporting parser-specific limits. BRAN is +responsible for: + +- preserving original media type, claimed byte length, and SHA-256 +- recording parser identity, processor, version, and whether attestation is + available +- recording a native locator plus exact revision state when attested +- assigning deterministic evidence and anchor identities +- hashing normalized content and recording content-addressed assets +- recording per-feature fidelity, truncation, malformed-input, and + unavailable-evidence receipts +- applying DLP, classification, and public-boundary outcomes +- admitting only validated envelopes into queries and bounded packets + +An unavailable provider claim stays unavailable. BRAN does not invent +revision, permission, fidelity, or completeness evidence. + +## Canonical JSON + +The envelope is canonical JSON. There is no custom archive or container. + +Canonical bytes are UTF-8 +`json.dumps(value, sort_keys=True, separators=(",", ":"), ensure_ascii=False)`. +Equivalent objects with permuted in-memory key order serialize to the same +bytes. + +- `envelope_digest` is SHA-256 of the canonical envelope after omitting + `envelope_digest` +- `normalized.digest` is SHA-256 of the canonical `normalized.content` + object +- `anchors[].text_digest` is SHA-256 of the UTF-8 text bytes +- `original.sha256` and `assets[].sha256` are attested content addresses; + V1 does not recompute them from absent native bytes + +The JSON Schema at +`schemas/enterprise-document-evidence-envelope.schema.json` is the portable +shape. `tools/ci/enterprise_contract_check.py` is the semantic oracle for +digest equality, path safety, family pairing, and cycle freedom. + +## Envelope + +Required fields: + +| Field | Role | +| --- | --- | +| `schema_version` | `1.0.0` | +| `evidence_id` | stable envelope identity | +| `envelope_digest` | canonical envelope digest | +| `original` | media type, byte length, SHA-256 | +| `parser` | identity, processor, version, attestation | +| `source` | native locator and revision state | +| `normalized` | family, text, language, content digest | +| `anchors` | typed locators for one family | +| `assets` | content-addressed references | +| `relations` | derivation and citation edges | +| `fidelity` | per-feature `exact`, `normalized`, `approximated`, or `unsupported` | +| `receipts` | truncation, malformed-input, unavailable | +| `hazards` | active content and external references | +| `policy` | classification, DLP, public-boundary | +| `admission` | packet and query eligibility | + +V1 original media types are `application/pdf`, the three OOXML +word/presentation/sheet types, and no others. Claimed original size is at +most 20,971,520 bytes, matching the Document AI online input cap as a +recorded bound, not a live parser call. Canonical envelope bytes are at +most 1,048,576, matching BRAN packet byte limits. + +## Typed anchors + +The four families do not share semantics. A PDF table is still +fixed-layout; an XLSX cell is still grid. + +| Family | Media | Locator | +| --- | --- | --- | +| `fixed-layout` | PDF | `page`, `block`, integer `bbox` | +| `flow` | DOCX | `section`, `ordinal` | +| `presentation` | PPTX | `slide`, `shape`, `z_index` | +| `grid` | XLSX | `sheet`, `row`, `column` | + +`normalized.content.family` and every anchor family must match the original +media type. Mixed-family envelopes are unsupported evidence. Coordinates +are integers so canonical JSON has no float drift. + +Required fidelity features also differ: + +- fixed-layout: `text`, `reading_order`, `bounding_boxes`, `tables`, + `figures`, `ocr`, `javascript` +- flow: `text`, `paragraphs`, `headings`, `lists`, `tables`, + `headers_footers`, `macros` +- presentation: `text`, `slides`, `shapes`, `speaker_notes`, `z_order`, + `macros`, `animations` +- grid: `text`, `sheets`, `cells`, `formulas`, `charts`, `macros` + +`macros`, `formulas`, `javascript`, `animations`, `embedded_objects`, +`external_relationships`, and `round_trip` must never be `exact`. +Unsupported features are listed in `receipts.unavailable.features`. + +## Security and receipts + +The contract never executes macros, formulas, scripts, embedded objects, or +external relationships, and never fetches a relationship or contacts a +provider. + +- `source.revision.state=unavailable` forces `value=null` and + `receipts.unavailable.revision=true` +- `parser.attestation=unavailable` forces + `receipts.unavailable.parser_attestation=true` +- active content or a positive external-reference count is rejected before + admission +- asset paths are repository-relative POSIX paths with no `.`, `..`, + absolute root, or backslash +- digest mismatch, malformed structure, cycles, and claimed original size + above the bound are rejected +- credentials, OAuth tokens, signed URLs, cookies, and raw authentication + state are not envelope fields + +## Policy and packet admission + +Policy outcomes reuse BRAN vocabulary. Classification values are `public`, +`public-compatible`, `private`, and `internal`. DLP status is +`not-evaluated`, `passed`, or `findings`. Public-boundary outcomes are +`admit-export`, `reject-export`, or `unavailable`. `admit-export` is +allowed only when classification is `public`. Internal evidence may still +enter an internal packet. + +Validated anchors do not become graph nodes automatically. After the +contract admits an envelope: + +1. Each admitted anchor may be supplied to `PacketAssembler` as + `EvidenceContent`. +2. `id` is the anchor id, which already matches the packet `NodeId` + pattern `^[A-Za-z0-9./:_-]+$`. +3. `content` is the bounded anchor text. +4. Typed locator facts become `PreservationAnchor` values (`id` ≤ 64 bytes, + `[A-Za-z0-9._-]+`; `value` ≤ 512 bytes). +5. `priority`, `authority`, and `freshness` come from the compiled view or + caller. The envelope does not invent ranking. +6. Existing item, byte, and runtime-token bounds still apply. Required + evidence that does not fit remains a packet error; other items may be + omitted and recorded on the packet receipt. +7. Query ranking may consume the same admitted evidence as external + content. This contract does not add scanner ingestion or new + `EvidenceClass` values. + +`admission.status=admitted` is necessary and not sufficient. DLP findings +force `rejected` / `ineligible`. Rejected envelopes never become packet +evidence. + +## Fixtures and check + +`fixtures/enterprise-documents/positive/` holds four synthetic normalized +envelopes, one per V1 media type. They are not native binaries and do not +claim round-trip fidelity. `fixtures/enterprise-documents/negative/` holds +named rejections: `digest-mismatch`, `unsafe-asset-path`, `active-content`, +`external-reference`, `malformed-structure`, `oversized`, and +`unsupported-evidence`. + +`python3 tools/ci/enterprise_contract_check.py` uses the Python standard +library only. It validates structural invariants, recomputes canonical +bytes and digests, accepts the four positives, rejects each negative for +its typed reason, and checks that a permuted in-memory object matches the +golden canonical bytes. + +## Non-goals + +No DOCX, XLSX, PPTX, or PDF parser. No Document AI, Office, or layout +engine reimplementation. No conversion platform. No lossless or unsupported +fidelity claims. No provider SDK, credentials, or live Google dependency. +Issues #6–#10 remain conditional adapter work. Issue #13 remains the +Google attestation profile. diff --git a/docs/integrations/proposals/google-enterprise-attestation-profile.md b/docs/integrations/proposals/google-enterprise-attestation-profile.md new file mode 100644 index 0000000..8645e19 --- /dev/null +++ b/docs/integrations/proposals/google-enterprise-attestation-profile.md @@ -0,0 +1,342 @@ +--- +type: design-contract +proposal_id: BRAN-GOOGLE-ENTERPRISE-ATTESTATION +kind: google-attestation-profile-v1 +title: "Google Enterprise Attestation Profile" +okf_status: draft +status: draft +tags: + - internal + - bran +freshness: "2026-08-18" +resource: https://github.com/alphazede/bran-dev/issues/13 +public_boundary: private +--- + +# Google Enterprise Attestation Profile + +V1 design contract for [GitHub issue #13](https://github.com/alphazede/bran-dev/issues/13). +Gemini Enterprise and Agent Search own connectors and enterprise search. +Document AI owns native PDF, DOCX, PPTX, XLSX, OCR, and layout extraction. +Knowledge Catalog owns BigQuery metadata, governance, and lineage. BRAN owns +only deterministic attestation, provenance, replay, DLP, public-boundary, and +packet admission. This contract does not add a connector, parser, catalog, +provider adapter, or live Google dependency. A bounded offline CLI can +replay a saved processor create/get response and a saved process response +into issue #5 and #13 artifacts; it does not authenticate or call Google. + +Issue #5 remains the canonical enterprise-document evidence envelope. Document +AI output in this profile references that envelope and reuses its canonical +JSON and digest rules. Direct Cloud Storage, Drive, BigQuery, or repository +adapters stay out of V1. + +## Product boundary + +Managed Google products are named capabilities, not reimplemented adapters. + +| Product | Owns | BRAN records | +| --- | --- | --- | +| Gemini Enterprise | connectors, engines, retrieval | engine/connector identity, filters, access mode, result digest, revision when attested | +| Agent Search | data stores and enterprise search | data-store identity, selected filters, federated/indexed/imported state | +| Document AI | native parse, OCR, layout, chunks | processor identity, location, #5 envelope digest, page/item limits | +| Knowledge Catalog | BigQuery metadata and lineage | entry identity, asset type, metadata revision, lineage references | +| Existing BRAN Git/OKF | repository and bundle evidence | unchanged Git/OKF path; no Google call | + +Google-managed products own connectivity, search, parsing, catalog metadata, +IAM, and end-user access enforcement. BRAN owns offline capability +declarations, owner-approved source and tenant allowlists, opaque account +references, source/revision/generation/entry evidence, normalized output +digests, checkpoint receipts, deterministic replay fixtures, DLP, +classification, public-boundary, byte-budget, and packet admission. + +An unavailable provider claim stays unavailable. BRAN does not invent +revision, permission, fidelity, completeness, cost, or perimeter evidence. + +## Capability states + +Requested, effective, and attested capability are recorded separately. + +| Product | Allowed attested states | +| --- | --- | +| `gemini-enterprise` | `federated`, `indexed`, `imported`, `unavailable` | +| `agent-search` | `federated`, `indexed`, `imported`, `unavailable` | +| `document-ai` | `parsed`, `unavailable` | +| `knowledge-catalog` | `metadata-only`, `unavailable` | +| `bran-git`, `bran-okf` | `git-okf`, `unavailable` | + +`federated`, `indexed`, and `imported` are different search states. Indexed +or imported results require attested source revision; otherwise the typed +failure is `history-incomplete`. Federated search may record +`revision.state=unavailable` without claiming history completeness. Catalog +metadata and lineage are never an authorization proof. +`permission.authorization_proof` is always false in V1. + +The default local profile performs no provider or network call. +`runtime.network=disabled` forces attested and effective `unavailable` and +the typed failure `network-disabled` for Google-managed products. Synthetic +positives use `runtime.network=not-invoked`: they are recorded outputs, not +live calls. + +Existing Git and OKF snapshots remain the repository/bundle path. They do +not require a Google product. `bran-git` and `bran-okf` may stay attested +when the network is disabled. + +## Canonical JSON + +The attestation is canonical JSON. There is no provider SDK and no custom +archive. + +Canonical bytes reuse the issue #5 rule: UTF-8 +`json.dumps(value, sort_keys=True, separators=(",", ":"), ensure_ascii=False)`. +Equivalent objects with permuted in-memory key order serialize to the same +bytes. `tools/ci/google_attestation_contract_check.py` imports those helpers +from `tools/ci/enterprise_contract_check.py` and does not fork +canonicalization. + +- `attestation_digest` is SHA-256 of the canonical attestation after omitting + `attestation_digest` +- `source.filter_digest` is SHA-256 of the canonical `source.filters` object +- `source.configured_digest` is SHA-256 of the canonical tenant, project, + account reference, locator, and filters +- Document AI `output.digest` is the issue #5 `envelope_digest` of the + referenced envelope, recomputed with the integrated #5 oracle +- Search, catalog, and `git-okf` `output.digest` is SHA-256 of canonical + `output.normalized` +- Current checkpoints with an attested revision hash locator, revision + value, and output digest +- Same attested provider output plus BRAN policy produces the same + canonical bytes and digest + +The JSON Schema at `schemas/google-source-attestation.schema.json` is the +portable shape. `x-product-capabilities` is the capability table. The +semantic oracle binds digest equality, #5 envelope linkage, product/state +pairing, and typed fail-closed outcomes. + +## Attestation + +Required fields: + +| Field | Role | +| --- | --- | +| `schema_version` | `1.0.0` | +| `attestation_id` | stable attestation identity | +| `attestation_digest` | canonical attestation digest | +| `profile` | `bran-google-enterprise-v1` / `1.0.0` | +| `product` | named managed product, identity, component, version | +| `capability` | requested, effective, and attested states | +| `tenancy` | tenant, project, location, opaque `acct:opaque:…` reference, perimeter | +| `source` | native locator, filters, configured/filter digests, revision | +| `permission` | `attested`, `partial`, or `unavailable`; never an authorization proof | +| `output` | kind, digest, optional #5 envelope path, normalized result identity | +| `checkpoint` | replay identity, digest, `current` / `stale` / `conflict` / `unavailable` | +| `truncation` | omitted bytes and items | +| `cost` | recorded or unavailable quota evidence | +| `runtime` | `not-invoked` or `disabled`; never an action path | +| `policy` | classification, DLP, public-boundary | +| `failures` | sorted typed failures computed from the fields | +| `admission` | packet and query eligibility | + +Revision kind is product-specific: search uses `revision`, Document AI uses +`generation`, Knowledge Catalog uses `entry`, and `bran-git` / `bran-okf` +use `revision`. `state=unavailable` forces `kind=unavailable` and +`value=null`. Credentials, OAuth tokens, signed URLs, cookies, and raw +authentication state are not attestation fields. + +Every product has an exact locator grammar and required scope fields. The +oracle parses locators as resource identities, not local filesystem paths, +and never treats object names as pathnames. + +| Product | Locator grammar | Required scope | +| --- | --- | --- | +| `gemini-enterprise` | `projects/{project}/locations/{location}/collections/{collection}/engines/{engine}` | project, location | +| `agent-search` | `projects/{project}/locations/{location}/collections/{collection}/dataStores/{data_store}` | project, location | +| `document-ai` | `projects/{project}/locations/{location}/processors/{processor}/processorVersions/{processor_version}` | project, location | +| `knowledge-catalog` | `projects/{project}/locations/{location}/entryGroups/{entry_group}/entries/{entry}` | project, location | +| `bran-git` | `git:repository/{repository}/commit/{snapshot}` or `.../tree/{snapshot}` | repository, commit or tree, exact snapshot | +| `bran-okf` | `okf:bundle/{bundle}/snapshot/{snapshot}` | bundle root, exact source snapshot | + +`bran-git` and `bran-okf` record existing BRAN Git and OKF evidence. They +are not Google connectors and do not require a provider call. +`output.kind` is `git-okf`. An attested `bran-git` or `bran-okf` revision +value must equal the locator snapshot identity. + +Unknown, opaque, malformed, cross-project, cross-location, cross-tenant, or +cross-bundle locator shapes fail closed. They emit `tenant-escape` and +`location-mismatch` when the product-specific grammar cannot supply the +required scope, and they are never query or packet eligible. + +Document AI `output.kind` is `enterprise-document-evidence-envelope`. +`output.envelope_path` must be a repository-relative issue #5 positive +envelope. The oracle loads that envelope, runs the integrated #5 classifier, +and requires `output.digest` to equal the envelope digest. BRAN still does +not parse native DOCX, XLSX, PPTX, or PDF. Search and catalog outputs keep +`search-result` and `catalog-entry`. `bran-git` and `bran-okf` use +`git-okf` with the same normalized result-identity contract. + +## Security and typed failures + +The contract never calls a provider, never follows an action path, and never +executes macros, formulas, scripts, or external relationships. + +Typed failures are a closed vocabulary: + +| Code | Meaning | +| --- | --- | +| `permission-unavailable` | permission is partial or unavailable | +| `history-incomplete` | indexed/imported state lacks attested revision | +| `stale` | checkpoint state is stale | +| `conflict` | checkpoint state is conflict | +| `mixed-revision` | source revision and checkpoint revision disagree | +| `dlp-findings` | DLP status is `findings` | +| `quota-exhausted` | quota evidence is exhausted | +| `location-mismatch` | locator location is missing or is not the recorded location | +| `perimeter-denied` | recorded perimeter is denied | +| `tenant-escape` | locator project, repository, or bundle is missing or is not the recorded scope | +| `secret-reflection` | a field contains a credential or signed-URL marker | +| `unauthorized-action` | a field requests a provider mutation | +| `completeness-overclaim` | authorization proof, or recorded failures do not match computed failures | +| `network-disabled` | default profile denied a Google product because the network is disabled | + +Computed failures must equal the recorded `failures` array. Any non-empty +failure set forces `admission.status=rejected` and packet/query +`ineligible`. Rejected attestations never become packet evidence. + +Account references stay opaque. Locators must match the product grammar and +stay under the recorded project, location, repository, or bundle. Search-only +profiles remain read-only. + +## Policy and packet admission + +Policy outcomes reuse the issue #5 vocabulary. Classification values are +`public`, `public-compatible`, `private`, and `internal`. DLP status is +`not-evaluated`, `passed`, or `findings`. Public-boundary outcomes are +`admit-export`, `reject-export`, or `unavailable`. `admit-export` is +allowed only when classification is `public`. Internal evidence may still +enter an internal packet. + +`admission.status=admitted` is necessary and not sufficient. After the +contract admits an attestation: + +1. Native locator, product identity, permission status, truncation, and + output digest are the derivation path. +2. Document AI anchors enter `PacketAssembler` only through the admitted + issue #5 envelope. +3. Search and catalog `result_ids` may be supplied as `EvidenceContent` + identities that already match `NodeId`. +4. Locator facts become `PreservationAnchor` values under the existing + packet byte limits. +5. `priority`, `authority`, and `freshness` come from the compiled view or + caller. The attestation does not invent ranking. +6. Existing item, byte, and runtime-token bounds still apply. +7. This contract does not add scanner ingestion or new `EvidenceClass` + values. + +## Fixtures and check + +`fixtures/google-attestation/positive/` holds six synthetic attestations: +Gemini Enterprise indexed search, Agent Search federated search, Document AI +wrapping the issue #5 PDF envelope, Knowledge Catalog metadata-only entry +evidence, existing BRAN Git commit evidence, and existing BRAN OKF bundle +evidence. They are not live project output. + +`fixtures/google-attestation/negative/` combines typed failures instead of +creating one file per bullet: incomplete permission plus incomplete +revision plus stale plus truncation; conflict plus mixed revision; DLP +rejection; quota plus location plus perimeter; cross-tenant escape plus +secret reflection plus unauthorized action; completeness overclaim; network +disabled; and unknown opaque locator plus missing scope. + +`python3 tools/ci/google_attestation_contract_check.py` uses the Python +standard library only. It validates structural invariants, recomputes +canonical bytes and digests, accepts the six positives, checks the +Document AI envelope with the issue #5 oracle, rejects each negative for +its typed failures, and checks that a permuted in-memory object matches the +golden canonical bytes. The check also executes +`tools/ci/document_ai_smoke_adapter.py` against synthetic recorded +responses, validates both outputs with the same #5 and #13 classifiers, +requires the recorded #5 envelope to stay packet and query ineligible +because hazard evidence, DLP, and response/input binding are unavailable, +requires the #5 source identity to be the input SHA-256, requires the #13 +record to stay rejected because permission is unavailable, requires +repeated offline replay to be byte-identical, proves an oversized-text +probe reports the same nonzero truncation on #5 and #13, refuses to +overwrite existing destination files, and proves the fail-closed +negatives including an explicit non-PDF MIME mismatch. The check imports +no socket, TLS, or HTTP client and performs no provider call. Every +schema-declared product has an output contract and a locator grammar. +Unrecognized locators never become packet or query eligible. + +## Recorded-response Document AI adapter + +`tools/ci/document_ai_smoke_adapter.py` is an offline stdlib CLI. It +accepts a saved processor create or get JSON, a saved process JSON, the +original PDF, an output directory, an opaque account reference, and a +tenant. It never authenticates, opens a network client, or calls Google. +`runtime.network=not-invoked` means the adapter did not invoke a runtime +network path. + +Current Layout Parser process responses expose +`document.documentLayout.blocks` with recursive `textBlock` and +`tableBlock` content. The adapter consumes that tree only. Legacy +`document.text` / `document.pages` output is not a usable layout. A +bounded live process response may omit `document.mimeType` while still +returning `documentLayout`. Omission is accepted because `--input-pdf` +bytes are independently required to begin `%PDF`. If `mimeType` is +present, it must be `application/pdf`; an explicit non-PDF type is +rejected. The processor create or get response must supply the full +`projects/{project}/locations/{location}/processors/{processor}/processorVersions/{processor_version}` +identity. A smoke that does not persist that response cannot emit an +honest #13 locator. That processor-version locator belongs in +`parser.processor` and the #13 `source.locator`. The #5 `source.locator` +is the supplied original input digest `sha256:{input-sha256}`, not the +parser identity. + +The adapter has no PDF parser, hazard scanner, DLP evaluation, or +cryptographic binding from process response to the supplied input bytes. +It cannot independently prove that the recorded response came from that +PDF, and it cannot prove original-file hazard absence. Hazard fields with +`present=false` mean none observed in the normalized recorded response, +not proof of absence in the original PDF. The deterministic #5 envelope +stays structurally valid and fail-closed: packet and query are ineligible, +with sorted reasons that hazard evidence is unavailable, DLP is not +evaluated, and response/input binding is unavailable. Those reasons do +not mean the checks were performed. Raw adapter output is not packet or +query eligible until separate owner-approved evidence supplies those +checks. This path is offline recorded-response replay, not a live +provider success. + +The #13 truncation receipt is the #5 truncation receipt. +`omitted_item_count` is the envelope `omitted_anchor_count`. If those +exact totals exceed the #13 numeric bounds, the adapter fails closed +instead of clamping or underreporting. + +The adapter fails closed when: + +- full processor identity or the default processor version cannot be derived +- locator, project, and location disagree +- the input is not a PDF +- process `document.mimeType` is present and is not `application/pdf` +- `documentLayout` blocks contain no usable text +- either destination file already exists +- the #5 omitted-byte or omitted-item total cannot be represented exactly on #13 +- an output path would escape the output directory +- required #5 or #13 evidence cannot be truthfully attested + +It does not invent revision, permission, cost, perimeter, hazard-absence, +DLP-pass, or response/input-binding evidence. Requested, effective, and +attested capability stay separate fields. Committed files under +`fixtures/google-attestation/recorded/` are synthetic models of the +observed response shape. They are not a live provider test and contain no +live or private identifiers. + +## Non-goals + +No Gemini Enterprise or Agent Search connector or search engine. No +Document AI parser. No Knowledge Catalog metadata or lineage +reimplementation. No direct GCS, BigQuery, Drive, or repository adapter. +No mirroring of customer estates, arbitrary BigQuery rows, or a general +cloud browser. No provider actions, IAM or sharing changes, or combined +security domains. No live Google integration, billed query, credential, or +SDK. No provider client, connector abstraction, or Cargo/dependency +change. Those remain a separately approved adapter issue after an owner +selects one concrete GCP MVP. diff --git a/docs/integrations/proposals/okf-bundle-scan-scope.md b/docs/integrations/proposals/okf-bundle-scan-scope.md new file mode 100644 index 0000000..bf01dff --- /dev/null +++ b/docs/integrations/proposals/okf-bundle-scan-scope.md @@ -0,0 +1,77 @@ +--- +type: upstream-proposal +proposal_id: UPSTREAM-OKF-BUNDLE-SCOPE +kind: normative-clarification +submission_status: pull-request-open +title: "Upstream OKF Proposal: Explicit Bundle Scan Scope and Traversal Rules" +okf_status: draft +status: draft +tags: + - internal + - developer +freshness: "2026-07-25" +resource: https://github.com/GoogleCloudPlatform/knowledge-catalog/pull/232 +public_boundary: public-compatible +--- + +# Upstream OKF Proposal: Explicit Bundle Scan Scope and Traversal Rules + +## Current status + +The owner approved this contribution and submitted it to Google Cloud's Knowledge +Catalog repository as [pull request #232](https://github.com/GoogleCloudPlatform/knowledge-catalog/pull/232), +"Clarify the OKF bundle conformance boundary." + +- **Upstream specification:** [OKF v0.2](https://github.com/GoogleCloudPlatform/knowledge-catalog/blob/main/okf/SPEC.md) +- **Submitted by:** `1wgrumph` +- **Source fork:** `alphazede/knowledge-catalog` +- **Source branch:** `proposal/okf-bundle-scan-boundary` +- **Source commit:** `a0801c480d473f998718d698c4677b5dc71b8c45` +- **State recorded 2026-07-25:** open; Google CLA and `check-changes` pass; no maintainer review or disposition yet + +The pull request is the source of truth for the wording under review. This file records +the reasoning and status; it does not imply acceptance or merge. + +## What the pull request proposes + +The change adds a narrow bundle-root and conformance-boundary rule to OKF v0.2: + +- Each conformance evaluation establishes one bundle root. +- The conformance corpus contains regular Markdown entries beneath that root, excluding + symbolic-link entries. +- Candidate roots outside the selected root receive separate conformance results. +- Non-Markdown resources may live inside a bundle without becoming OKF documents. +- Links, path-valued fields, and symbolic links do not expand the conformance corpus or + authorize dereferencing their targets. +- The conformance and version-history sections use that same boundary consistently. + +This is intentionally a format-boundary clarification. It does not standardize command +syntax, root auto-discovery, archive extraction, filesystem access, resource limits, link +resolution, execution, or BRAN policy. + +## Why the clarification matters + +OKF v0.2 allows a bundle to be a repository, archive, or subdirectory of a larger +repository, while its conformance section evaluates Markdown files "in the tree." +Without an explicit selected root, two validators can accidentally evaluate different +corpora, merge sibling bundles, or inspect unrelated repository content. + +The submitted rule makes the evaluated document set deterministic without treating +neighboring files as safe or exempt from separate security and data-spill reviews. + +## BRAN evidence and limits + +BRAN's scanner and bundle logic already use an explicit repository root, deterministic +containment, and non-expanding link behavior. That implementation experience motivated +the contribution, but BRAN is not a normative dependency of the proposal. + +The earlier internal draft targeted OKF v0.1 and proposed broader implementation-level +symlink language. OKF v0.2 now supersedes v0.1, and the owner-reviewed pull request above +contains the narrower text actually submitted. No stable BRAN release or public receipt +is asserted as upstream proof. + +## Next step + +Keep the fork and source branch available while the pull request is open. Respond only +to maintainer feedback or requested changes, and continue to describe the change as a +proposal until upstream merges it. diff --git a/docs/integrations/proposals/okf-layered-profile-separation.md b/docs/integrations/proposals/okf-layered-profile-separation.md new file mode 100644 index 0000000..bd1a215 --- /dev/null +++ b/docs/integrations/proposals/okf-layered-profile-separation.md @@ -0,0 +1,74 @@ +--- +type: upstream-proposal +proposal_id: UPSTREAM-OKF-LAYERED-PROFILES +kind: layered-profile-design +submission_status: upstream-discussion-open +title: "Upstream OKF Proposal: Layered Profile Separation for Conformance and Readiness" +okf_status: draft +status: draft +tags: + - internal + - developer +freshness: "2026-07-25" +resource: https://github.com/GoogleCloudPlatform/knowledge-catalog/issues/212#issuecomment-5081662199 +public_boundary: public-compatible +--- + +# Upstream OKF Proposal: Layered Profile Separation for Conformance and Readiness + +## Current status + +The owner approved a short design comment on the existing upstream profile discussion, +[issue #212](https://github.com/GoogleCloudPlatform/knowledge-catalog/issues/212). The +comment was submitted by `1wgrumph` on 2026-07-25: + +> Building on the “compatible superset, not a fork” idea, I think it would help to make +> one thing explicit: OKF conformance and profile warnings should be reported separately. +> +> A bundle might pass OKF v0.2 while `civic-v1` reports a missing field. That warning +> shouldn’t be described as OKF nonconformance. Likewise, passing the profile shouldn’t +> override a real OKF failure. +> +> I’m not suggesting a central registry or standard result format—just a short note in +> §11 that keeps those results separate. Would that be useful? + +The exact record is [issue comment 5081662199](https://github.com/GoogleCloudPlatform/knowledge-catalog/issues/212#issuecomment-5081662199). +There is no maintainer response or follow-up pull request recorded yet. + +## The reporting boundary + +OKF v0.2 §11 defines portable conformance. An authoring or validation tool may also run +a stricter profile, but the two results answer different questions: + +| OKF result | Profile result | Accurate description | +|---|---|---| +| pass | pass | OKF-conformant and profile-clean | +| pass | warning or fail | OKF-conformant with profile diagnostics | +| fail | pass | Not OKF-conformant; the profile result does not repair it | +| fail | warning or fail | Not OKF-conformant and also has profile diagnostics | + +The contribution asks only that tools preserve this distinction in terminology and +diagnostics. It does not ask OKF to define a central profile registry, standard result +envelope, profile identifiers, consumer enforcement, or BRAN-specific metadata. + +## BRAN evidence and limits + +BRAN's `ProfileValidator` reports its portable compatibility result separately from +`bran-strict`, and only the selected profile controls the process exit. The focused test +is: + +```sh +cargo test --manifest-path Cargo.toml -p bran-core profile::tests::p1_profiles +``` + +This is implementation evidence for keeping outcomes separate, not a request to make +BRAN's envelope or `bran-strict` part of OKF. The submitted comment recorded BRAN's +then-current compatibility identifier as `okf-v0.1`. Subsequent repository work +added a selectable `okf-v0.2` profile; `okf-v0.1` remains supported and is not +removed. That later additive profile is not implied by the upstream comment. + +## Next step + +Wait for maintainer feedback on issue #212. If maintainers want conformance wording, +prepare a small §11 change for another owner review before opening a pull request. Until +then, the contribution remains an open design suggestion rather than an accepted rule. diff --git a/docs/plans/2026-07-21-bran-okf-migration/design.md b/docs/plans/2026-07-21-bran-okf-migration/design.md new file mode 100644 index 0000000..d1328aa --- /dev/null +++ b/docs/plans/2026-07-21-bran-okf-migration/design.md @@ -0,0 +1,601 @@ +--- +type: design +name: bran-okf-migration +status: amended +date: 2026-07-21 +applies_to: bran +plan_spec: ./plan-spec.md +lenses_applied: [CDD, SecDD, RDD, ODD] +lenses_skipped: [BizDD, DDD, EDD, GDD, PDD] +--- + +## Synthesis + +BRAN becomes the sole owner of repository-knowledge policy, validation, retrieval, +and bounded repair semantics. A thin compatibility boundary preserves the legacy +`use-okf` skill, hook triggers, `tools/okf/okf` entrypoint, and +`tools/okf/config.yaml` inputs while consumers migrate. Compatibility code may +translate requests and results, but it may not implement validation rules, ranking, +repair authority, or source mutation. + +The design has four layers: + +1. `bran-core` owns the native policy model, deterministic validation, retrieval + precedence, derived-state rebuilding, and repair state machine. +2. `bran-cli` owns versioned command envelopes, typed exits, native policy loading, + and explicit maintenance authorization input. +3. A legacy adapter owns only old command/configuration translation and parity + comparison. It never rewrites legacy configuration. +4. Repository hooks discover the pinned BRAN executable and invoke bounded, + fail-open advisory operations. Explicit CLI validation and CI remain strict. + +The native repository policy is `.bran/policy.yaml`, with an explicit +`schema_version`. It uses BRAN terms and is validated before repository scanning. +The choice reuses BRAN's existing dependency-free YAML value/parser surface, +keeps policy human-reviewable, and avoids claiming the legacy OKF file is the native +contract. Generated JSON schemas and reports remain BRAN-owned derived artifacts. + +The pre-lens test stance remains contract-first and offline: frozen repositories +must prove native validation, legacy parity, source precedence, hook degradation, +and exact repair rollback without providers, network access, or live consumer +mutation. Lens analysis adds threat-boundary, fault-injection, receipt, and +observability assertions. + +## Use Cases and Communication Flows + +### Flow 1 - Native validation + +```text +caller -> bran CLI -> .bran/policy.yaml loader -> repository scanner + -> normalized bundle -> BRAN strict validator -> deterministic envelope + exit +``` + +Text equivalent: an explicit CLI or CI call loads and validates the versioned native +policy before scanning. BRAN normalizes repository evidence, runs strict rules, and +returns ordered diagnostics. Policy, scan, or validation errors remain distinct and +only the selected profile controls the terminal exit. + +### Flow 2 - Legacy adapter during staged migration + +```text +legacy caller -> use-okf/tools/okf adapter -> legacy config reader + -> normalized BRAN policy request -> BRAN core/CLI + -> legacy-shaped result + parity receipt +``` + +Text equivalent: the adapter accepts the old command and configuration without +rewriting either. It translates them into BRAN-native requests, invokes the same +core behavior as native callers, and translates the result shape. Shadow mode records +both outcomes and differences; it never gives the legacy implementation authority +over BRAN behavior. + +### Flow 3 - Advisory hook + +```text +SessionStart | relevant prompt | relevant edit + -> dynamic repository discovery -> trusted pinned BRAN binary + -> bounded advisory query/check -> compact message + -> unavailable/timeout/malformed result => warning or silence, exit 0 +``` + +Text equivalent: the existing three hook triggers remain. The hook resolves the +managed repository and trusted executable, applies its configured timeout, and emits +compact advice. Missing BRAN, timeout, invalid telemetry, or validation findings do +not block the agent and never mutate repository source. + +### Flow 4 - Authorized repair and recovery + +```text +maintain propose (read only) -> immutable proposal + digest +owner-reviewed authority + exact digest -> maintain apply + -> stale/path checks -> staged write -> native revalidation + -> pass: success receipt + -> fail: exact rollback -> restoration receipt + validation failure +``` + +Text equivalent: proposal captures target, replacement, and original bytes without a +write. Apply requires explicit authority and the exact proposal digest. It refuses +stale or unsafe targets, stages the write, revalidates, and reports success only after +validation. Failed validation restores the exact original state and retains an +attributable failure receipt. + +### Flow 5 - Consumer retirement + +```text +consumer inventory -> native policy + BRAN hook/skill migration + -> validation parity + retrieval parity -> active-reference audit + -> per-consumer complete -> all consumers complete -> owner removal approval +``` + +Text equivalent: each consumer moves independently and retains its evidence. A delayed +consumer stays on the adapter without invalidating completed consumers. Global removal +requires all six consumers, parity evidence, absence of active legacy references, and +owner approval. + +## Test Strategy + +### Pre-lens stance + +Use deterministic fixtures and contract tests. Native BRAN behavior must be testable +without hooks or adapters; adapters must be testable against the same frozen corpus; +and repair behavior must retain byte-level evidence across all terminal states. + +### Lens revisions + +- CDD adds schema-version, command-envelope, typed-exit, and adapter contract tests. +- SecDD adds traversal, symlink, stale digest/source, authority, secret redaction, and + public-boundary negative cases. +- RDD adds timeout, unavailable binary, malformed output, partial write, failed + validation, rollback failure, and retry/idempotency cases. +- ODD adds deterministic receipt fields, parity deltas, missing-observability handling, + and first-command diagnostic procedures. + +### Per-slice approach + +| Design area | Primary test layer | Cross-cutting proof | +| --- | --- | --- | +| Native policy and validation | core unit, schema, conformance | deterministic diagnostics and exits | +| CLI maintenance contracts | CLI contract and fault fixtures | authority, digest, rollback receipts | +| Legacy adapter and configuration | characterization and parity | no rewrite; same semantic outcome | +| Hooks and skill | shell fixtures and integration | trigger parity, bounded timeout, exit 0 | +| Consumer migration | repository procedure and audit | preserved per-consumer evidence | + +### Cross-cutting checks + +All cases run offline against disposable fixtures. Tests compare semantic outcomes, +not timestamps or path ordering accidents. Missing optional telemetry is retained as +`unavailable` and cannot change validation success. Public-boundary scans cover plans, +receipts, hook output, fixtures, and release artifacts. + +## CDD + +- **Surfaces touched.** `.bran/policy.yaml`; BRAN validation and maintenance CLI + envelopes; `RepairProposal`, `RepairReceipt`, and `RepairTerminal`; legacy + `tools/okf/okf` commands/config; `use-okf` skill and hook trigger/result behavior. +- **Contracts.** `DES-1`: the native policy begins with `schema_version`, rejects an + unsupported version as a typed usage/configuration error, and models frontmatter, + coverage classes, source links, tags/status, and public boundaries. `DES-2`: CLI + commands return deterministic JSON envelopes and typed exits `0` success, `1` + validation, `2` usage/configuration, and `3` operation/unavailable. `DES-3`: + proposal is read-only; apply accepts the same target/replacement, exact digest, and + non-blank authority; revalidation alone performs no source mutation. `DES-4`: the + legacy adapter translates old inputs and outputs only and records parity differences. +- **Idempotency and ordering.** Validation and retrieval are read-only and repeatable. + Derived-state rebuilds replace only BRAN-owned artifacts deterministically. Applying + an already-consumed proposal encounters stale source rather than repeating a write. + Diagnostics and parity rows sort by repository-relative path, code, then message. +- **Compatibility commitments.** Legacy calls remain accepted per consumer until AC-7 + evidence and owner approval. Unknown legacy fields are preserved or diagnosed, never + silently discarded when they affect behavior. Native policy has no promise to serialize + back to the legacy format. +- **Versioning strategy.** Native policy and structured receipts carry explicit schema + versions. CLI command names and typed exits are stable within the initial native schema. + Adapter compatibility is versioned by its mapping tests and release pin. +- **Interface option input.** Native policy location/serialization requires the global + Interface Option Check. Maintenance authority and hook triggers retain approved shapes. +- **Validation and tests.** Parser/schema tests live in `bran-core`; CLI envelope and exit + tests in `bran-cli`; adapter and hook characterization tests remain beside their + compatibility surfaces until retirement. +- **Generated code provenance.** JSON schemas/reports are generated or checked from the + BRAN-owned model by repository tooling. Generated artifacts never become policy input. +- **Notable omissions.** No network API, service protocol, or provider contract is added. + +## SecDD + +- **Threat model.** A repository author may craft paths, symlinks, metadata, or links to + escape the root or cross public/private boundaries. A stale or malicious caller may + replay a proposal or forge authority text. A compromised compatibility script may try + to bypass native validation. Accidental output may expose private paths or corpus text. +- **Trust boundaries and validation.** `DES-5`: all policy paths become normalized + repository-relative paths and are checked against the canonical root without following + symlink escapes. Legacy configuration is untrusted adapter input and must pass the + native policy validator. Only BRAN core decides validation and repair terminal state. +- **Authn / authz.** Offline read-only commands require no identity. Source apply requires + an explicit invocation authority reason and exact digest; no hook or adapter infers it. + Publication, release, and adapter removal remain owner-authorized operations. +- **Secrets.** No new secret is introduced. Hooks use a checksum-pinned local binary and a + sanitized environment. Policy, receipts, logs, and fixtures must reject or redact auth + state, credentials, host-private paths, and hidden evaluation material. +- **Sensitive data.** Private repository content stays local. Diagnostics contain bounded + repository-relative locators and rule codes, not arbitrary source bodies. +- **Audit trail.** Repair receipts record schema version, digest, target, authority tag, + and lifecycle. Parity records name consumer, BRAN pin, corpus/policy identity, outcome, + and semantic differences. Receipts are evidence, not permission tokens. +- **Abuse cases.** Traversal, absolute paths, NULs, symlink ancestors, stale snapshots, + digest mismatch, blank authority, config ambiguity, secret-like values, and public-link + violations are refused before mutation. +- **Notable omissions.** No remote authentication or cryptographic signer is required for + local migration. The digest is an identity/staleness check, not a security signature. + +## RDD + +- **Failure modes.** `DES-6`: missing/timed-out BRAN affects only the triggering hook and + yields advisory unavailable; malformed policy stops explicit validation before scanning; + stale source/digest stops apply before writing; I/O failure returns operation failure; + failed validation rolls back; rollback failure reports partial-write uncertainty and + preserves recovery artifacts. A consumer parity mismatch delays only that consumer. +- **Timeouts and retry budget.** Hook timeouts remain 12 seconds for SessionStart, 15 for + prompt submit, and 20 for post-edit. Hooks do not retry. Explicit commands rely on their + caller/CI budget. Apply is never blindly retried; callers must propose again after stale + or uncertain outcomes. +- **Degradation behavior.** Hooks fail open and exit success. Explicit validation and CI + fail on native validation errors. Missing metrics or receipts reduce observability but do + not rewrite semantic success. Adapter parity mismatch is recorded and blocks only that + consumer's retirement. +- **Recovery and repair.** Derived state may be rebuilt automatically. Source recovery uses + exact backup bytes retained through revalidation. Partial-write uncertainty stops further + mutation and directs the operator to inspect the receipt/backup before a fresh proposal. +- **Backup and restore.** No repository-wide backup is introduced. The repair coordinator's + same-directory staged backup is the transactional recovery boundary and is deleted only + after successful revalidation. +- **Notable omissions.** No queue, daemon, distributed retry, or background reconciliation. + +## ODD + +- **Logs.** Structured command envelopes and parity/repair receipts are the operational + record. Fields are schema version, command, status, rule/error codes, bounded locators, + pin/policy identity, and lifecycle. Source bodies, secrets, auth state, and host-private + absolute paths are excluded. +- **Metrics.** `DES-7`: per consumer retain validation parity, retrieval parity, legacy + active-reference count, hook unavailable/timeout count, and migration state. Metrics are + bounded by consumer and rule code; repository paths remain evidence fields, not labels. +- **Traces.** No distributed tracing. A proposal digest correlates propose/apply/revalidate; + a parity run ID correlates legacy and BRAN outcomes. +- **Health checks.** `bran --version` plus release-pin verification answers executable + readiness. Native policy parse/validate answers repository readiness. Hook success alone + never claims validation readiness. +- **Dashboards and alerts.** No service dashboard or paging. Migration evidence is a + deterministic report; explicit CI failures surface normally. Hook failures are compact + warnings and aggregated evidence, not pages. +- **Operator first-five-minutes runbook stub.** Verify pin, run native validation directly, + inspect its typed envelope, then run adapter parity for only the affected consumer. +- **Questions answerable from telemetry alone.** Which BRAN build ran? Which policy and + consumer were checked? Did native and legacy semantics differ? Was source mutated? Was a + failed mutation restored? Which consumer still references legacy behavior? Which fields + are unavailable? +- **Notable omissions.** No uptime SLO, telemetry backend, or remote collector. + +## Interface Option Check + +Three repository-policy interfaces were considered: + +| Option | Shape | Compatibility | Main tradeoff | +| --- | --- | --- | --- | +| A | `.bran/policy.yaml`, versioned BRAN schema | legacy adapter maps old YAML read-only | explicit ownership and human review; one migration step | +| B | keep `tools/okf/config.yaml` as native | zero initial path migration | makes legacy names and schema permanent BRAN API | +| C | infer policy from repository contents | fewer files | ambiguous authority, weak reproducibility, unsafe defaults | + +`interface_options: selected - Option A (.bran/policy.yaml)` + +`DES-8`: Option A is selected. `bran-core` owns parsing and normalized policy +semantics; `bran-cli` discovers the file only from an explicit repository root; the +legacy adapter maps `tools/okf/config.yaml` into the same in-memory policy without +writing `.bran/policy.yaml`. Schema version, unknown-field diagnostics, deterministic +serialization fixtures, and migration parity are mandatory. A future format change +requires a new schema version rather than heuristic parsing. + +## OOPDSA Implementation Design + +### Requirements trace + +| Requirement ID | OOPDSA owner | Proof obligation | +| --- | --- | --- | +| AC-1, AC-7 | `LegacyOkfAdapter` and migration inventory | native ownership plus evidence-based retirement | +| AC-2, AC-5 | `RepositoryPolicyLoader`, `ProfileValidator`, query engine | strict policy and deterministic precedence | +| AC-3, AC-4, AC-6 | `RepairCoordinator` | explicit authority, exact digest, revalidate, rollback | +| RISK-1, RISK-5 | `ParityRecorder` | independent consumer state and semantic deltas | +| RISK-2 | hook adapter | trigger parity and fail-open behavior | +| RISK-3 | release/public-boundary procedure | no implicit publication | +| RISK-4 | `RepositoryPolicyLoader` | selected versioned native policy contract | + +### Ownership contract + +| Object / Service | Responsibility | Owns Data? | Key Methods / Entry Points | Collaborators | Boundary / Interface | Test Focus | Must Not Own | +| --- | --- | ---: | --- | --- | --- | --- | --- | +| `RepositoryPolicyLoader` | parse/version/normalize `.bran/policy.yaml` | yes, immutable policy value | `load(root)`, `normalize()` | scanner, validator | filesystem to policy | versions, paths, unknown fields | repository mutation | +| `ProfileValidator` | evaluate compatibility and strict rules | no | `validate(bundle, profile)` | policy, bundle | normalized evidence to diagnostics | deterministic rules/exits | adapter shapes | +| query engine | canonical retrieval and precedence | yes, derived index | existing query/packet entrypoints | scanner, graph | query to ranked evidence | rank stability, precedence | policy migration | +| `RepairCoordinator` | proposal/apply/revalidate/rollback | yes, proposal snapshot and staged backup | `propose`, `apply` | validator | explicit mutation boundary | all terminal states, exact restore | inferred authority | +| `LegacyOkfAdapter` | translate legacy commands/config/results | no | `check`, `doctor`, shadow/parity | BRAN CLI/core | legacy to native | characterization and parity | validation/ranking rules | +| hook adapter | preserve triggers and bounded advisory calls | no | SessionStart, UserPromptSubmit, PostToolUse | pinned CLI | agent hook boundary | timeout, unavailable, exit 0 | source mutation or strict gate | +| `ParityRecorder` | retain per-consumer semantic comparison | yes, derived receipts | `record`, `summarize` | adapter, inventory | evidence ledger | missing fields, deterministic deltas | task success or authority | + +### Pattern decisions + +| Decision ID | Pressure | Candidate Pattern | Chosen Pattern / Plain Code | Why | Simpler Alternative | Tradeoffs | Review Trigger | +| --- | --- | --- | --- | --- | --- | --- | --- | +| CONTRACT-1 | legacy/native shapes differ | Adapter | one thin `LegacyOkfAdapter` | isolates retirement and prevents rule duplication | conditionals in CLI | temporary extra surface | adapter implements semantics | +| CONTRACT-2 | repair has explicit lifecycle | State machine | retain typed `RepairTerminal` transitions | impossible to claim success before revalidation | booleans/errors | more variants | terminal state loses evidence | +| CONTRACT-3 | validators need a policy value | immutable value object | `RepositoryPolicy` parsed once | single owner and deterministic consumers | raw YAML maps | schema migration code | consumers read raw fields | +| CONTRACT-4 | hooks need graceful calls | plain shell boundary | preserve small fail-open script | no daemon/framework needed | shared runtime service | repeated process startup | hook gains mutation/retry | +| CONTRACT-5 | migration evidence is partial | append-only derived receipts | records available fields plus `unavailable` | observability cannot invalidate work | strict ledger schema | consumers handle missing values | receipt becomes eligibility gate | + +### DSA decisions + +| Decision ID | Owner | Operation | Expected Scale | Chosen Structure | Chosen Algorithm | Time | Space | Reason | Simpler Alternative | Edge Cases | +| --- | --- | --- | ---: | --- | --- | --- | --- | --- | --- | --- | +| CONTRACT-6 | `RepositoryPolicy` | membership/classification | repository paths | ordered maps/sets | normalize then lexical traversal | O(n log n) | O(n) | deterministic diagnostics and overlap detection | vectors | duplicate/overlap/excluded roots | +| CONTRACT-7 | query engine | precedence/ranking | repository evidence nodes | existing graph indexes + stable tuples | canonical/status/freshness/authority ordering | existing bounded query contract | existing index budget | preserve proven retrieval behavior | full scan/sort | ties, stale and legacy sources | +| CONTRACT-8 | `ParityRecorder` | semantic diff | six consumers, bounded results | ordered map keyed by semantic identity | normalize, join, compare, lexical emit | O(n log n) | O(n) | ignores formatting/order noise | raw text diff | missing telemetry, duplicate codes | +| CONTRACT-9 | `RepairCoordinator` | stale detection and rollback | one bounded target | byte snapshot plus staged backup | exact compare, staged replace, validate, restore | O(b) | O(b) | exact recovery is more important than cleverness | timestamps | absent file, same-length edits, rollback I/O failure | + +### Invariants and edge cases + +- Native and adapter requests with equivalent policy have the same semantic validation + and retrieval outcomes. +- Only BRAN-owned derived paths may be automatically replaced. +- No apply reaches a write with blank authority, mismatched digest, stale bytes, unsafe + path, or symlink escape. +- Validation failure cannot produce success; successful rollback restores byte identity. +- Hook timeout, missing executable, malformed output, or metric absence always exits zero. +- One consumer mismatch cannot erase another consumer's completed evidence. +- Active legacy references outside historical documents prevent only retirement. + +The implementation must satisfy `CONTRACT-1` through `CONTRACT-9`; the prospective +proof map is owned by `seit.md`. + +## Owner-approved product parity amendment — 2026-07-22 + +`DES-9`: Repository policy is an immutable validated value with two explicit input +sources. The default native command loads `.bran/policy.yaml` from the explicit +repository root. `--policy-stdin` reads the same schema without persistence. The +sources are mutually exclusive, policy validation precedes scanning, stdin is +bounded, and policy content is not echoed into diagnostics or logs. + +`DES-10`: BRAN owns the remaining semantic OKF customer contracts: document coverage +classification and migration-state rules, preserved frontmatter keys, source/link/ +citation integrity, public-boundary allowlists, packet supersession validation, and +body-preservation validation. Existing BRAN graph, metadata, packet, and policy types +are extended rather than duplicating these rules in Python or shell adapters. + +`CONTRACT-10`: `LegacyOkfAdapter` converts legacy YAML into the versioned native +policy schema, sends it through `--policy-stdin`, translates the native envelope back +to the legacy command result, and records parity. Unknown behavior-affecting fields +produce a typed configuration failure. The adapter never writes `.bran/policy.yaml` +and never falls back to a second semantic validator. + +Customer-facing consequences are additive: repository policy remains the recommended +interface, while read-only checkouts, centrally managed CI policy, editors, and +migration tools can supply an equivalent transient policy. Legacy validator build and +self-heal machinery, benchmarking, SQZ evaluation, and issue automation remain outside +the BRAN semantic product boundary. + +This owner-approved amendment refines AC-1, AC-2, AC-5, AC-7, RISK-3, and RISK-4. +The amended implementation must satisfy `CONTRACT-1` through `CONTRACT-10`. + +## Design Amendment — 2026-07-22 — Native quoted-scalar interoperability + +Implementation exposed an interoperability gap at the native-policy boundary: the +legacy adapter can serialize quoted YAML, but BRAN's bounded parser currently strips +delimiters without decoding the quote forms needed to preserve exact values. + +`DES-11`: BRAN's single native policy parser owns a bounded, explicitly documented +quoted-scalar subset. Single-quoted scalars decode doubled apostrophes. Double-quoted +scalars decode only the minimal escapes required for exact adapter transport (`\"` and +`\\`); unsupported escapes, literal CR/LF, control characters, and unmatched delimiters +fail with the existing non-echoing malformed-policy error. Unquoted behavior and policy +semantics remain unchanged. + +`CONTRACT-11`: `LegacyOkfAdapter` selects a lossless representation from that native +subset, never silently coerces a behavior-affecting value, and returns static field/index +diagnostics that cannot expose raw policy values, repository paths, operating-system +errors, or arbitrary child-process output. Equivalent file and stdin policies parse to +the same immutable `RepositoryPolicy` value. + +This amendment changes serialization interoperability and error sanitization only. It +does not change validation rules, authority, mutation scope, the default +`.bran/policy.yaml` interface, compatibility-retirement criteria, or publication scope. +The Interface Option Check remains unchanged because both policy sources still converge +on the same parser. OOPDSA ownership remains `RepositoryPolicy` plus the thin +`LegacyOkfAdapter`; the parser uses a bounded linear state machine with O(n) time and +O(n) output for each quoted scalar. + +## Design Amendment — 2026-07-22 — Oversized binary scan isolation + +Full-config adapter proof exposed a pre-profile failure on an unrelated 1.9 MiB image. +Legacy OKF treats non-text assets as outside repository-knowledge validation, while BRAN +currently applies its text-source byte limit before it can classify an oversized binary +as unsupported input. + +`DES-12`: When a regular file advertises a size above the configured per-file text limit, +the scanner reads only a fixed bounded prefix before deciding. A prefix containing NUL or +invalid UTF-8 is recorded as `UnsupportedInput` and the file is not buffered, parsed, or +charged to accepted-source byte totals. A valid UTF-8 prefix remains subject to the +existing hard size failure. The same rule applies to full and incremental scans, retains +symlink/root-escape checks, and never guesses that oversized text is safe. + +`CONTRACT-12`: Oversized binary isolation is a scanner input-classification rule, not a +policy exclusion or adapter exception. The probe is constant-space and bounded O(1) by a +fixed byte ceiling; accepted text retains existing limits and identity semantics. This +restores profile evaluation for repositories containing unrelated binary assets without +weakening protection against oversized textual knowledge inputs. + +## Design Amendment — 2026-07-22 — Check-time knowledge-candidate alignment + +Full-config adapter proof next exposed an oversized generated `review.html`. BRAN's +general-purpose repository scanner correctly supports source and other text inputs, but +the `check` pipeline later discards every entry except the native Markdown knowledge +formats. Applying accepted-source limits before that existing admissibility decision lets +non-knowledge generated text block profile evaluation. + +`DES-13`: The native `check` pipeline supplies the scanner a deterministic knowledge- +candidate predicate equal to the predicate used to derive its validation bundle. Paths +that cannot enter that bundle are not opened, parsed, or charged to check-time accepted- +source totals. The general-purpose scanner remains unchanged by default so other BRAN +features can scan source and text files. Full and incremental filtered scans use the same +predicate, and containment, symlink, file-count, and byte-limit checks remain mandatory +for every admitted candidate. + +`CONTRACT-13`: Knowledge-candidate selection is a BRAN-native check contract, not an +adapter rule or configurable extension allow/deny facility. One shared predicate owns the +currently supported Markdown path forms and is reused by scanning and bundle derivation. +An oversized admitted Markdown document still fails closed; a generated non-candidate +file cannot prevent profile selection. This removes duplicate downstream filtering and +generalizes to every customer without changing policy, repository content, or limits. + +## Authorization-gated upstream OKF contribution candidates + +Implementation produced two reusable format-level lessons that are suitable for a +separately authorized issue or pull request against the upstream Open Knowledge Format +specification. They remain proposals, not migration deliverables: + +- `UPSTREAM-1 — bundle scan scope`: clarify that non-OKF files may coexist beside a + bundle, do not participate in OKF conformance, and should not be opened merely to + validate the bundle unless explicitly referenced. This prevents unrelated binary or + generated text from blocking conformance while leaving implementation resource limits + outside the format contract. +- `UPSTREAM-2 — layered profile separation`: permit implementations to expose stricter + organizational readiness profiles only when their results are reported separately from + OKF conformance. An implementation-specific failure must not be characterized as OKF + nonconformance when the portable v0.1 floor passes. + +BRAN keeps `okf-v0.1` as the portable interoperability outcome and `bran-strict` as the +additive repository-policy outcome. Both are computed independently and only the selected +profile controls the command exit. Before BRAN claims complete OKF v0.1 certification, a +separate bounded follow-up must close the known reserved-file coverage gap: the current +compatibility profile validates concept frontmatter and `type` but does not yet validate +the upstream `index.md` and `log.md` structural requirements. + +No upstream issue, pull request, comment, push, or publication is authorized by this +plan. The Conductor must first present the exact proposed upstream text, target, and +scope, then obtain explicit owner authorization for that external write. + +### Closeout update — 2026-07-25 + +The paragraphs above preserve the state and authorization boundary at plan approval. +Subsequent owner-authorized work changed that state: + +- The reserved-file coverage gap is closed. `ProfileValidator` now validates the + structural rules for `index.md` and `log.md`, with positive and negative fixtures in + `fixtures/conformance/okf-v0.1-index-*.fixture` and + `fixtures/conformance/okf-v0.1-log-*.fixture` exercised by + `profile::tests::p1_conformance`. +- Upstream OKF v0.2 supersedes v0.1. BRAN's existing `okf-v0.1` profile identifier is + still a product compatibility label; renaming it or claiming full v0.2 coverage + requires a separate versioned migration. +- The bundle-boundary clarification is open as + [GoogleCloudPlatform/knowledge-catalog#232](https://github.com/GoogleCloudPlatform/knowledge-catalog/pull/232). +- The profile-separation suggestion was added to the existing upstream discussion in + [issue #212](https://github.com/GoogleCloudPlatform/knowledge-catalog/issues/212#issuecomment-5081662199). + +Neither upstream contribution is recorded as accepted or merged. The live pull request +and issue discussion are authoritative for their current wording and disposition; the +original contribution briefs below remain historical design context. + +## Design Amendment — 2026-07-23 — Upstream OKF rationale and sequencing + +This amendment expands `UPSTREAM-1` and `UPSTREAM-2` into reviewable contribution +briefs. It does not authorize an external write, add BRAN-specific behavior to OKF, or +change the completed migration acceptance boundary. + +### UPSTREAM-1 — Bundle scan scope + +**Problem.** OKF v0.1 defines a knowledge bundle as a directory tree of Markdown files +and permits the bundle to be a subdirectory of a larger repository. Its conformance +rules apply to non-reserved Markdown files "in the tree," but the specification does not +explicitly say that validators can restrict conformance I/O to the designated bundle +root. Implementations can therefore disagree: one validates only the bundle while +another recursively opens unrelated repository assets, generated reports, databases, or +binaries. + +**Representative layout.** In the following repository, only `docs/okf/` is the +designated bundle: + +```text +customer-repository/ +├── docs/okf/ +│ ├── index.md +│ └── concepts/orders.md +├── application/ +├── screenshots/ +├── build/ +├── database.sqlite +└── generated-report.html +``` + +The application, screenshots, build outputs, database, and generated report do not +participate in OKF conformance and need not be opened merely to validate `docs/okf/`. +Within the designated bundle root, every non-reserved `.md` file still participates +under the existing specification, reserved files retain their structural obligations, +and referenced content remains subject to the relevant link or citation behavior. + +**Recommended normative direction.** Add a narrow clarification to the bundle-structure +or conformance section: + +> Conformance is evaluated within a designated bundle root. Files outside that root do +> not participate. Within the bundle root, reserved and non-reserved Markdown files +> participate as specified; other files may coexist and need not be opened for +> conformance unless explicitly referenced by a participating document. + +**Benefits.** The clarification makes OKF practical in monorepos, prevents unrelated +binary or generated files from changing format outcomes, reduces unnecessary I/O, and +gives independent validators the same corpus boundary. + +**Non-goals and safety boundary.** This proposal does not standardize BRAN's scanner, +knowledge-candidate predicate, byte limits, file-count limits, or security policy. It +does not declare neighboring files safe or exempt them from repository security scans. +OKF conformance validation and whole-repository security analysis remain separate +operations. + +**Recommended contribution vehicle.** Submit a small specification pull request because +this clarifies the existing rule that a bundle may be a subdirectory rather than adding +a new document shape. + +### UPSTREAM-2 — Layered profile separation + +**Problem.** OKF intentionally defines a permissive interoperability floor. Organizations +still need stronger readiness, governance, freshness, source-integrity, and +public-boundary policies. Without profile-reporting guidance, an implementation can +collapse a stricter organizational failure into a generic failure and incorrectly imply +that a portable OKF bundle is nonconformant. + +**Required outcome separation.** A bundle can legitimately produce two independent +results: + +```text +OKF v0.1: PASS +BRAN Strict: FAIL — missing public_boundary +``` + +This means the bundle satisfies the portable format floor but is not ready under one +implementation's organizational policy. `bran-strict` remains a BRAN profile; it is not +proposed as an upstream OKF profile. + +**Recommended normative direction.** After maintainer discussion, add a short rule to +the conformance section: + +> Implementations MAY provide additional validation profiles beyond OKF conformance. +> Such profiles MUST report their outcomes separately. Failure of an +> implementation-specific profile MUST NOT be described as OKF nonconformance when the +> bundle satisfies the selected OKF version. + +**Benefits.** Implementations can add security or operational readiness checks without +fragmenting the portable format. Producers retain exchange compatibility, consumers can +distinguish interoperability from organizational readiness, and vendor-specific policy +cannot silently redefine OKF conformance. + +**Non-goals.** This proposal does not standardize `bran-strict`, require organizations to +offer a strict profile, create a central profile registry, or add BRAN policy fields to +OKF. Profile identifiers, policy contents, and enforcement mechanisms remain +implementation-owned. + +**Recommended contribution vehicle.** Open a design issue first because profile +separation adds normative reporting guidance. Draft a small conformance-section pull +request only after upstream maintainers agree with the distinction. + +### Recommended timing + +Draft both contributions now, but approach upstream after BRAN is publicly inspectable. +Before publication, close BRAN's reserved `index.md` and `log.md` validation gap and +describe the current `okf-v0.1` result only as the OKF v0.1 concept-document +interoperability floor. Then: + +1. publish a stable BRAN release with accurate conformance claims and reproducible tests; +2. submit `UPSTREAM-1` as a narrow specification clarification; +3. open `UPSTREAM-2` as a design issue; +4. submit profile-separation wording only after maintainer agreement. + +A public implementation gives maintainers inspectable evidence, while separating the +two contributions keeps discussion, review, and disposition independent. Every external +issue, pull request, comment, branch push, or publication still requires the owner's +explicit approval of the exact text, repository, and destination. diff --git a/docs/plans/2026-07-21-bran-okf-migration/implementation.md b/docs/plans/2026-07-21-bran-okf-migration/implementation.md new file mode 100644 index 0000000..8b92126 --- /dev/null +++ b/docs/plans/2026-07-21-bran-okf-migration/implementation.md @@ -0,0 +1,341 @@ +--- +type: implementation +name: bran-okf-migration +status: draft +date: 2026-07-21 +plan_spec: ./plan-spec.md +design: ./design.md +seit: ./seit.md +--- + +# Implementation - BRAN OKF Migration + +This is a pipeline plan. Waves are sequential because later compatibility work +consumes the native BRAN policy, validation, repair, and receipt contracts. All +slices use the existing Pi route for `deepseek-v4-pro`. Publication, release, +consumer-repository mutation, and legacy removal are outside this execution authority. + +The integrated closeout runs `CMD-FAST` once after all code-bearing slices and uses +the repository's native read-only review on the integrated diff. `CMD-FAST` remains a +cross-cutting repository gate rather than a slice-owned semantic proof. + +## Wave 1 - Native BRAN ownership + +Wave 1 establishes the native policy and deterministic core behavior. Its slices are +sequential because they share the core module registry and normalized policy contract. + +### Slice 1.1 — Native repository policy + +**Goal.** Add the versioned BRAN repository-policy model, loader, schema, and frozen fixtures. + +**Requirement IDs.** AC-2, RISK-4 + +**Design IDs.** DES-1, DES-8, CONTRACT-3 + +**SEIT proof rows.** SEIT-2, SEIT-12 + +**Type.** /tdd + +**Design lenses.** CDD, SecDD + +**Implementation role.** Rust policy and schema maintainer + +**Agent model route.** Pi (deepseek-v4-pro) + +**Agent reasoning level.** high + +**Ponytail mode.** full + +**Review path.** Focused tests followed by the BRAN native read-only review on the integrated diff. + +### 1.1 execution manifest + +**Write set.** Only `crates/bran-core/src/policy.rs`, `crates/bran-core/src/lib.rs`, `schemas/bran-repository-policy.schema.json`, `fixtures/policy/valid-v1.yaml`, `fixtures/policy/invalid-version.yaml`, and `fixtures/policy/unsafe-path.yaml`. + +**Command IDs.** CMD-POLICY + +**Stop condition.** Stop on a schema decision that contradicts DES-8 or requires consumer-source mutation. + +**Human decision.** None; ask before changing the selected policy path or serialization. + +### Slice 1.2 — Strict validation and retrieval parity + +**Goal.** Make native policy drive strict validation, preserve deterministic source precedence, +reject active packet references to superseded prompts, and verify migration body preservation. + +**Requirement IDs.** AC-2, AC-5 + +**Design IDs.** DES-2, DES-4, DES-10, CONTRACT-7 + +**SEIT proof rows.** SEIT-3, SEIT-6, SEIT-17 + +**Type.** /tdd + +**Design lenses.** CDD, SecDD, RDD + +**Implementation role.** Rust validation and retrieval maintainer + +**Agent model route.** Pi (deepseek-v4-pro) + +**Agent reasoning level.** high + +**Ponytail mode.** full + +**Review path.** Focused tests followed by the BRAN native read-only review on the integrated diff. + +### 1.2 execution manifest + +**Write set.** Only `crates/bran-core/src/profile.rs`, `crates/bran-core/src/graph/query.rs`, +`crates/bran-core/src/packet/mod.rs`, `crates/bran-core/src/migration.rs`, +`crates/bran-core/src/lib.rs`, and `fixtures/conformance/bran-policy-parity.fixture`. + +**Command IDs.** CMD-PROFILE, CMD-QUERY, CMD-PACKET, CMD-MIGRATION, PROC-PARITY + +**Stop condition.** Stop if compatibility requires duplicating native rules in an adapter or changing established retrieval precedence. + +**Human decision.** None; ask before weakening a public/private or source-precedence rule. + +### Slice 1.3 — Derived-state self-healing + +**Goal.** Rebuild only BRAN-owned derived artifacts while refusing automatic source or policy repair. + +**Requirement IDs.** AC-6 + +**Design IDs.** DES-3, DES-5, CONTRACT-9 + +**SEIT proof rows.** SEIT-7 + +**Type.** /tdd + +**Design lenses.** SecDD, RDD + +**Implementation role.** Rust maintenance-state maintainer + +**Agent model route.** Pi (deepseek-v4-pro) + +**Agent reasoning level.** high + +**Ponytail mode.** full + +**Review path.** Focused tests followed by the BRAN native read-only review on the integrated diff. + +### 1.3 execution manifest + +**Write set.** Only `crates/bran-core/src/derived_state.rs`, `crates/bran-core/src/lib.rs`, and `fixtures/derived-state/rebuild-v1.json`. + +**Command IDs.** CMD-DERIVED, CMD-REPAIR + +**Stop condition.** Stop if a proposed automatic action targets source, metadata, classification, configuration, or source links. + +**Human decision.** None; explicit authority is required for any non-derived repair proposal. + +## Wave 2 - Authorized repair and CLI contracts + +Wave 2 consumes the native validator from Wave 1 and closes the source-mutation +boundary before any compatibility surface can invoke maintenance behavior. + +### Slice 2.1 — Repair and maintenance lifecycle + +**Goal.** Complete production-safe proposal, authority, digest, staged apply, revalidation, +rollback, receipt, typed-exit behavior, and bounded native policy input from stdin. + +**Requirement IDs.** AC-3, AC-4, AC-6 + +**Design IDs.** DES-3, DES-5, DES-6, DES-9, CONTRACT-2, CONTRACT-3, CONTRACT-9 + +**SEIT proof rows.** SEIT-4, SEIT-5, SEIT-7, SEIT-14, SEIT-16 + +**Type.** /tdd + +**Design lenses.** CDD, SecDD, RDD, ODD + +**Implementation role.** Rust repair and CLI security maintainer + +**Agent model route.** Pi (deepseek-v4-pro) + +**Agent reasoning level.** high + +**Ponytail mode.** full + +**Review path.** Focused fault tests followed by the BRAN native read-only review on the integrated diff. + +### 2.1 execution manifest + +**Write set.** Only `crates/bran-core/src/repair/mod.rs`, `crates/bran-cli/src/main.rs`, and `fixtures/repair/rollback-v1.json`. + +**Command IDs.** CMD-REPAIR, CMD-CLI, CMD-DERIVED, CMD-POLICY, PROC-ROLLBACK + +**Stop condition.** Stop on any false-success state, uncertain rollback without explicit terminal evidence, or inferred mutation authority. + +**Human decision.** None; ask before introducing a new authority source or widening mutation targets. + +## Wave 3 - AlphaZedeHQ staged adoption + +Wave 3 updates the canonical internal skill, shared compatibility tool, and hooks. +These slices are sequential because they share the adapter invocation and pinned binary. +No consumer repository is migrated or rewritten in this wave. + +### Slice 3.1 — BRAN skill and shared compatibility adapter + +**Goal.** Make BRAN the canonical internal knowledge workflow while retaining deprecated OKF entrypoints as translation-only adapters. + +**Requirement IDs.** AC-1, AC-7 + +**Design IDs.** DES-4, DES-7, DES-10, DES-11, DES-12, DES-13, CONTRACT-1, CONTRACT-5, CONTRACT-10, CONTRACT-11, CONTRACT-12, CONTRACT-13 + +**SEIT proof rows.** SEIT-1, SEIT-8, SEIT-17, SEIT-18, SEIT-19, SEIT-20 + +**Type.** /tdd + +**Design lenses.** CDD, RDD, ODD + +**Implementation role.** Rust/Python policy interoperability and agent-skill maintainer + +**Agent model route.** Pi (deepseek-v4-pro) + +**Agent reasoning level.** high + +**Ponytail mode.** full + +**Review path.** AlphaZedeHQ focused tests plus native read-only review of the cross-repository integrated diff. + +### 3.1 execution manifest + +**Write set.** Only `/home/spectre/alphazede/bran/crates/bran-core/src/policy.rs`, `/home/spectre/alphazede/bran/crates/bran-core/src/scan/mod.rs`, `/home/spectre/alphazede/bran/crates/bran-cli/src/main.rs`, `/home/spectre/alphazede/Alphazedehq/skills/use-bran/SKILL.md`, `/home/spectre/alphazede/Alphazedehq/skills/use-okf/SKILL.md`, `/home/spectre/alphazede/Alphazedehq/tools/okf/okf`, `/home/spectre/alphazede/Alphazedehq/tools/okf/bran_runtime.py`, and `/home/spectre/alphazede/Alphazedehq/tools/okf/test_bran_runtime.py`. Keep the bounded BRAN parser/scanner packets and dependent AlphaZedeHQ adapter packet sequential in their respective task worktrees. + +**Command IDs.** CMD-POLICY, CMD-SCAN, CMD-CLI, CMD-ADAPTER, PROC-PARITY, PROC-REFERENCES + +**Stop condition.** Stop if the adapter becomes a semantic rule owner, rewrites legacy configuration, or retires an entrypoint without AC-7 evidence. + +**Human decision.** None; publication and final legacy removal remain owner decisions. + +### Slice 3.2 — BRAN-backed fail-open hooks + +**Goal.** Preserve the existing trigger and timeout behavior through a native BRAN hook with deprecated OKF forwarding compatibility. + +**Requirement IDs.** AC-1, RISK-2 + +**Design IDs.** DES-4, DES-6, CONTRACT-1, CONTRACT-4 + +**SEIT proof rows.** SEIT-1, SEIT-10 + +**Type.** /tdd + +**Design lenses.** CDD, SecDD, RDD, ODD + +**Implementation role.** Shell hook and compatibility maintainer + +**Agent model route.** Pi (deepseek-v4-pro) + +**Agent reasoning level.** high + +**Ponytail mode.** full + +**Review path.** AlphaZedeHQ shell fixtures plus native read-only review of the cross-repository integrated diff. + +### 3.2 execution manifest + +**Write set.** Only `/home/spectre/alphazede/Alphazedehq/.grok/hooks/use-bran.sh`, `/home/spectre/alphazede/Alphazedehq/.grok/hooks/use-bran.json`, `/home/spectre/alphazede/Alphazedehq/.grok/hooks/test-use-bran.sh`, `/home/spectre/alphazede/Alphazedehq/.grok/hooks/use-okf.sh`, `/home/spectre/alphazede/Alphazedehq/.grok/hooks/use-okf.json`, `/home/spectre/alphazede/Alphazedehq/.grok/hooks/test-use-okf.sh`, and `/home/spectre/alphazede/Alphazedehq/.grok/hooks/README.md`. + +**Command IDs.** CMD-HOOK, CMD-ADAPTER + +**Stop condition.** Stop if any hook path blocks agent completion, performs source mutation, retries maintenance, or trusts a target-repository executable. + +**Human decision.** None; strict behavior remains limited to explicit validation and configured CI. + +### Slice 3.3 — Pinned local adoption and boundary check + +**Goal.** Verify the exact local BRAN artifact used by the adapter and hooks while preserving the publication boundary. + +**Requirement IDs.** AC-1, AC-7, RISK-3 + +**Design IDs.** DES-5, DES-7 + +**SEIT proof rows.** SEIT-11, SEIT-15 + +**Type.** manual + +**Design lenses.** SecDD, ODD + +**Implementation role.** Local release provenance operator + +**Agent model route.** Pi (deepseek-v4-pro) + +**Agent reasoning level.** high + +**Ponytail mode.** off + +**Review path.** Checksum readback, public-boundary evidence, and native read-only review; no publication review is implied. + +### 3.3 execution manifest + +**Write set.** No committed repository writes. Owner-approved local runtime artifacts under `/home/spectre/alphazede/Alphazedehq/tools/okf/runtime/` may be created by the adoption procedure. On 2026-07-22 the owner explicitly authorized an uncommitted local `tools/okf/runtime/bran-release-pin.json` even though that path is trackable rather than ignored. The exception permits local pin verification only; the pin must remain uncommitted and does not authorize promotion, publication, push, or deployment. + +**Command IDs.** CMD-PUBLIC, PROC-PIN, PROC-PUBLICATION + +**Stop condition.** Stop on checksum mismatch, path aliasing, private-boundary leakage, or any action that would publish or promote an artifact. + +**Human decision.** Explicit owner approval is required before publication, release, promotion, or public install verification. + +## Wave 4 - Consumer evidence and closeout + +Wave 4 is read-only. It measures the six active consumers independently and preserves +incomplete evidence without mutating their source, configuration, hooks, or CI. + +### Slice 4.1 — Six-consumer parity and retirement inventory + +**Goal.** Produce independent parity and active-reference evidence without prematurely removing compatibility. + +**Requirement IDs.** AC-7, RISK-1, RISK-5 + +**Design IDs.** DES-7, CONTRACT-5, CONTRACT-8 + +**SEIT proof rows.** SEIT-8, SEIT-9, SEIT-13 + +**Type.** manual + +**Design lenses.** CDD, RDD, ODD + +**Implementation role.** Repository migration evidence auditor + +**Agent model route.** Pi (deepseek-v4-pro) + +**Agent reasoning level.** high + +**Ponytail mode.** off + +**Review path.** Read-only evidence review followed by the BRAN native integrated-diff review. + +### 4.1 execution manifest + +**Write set.** No writes required; evidence is retained in the execution transcript until a separately authorized evidence path is approved. + +**Command IDs.** PROC-PARITY, PROC-REFERENCES + +**Stop condition.** Stop on corpus mismatch, attempted consumer mutation, unsupported parity claim, or loss of completed per-consumer evidence. + +**Human decision.** Owner approval is required for every consumer migration and for final global adapter removal. + +## Execution closeout + +After Wave 4, run `CMD-FAST` once against the integrated BRAN diff and the focused +AlphaZedeHQ commands referenced by Wave 3. Run one native read-only review across the +integrated BRAN and AlphaZedeHQ diffs. Do not run a provider evaluation, publish BRAN, +promote a release, modify the six consumer repositories, or remove legacy adapters. + +If implementation exposes only missing proof coverage, append a SEIT-only amendment +through `design-driven-build`. If it changes policy, authority, compatibility, +security, or acceptance, stop for the appropriate design amendment. + +### Authorization-gated upstream follow-up + +After local migration closeout, preserve draft candidates `UPSTREAM-1` (bundle scan +scope) and `UPSTREAM-2` (strict-profile separation) from `design.md`. Before any GitHub +issue, pull request, comment, branch push, or other external publication, present the +exact proposed text and destination to the owner and obtain explicit authorization. +Upstream contribution work is not part of this eight-slice execution and cannot delay, +weaken, or reclassify local migration evidence. + +Separately plan and authorize complete reserved `index.md`/`log.md` structural validation +before describing `okf-v0.1` as full upstream conformance certification. Until then, +describe it as the OKF v0.1 concept-document interoperability floor. diff --git a/docs/plans/2026-07-21-bran-okf-migration/plan-spec.md b/docs/plans/2026-07-21-bran-okf-migration/plan-spec.md new file mode 100644 index 0000000..863d8d1 --- /dev/null +++ b/docs/plans/2026-07-21-bran-okf-migration/plan-spec.md @@ -0,0 +1,250 @@ +--- +type: plan-spec +name: bran-okf-migration +status: draft +date: 2026-07-21 +applies_to: bran +parent_baseline: legacy use-okf skill and tools/okf/okf +--- + +## Problem + +Internal repository validation, retrieval, and repair currently flow through legacy +`use-okf` and `tools/okf/okf` in mixed ownership and shared command posture, while +BRAN has an independent parser/validator/repair stack already in-tree. +Owner constraints are now explicit, and migration proceeds under evidence-grounded +staging and coordinated inventory tracking. + +## Goal + +- Migrate to BRAN-core/CLI-owned validation and maintenance behavior while preserving + compatibility-only support for legacy `use-okf` and `tools/okf/okf` adapter + entrypoints until parity is proven. +- Preserve evidence-only/read-only default semantics and stronger-source precedence + outcomes during migration. +- Make self-healing repair authority explicit and bounded BRAN-owned derived + state. + +## Scope + +In scope: + +- Retrieval, validation, and maintenance command/receipt behavior in BRAN core and CLI + surfaces. +- Compatibility posture for legacy command names and per-repository OKF configurations. +- Evidence on proposal/apply/revalidate repair semantics, typed success/failure states, + rollback and receipt attribution, and boundary conditions. +- Compatibility surface in neighboring BRAN consumers is treated as migration target + inventory only (not implementation authorization). +- Retirement evidence for active consumers is in-scope, with repository-by-repository + migration status preserved until all active consumers are eligible for adapter retirement. + +Out of scope: + +- Schema/serialization details for new BRAN-native policy formats not yet finalized. +- Hard-coded legacy-adapter retirement window or fixed cutover date. +- New owner decisions for compatibility removal criteria beyond confirmed parity. + +## Current behavior + +- In `Alphazedehq`, `/home/spectre/alphazede/Alphazedehq/.grok/hooks/use-okf.sh` and + `/home/spectre/alphazede/Alphazedehq/.grok/hooks/use-okf.json` are the current + `use-okf` compatibility surfaces; both are evidence-only and read-only by policy + (`/home/spectre/alphazede/Alphazedehq/.grok/hooks/README.md:24-53`). +- In `Alphazedehq`, `/home/spectre/alphazede/Alphazedehq/tools/okf/okf` exposes legacy + command forms (`check`, `doctor`, `bran-verify-pin`, `bran-shadow`) and uses legacy policy + inputs in its adapter layer. +- BRAN CLI currently exposes `maintain ` and typed exits + (`Validation`, `Operation`, `Usage`, `Success`) in command help (`crates/bran-cli/src/main.rs:74-77,109-117`). +- BRAN repair core currently models explicit `RepairTerminal` states, proposal + digests, unsafe-path checks, and rollback-on-failed-validation behavior + (`crates/bran-core/src/repair/mod.rs:1-17,89-117,189-295`). +- Canonical retrieval indexes in BRAN core include canonical/status/freshness/authority + keys and path/title/tag matching for deterministic source selection + (`crates/bran-core/src/graph/query.rs:1596-1620`). +- Metadata frontmatter handling and parser fallback remain implemented in BRAN core + (`crates/bran-core/src/metadata/mod.rs:248,737`). + +## Target behavior + +- Staged replacement: BRAN becomes canonical internal repository-knowledge and + validation implementation; legacy `use-okf` and `tools/okf/okf` remain compatibility + adapters only until parity is proven. +- Strict repository validation is BRAN-native behavior (including required/allowed + frontmatter validation, metadata/status coverage, source-link integrity, source tag + policy, public/private boundaries, deterministic reports, and typed unavailable/conflict + behavior), with adapters only translating invocation/result shape during migration. +- Self-healing authority is split by ownership: + BRAN may auto-rebuild only BRAN-derived state such as indexes, snapshots, caches, + reports, and generated validator artifacts. +- Repository source, metadata, classifications, configurations, and source links are never + rewritten silently. +- BRAN can propose bounded repair operations, then require explicit authority with a digest, + then revalidate; validator failure restores original bytes and emits a restoration receipt path. + +## Use cases + +### UC-1 Validation parity use case +BRAN-native strict validation handles repository checks and returns deterministic pass/fail +exit plus structured output for repository boundary violations. + +### UC-2 Legacy-compatibility check +Legacy `use-okf` and `tools/okf/okf` commands remain callable as adapters and map into +BRAN-native behavior without changing core outcomes during migration. + +### UC-3 Retrieval use case +Queries continue to rank and select canonical evidence deterministically using canonical, +authority, status, and path/title/tag fields. + +### UC-4 Self-heal proposal use case +`maintain propose` returns digest and target metadata without mutating repository source. + +### UC-5 Apply with explicit authority +`maintain apply` requires a replacement plan and non-empty authority reason, verifies digest +and staleness, performs mutation, and only reports success after revalidation. + +### UC-6 Failure and rollback use case +Validation failure after apply restores the exact prior target state and returns failure receipts +with explicit failure terminal state. + +### UC-7 Boundary safety use case +Repository/classification/source-link checks enforce boundaries, with explicit diagnostics for +unsafe paths, stale source, missing authority marker, and unavailable checks. + +## Components + +- `crates/bran-cli/src/main.rs`: CLI command surface (`maintain`) and envelope + exits. +- `crates/bran-core/src/repair/mod.rs`: proposal/apply/state machine and restoration receipts. +- `crates/bran-core/src/metadata/mod.rs`: metadata parsing and header extraction behavior. +- `crates/bran-core/src/graph/query.rs`: deterministic retrieval path/title/tag/canonical + match behavior. +- `Alphazedehq` compatibility tooling (`/home/spectre/alphazede/Alphazedehq/.grok/hooks/use-okf.sh`, + `/home/spectre/alphazede/Alphazedehq/tools/okf/okf`). + +## Acceptance criteria + +- **AC-1**: Staged replacement keeps BRAN as canonical behavior for repository validation + while legacy compatibility remains explicitly adapter-only until explicit parity sign-off. +- **AC-2**: BRAN strict validation behavior remains behaviorally explicit in core/CLI and + continues to enforce frontmatter parsing, source-link handling, and boundary policy. +- **AC-3**: Repository maintenance flow enforces read-only proposal, explicit authority on apply, + digest matching, and revalidation before success. +- **AC-4**: Validation failures in apply path restore original target content and emit an + attributable failure lifecycle value indicating restoration. +- **AC-5**: Retrieval and compatibility flows preserve stronger-source precedence outcomes and + do not require unverified source-policy claims. +- **AC-6**: No repository rewrite happens without explicit, bounded BRAN-owned authority and + compatible revalidation result. +- **AC-7**: Legacy `use-okf`, `tools/okf/okf`, legacy hooks, and legacy configurations are + retired only after every active consumer has migrated to BRAN-native policy and BRAN-backed hook/skill. + Required evidence remains BRAN-vs-legacy retrieval and validation parity, plus audit that no active code, + skill, hook, or CI reference uses legacy entrypoints/configuration outside explicitly historical documents. + +## Risks and open questions + +- **RISK-1**: [Non-blocking] Active consumers can progress on different schedules; one consumer delay can + delay global adapter removal but does not invalidate completed migration evidence from completed consumers. +- **RISK-2**: [Non-blocking] Hook behavior migration requires careful implementation of fail-open + fallback and compatibility-only semantics, but owner-confirmed posture is now fixed. +- **RISK-3**: [Non-blocking] Publication sequencing is owner-authorized and constrained by public-boundary + review, with no remaining migration-blocking ambiguity. +- **RISK-4**: [Non-blocking] Native schema filename/serialization details remain design concerns and are + intentionally deferred until implementation design review. +- **RISK-5**: [Non-blocking] Compatibility parity evidence cadence will remain a planning and QA scheduling + pressure rather than a hard migration blocker. + +## Owner decisions + +1. Staged replacement. BRAN becomes the canonical internal repository-knowledge and + validation implementation. The legacy `use-okf` skill and `tools/okf/okf` command remain + deprecated compatibility adapters only until consumer parity is proven and owner resolves retirement + criteria. There is no hard same-change cutover. +2. Strict repository validation is native BRAN Core/CLI behavior, not a call through to the legacy + validator. It must preserve required/allowed frontmatter validation, canonical/legacy/excluded/unclassified + coverage, source-link integrity, repository tag/status policy, public/private boundary enforcement, + deterministic reports, and compatible typed exit behavior. The compatibility adapter may translate + old invocations/results during migration. +3. Self-healing authority is split by ownership. BRAN may automatically rebuild only BRAN-owned derived + state such as indexes, snapshots, caches, reports, and generated validator artifacts. Repository source, + metadata, classifications, configuration, and source links are never silently rewritten. BRAN may propose a + bounded repair; apply requires explicit authority and the exact proposal digest, then revalidation. + Validation failure restores the exact original bytes and emits an attributable receipt. + +4. Configuration relationship. BRAN owns a new native repository-policy schema. Existing + `tools/okf/config.yaml` inputs are migration-only and accepted read-only through the + compatibility adapter. They are never automatically rewritten. Repository conversion is deliberate + and occurs only after parity evidence. Exact native filename and serialization remain a design + concern unless owner input is genuinely required. +5. Hook behavior. Preserve the existing use-okf hook logic while replacing its implementation + with BRAN: SessionStart lightweight availability, relevant-keyword UserPromptSubmit, and + relevant-file PostToolUse; dynamic managed-repository discovery; trusted executable resolved from + the hook's physical checkout or owner-approved stable path; bounded timeouts; compact output; + graceful unavailable fallback; always exit success/fail-open; no hook-driven source mutation. + Strict failures remain exclusive to explicit BRAN validation or configured CI. +6. Adoption/publication order. Adopt an exact locally built BRAN artifact first using a checksum pin + and stable local path. Run compatibility/shadow and consumer parity before public publication. A public + download/install is later release-install verification, not a prerequisite for internal adoption. + Publication remains owner-authorized and occurs only after migration parity and public-boundary review. + +7. Legacy retirement is evidence-based, not date-based. There is no arbitrary migration window or adapter + retirement date. Retirement of legacy `use-okf`, `tools/okf/okf`, legacy hooks, and legacy + configurations occurs only when every active consumer repository has deliberately migrated to BRAN-native + policy and BRAN-backed hook/skill. Required evidence includes: + (a) BRAN-vs-legacy validation and retrieval compatibility parity passes; and + (b) confirmed absence of active code, skill, hook, or CI references to legacy entrypoints/configuration + outside explicitly historical documents. A migration problem in one repository can delay only that repository + and final global adapter removal, without invalidating completed migration evidence from other repositories. + Active migration inventory confirmed by focused discovery: Alphazedehq, alphazede-sports, betbot, + developers, hgts, and alphazede-markets. + +## Sequencing + +- Run compatibility inventory and parity evidence collection for retrieval and validation. +- Confirm repair lifecycle and rollback invariants with explicit failure/restore traces. +- Run per-repository BRAN-native migration and retire legacy entrypoints only when owner decision 7 + conditions and evidence are met; unresolved repositories remain on adapter pathways until complete. + +## Evidence consulted + +- `/home/spectre/alphazede/Alphazedehq/.grok/hooks/use-okf.sh:7-20,26-57,81-99,125-187` +- `/home/spectre/alphazede/Alphazedehq/.grok/hooks/use-okf.json:1-38` +- `/home/spectre/alphazede/Alphazedehq/.grok/hooks/README.md:24-53` +- `/home/spectre/alphazede/Alphazedehq/tools/okf/okf:56-85,88-174` +- `/home/spectre/alphazede/Alphazedehq/tools/okf/config.yaml:1` +- `/home/spectre/alphazede/alphazede-sports/tools/okf/config.yaml:1` +- `/home/spectre/alphazede/betbot/tools/okf/config.yaml:1` +- `/home/spectre/alphazede/developers/tools/okf/config.yaml:1` +- `/home/spectre/alphazede/hgts/tools/okf/config.yaml:1` +- `/home/spectre/alphazede/alphazede-markets/tools/okf/config.yaml:1` +- `/home/spectre/alphazede/Alphazedehq/AGENTS.md:106-123` +- `/home/spectre/alphazede/bran/AGENTS.md:32-44` +- `/home/spectre/alphazede/bran/docs/plans/AGENTS.md:1-24` +- `/home/spectre/alphazede/bran/crates/bran-core/src/metadata/mod.rs:248,737` +- `/home/spectre/alphazede/bran/crates/bran-core/src/graph/query.rs:1596,1600,1617-1620` +- `/home/spectre/alphazede/bran/crates/bran-core/src/repair/mod.rs:4,19,123,180-188,189-297` +- `/home/spectre/alphazede/bran/crates/bran-cli/src/main.rs:76,1994,2032,2124,2381` + +## Handoff to design-driven-build + +- **CDD pressure**: preserve staged replacement versus hard cutover, and boundary between proven parity + and completed owner decisions. +- **SecDD pressure**: typed repair failures, authority validation, stale-digest/conflict handling, and + rollback-receipt requirements. +- **RDD pressure**: retrieval precedence and compatibility adapter behavior (`legacy` vs `canonical`), + with parity invariants preserved under owner decision 7 and active-consumer sequencing. +- **ODD pressure**: command surface/API posture and exit-state contracts (`Validation`, `Operation`, + `Usage`, `Success`) across maintenance and adapter boundaries. +- **OOPDSA focus**: ownership boundaries for repair state, adapter layer split, and explicit authority + transitions from proposal to revalidation/receipt. +- **SEIT obligations**: include positive and negative parity cases, legacy compatibility cases, + validation failures, stale-source and stale-digest cases, and rollback assertions with evidence + retention. + +## See also + +- `/home/spectre/alphazede/Alphazedehq/.grok/hooks/use-okf.sh` +- `/home/spectre/alphazede/Alphazedehq/.grok/hooks/use-okf.json` +- `/home/spectre/alphazede/Alphazedehq/tools/okf/okf` +- `/home/spectre/alphazede/bran/crates/bran-cli/src/main.rs` +- `/home/spectre/alphazede/bran/crates/bran-core/src/repair/mod.rs` diff --git a/docs/plans/2026-07-21-bran-okf-migration/review.html b/docs/plans/2026-07-21-bran-okf-migration/review.html new file mode 100644 index 0000000..92e3529 --- /dev/null +++ b/docs/plans/2026-07-21-bran-okf-migration/review.html @@ -0,0 +1,1492 @@ + + + + + +BRAN OKF Migration Design Review + + +
+
DESIGN BASELINE · STAGED REPLACEMENT · PRIVATE
+

BRAN OWNS REPOSITORY KNOWLEDGE

+

A staged migration from internal use-okf and OKF tooling to BRAN-native policy, validation, retrieval, repair, and evidence—without allowing hooks or telemetry to block agent work.

+ +

Design outcome

+
+
One semantic ownerBRAN core owns policy, validation, ranking, and repair.
+
Thin compatibilityLegacy skill, tool, config, and hooks translate only.
+
Bounded self-healAutomatic repair is limited to BRAN-owned derived state.
+
Evidence retirementSix consumers migrate independently before global removal.
+
+ +

Architecture and communication flow

+
+
native caller
.bran/policy.yaml
+
legacy caller
read-only translation
+
BRAN CLI
typed envelope + exits
+
BRAN core
policy · validation · query
+
repair coordinator
authority · digest · rollback
+
receipts
partial telemetry preserved
+

Text equivalent: Native policy and translated legacy input converge at BRAN's CLI/core boundary. BRAN alone decides validation, retrieval, and repair outcomes. Explicit maintenance authority reaches the repair coordinator; hooks remain advisory. Deterministic receipts retain available evidence without becoming permission or eligibility gates.

+ +

Representative use cases

+
+
Native validationLoad a versioned policy, scan once, and emit deterministic diagnostics and typed exits.
+
Legacy parityTranslate old config without rewriting it and compare semantic outcomes on identical evidence.
+
Advisory hookPreserve three triggers, bounded timeouts, compact output, exit zero, and no source mutation.
+
Authorized repairPropose read-only, apply with exact authority and digest, revalidate, then succeed or restore.
+
Consumer retirementRetain independent evidence until all active consumers pass and the owner approves removal.
+
+ +

Authority and failure flow

+
+
read-only proposal
exact digest + authority
path/stale checks
staged write
native revalidation
success receipt OR exact restore
+

Text equivalent: No mutation occurs during proposal. Apply refuses missing authority, mismatched digest, stale bytes, traversal, or symlink escape. A staged write becomes successful only after native validation; failure restores the original bytes and returns an attributable failure lifecycle.

+ +

V&V flow

+
+
policy/schema fixtures
validation/query contracts
repair fault injection
adapter + hook characterization
six-consumer parity
reference + public audit
+

Text equivalent: Deterministic core contracts precede fault-injected repair tests, compatibility characterization, consumer-specific parity, and final active-reference/public-boundary audits. Missing telemetry stays visible but does not change semantic success.

+ +

Interface decision

+
SelectedRejected alternativesReason
.bran/policy.yaml with explicit schema versionmaking tools/okf/config.yaml permanent; implicit repository inferenceNames BRAN as owner, reuses the existing offline YAML model, supports reviewable migration, and avoids heuristic authority.
+

Owner-approved product parity amendment

+
+
native caller
.bran/policy.yaml
+
legacy or CI caller
bounded --policy-stdin
+
one native policy parser
+
BRAN semantic checks
coverage · sources · boundaries · packets
+
typed envelope + parity evidence
+

Text equivalent: Repository policy remains the recommended default. Explicit bounded stdin accepts the identical native schema for read-only CI and legacy translation. Both sources converge before scanning and use one BRAN-owned semantic implementation. Legacy build/self-heal machinery, benchmarks, SQZ evaluation, and issue automation remain outside the product contract.

+

Native quoted-scalar interoperability amendment

+
+
legacy YAML
untrusted values
+
lossless bounded serializer
+
one BRAN policy parser
file or stdin
+
immutable RepositoryPolicy
+
sanitized typed evidence
+

Text equivalent: Legacy values are serialized only when exactly representable by BRAN's bounded quoted-scalar subset. File and stdin inputs converge on the same parser and immutable policy. Malformed quoting, unsupported escapes, controls, and arbitrary child output fail without echoing raw values or paths.

+

Source revisions

+
ArtifactSHA-256
plan-spec.md3f387130702f06eb7b2b469b0a8ee8fc93520a0f28ce8745b9e55e710de84508
design.md6a38b87f609b961f2a23934aafaf57faf71c3e534497c7101a7e368f479f00ed
seit.mdbf87e62d9b55a3d0a391443ac5a5ff436966c616e2b388879917f265e41ef0f9
implementation.md0496673bc7b9489e34c54cc40ba6bbf95ac5399013fd8a7f100d3cfdcb9c4547
+

Canonical four-document bundle SHA-256: e653fa2e3b1db7a65163d380cceea90d754b49d2752baa42fe68ac49b1abe1ea. Regenerated deterministically on 2026-07-23 after the authorization-gated upstream OKF rationale and sequencing amendment. The Markdown artifacts remain authoritative.

+

Final QA

+
Empty by design. Implementation actuals, planned-versus-actual deviations, validation, review, and activation status are populated only after execution.
+

Complete canonical detail

+
plan-spec.md
---
+type: plan-spec
+name: bran-okf-migration
+status: draft
+date: 2026-07-21
+applies_to: bran
+parent_baseline: legacy use-okf skill and tools/okf/okf
+---
+
+## Problem
+
+Internal repository validation, retrieval, and repair currently flow through legacy
+`use-okf` and `tools/okf/okf` in mixed ownership and shared command posture, while
+BRAN has an independent parser/validator/repair stack already in-tree.
+Owner constraints are now explicit, and migration proceeds under evidence-grounded
+staging and coordinated inventory tracking.
+
+## Goal
+
+- Migrate to BRAN-core/CLI-owned validation and maintenance behavior while preserving
+  compatibility-only support for legacy `use-okf` and `tools/okf/okf` adapter
+  entrypoints until parity is proven.
+- Preserve evidence-only/read-only default semantics and stronger-source precedence
+  outcomes during migration.
+- Make self-healing repair authority explicit and bounded BRAN-owned derived
+  state.
+
+## Scope
+
+In scope:
+
+- Retrieval, validation, and maintenance command/receipt behavior in BRAN core and CLI
+  surfaces.
+- Compatibility posture for legacy command names and per-repository OKF configurations.
+- Evidence on proposal/apply/revalidate repair semantics, typed success/failure states,
+  rollback and receipt attribution, and boundary conditions.
+- Compatibility surface in neighboring BRAN consumers is treated as migration target
+  inventory only (not implementation authorization).
+- Retirement evidence for active consumers is in-scope, with repository-by-repository
+  migration status preserved until all active consumers are eligible for adapter retirement.
+
+Out of scope:
+
+- Schema/serialization details for new BRAN-native policy formats not yet finalized.
+- Hard-coded legacy-adapter retirement window or fixed cutover date.
+- New owner decisions for compatibility removal criteria beyond confirmed parity.
+
+## Current behavior
+
+- In `Alphazedehq`, `/home/spectre/alphazede/Alphazedehq/.grok/hooks/use-okf.sh` and
+  `/home/spectre/alphazede/Alphazedehq/.grok/hooks/use-okf.json` are the current
+  `use-okf` compatibility surfaces; both are evidence-only and read-only by policy
+  (`/home/spectre/alphazede/Alphazedehq/.grok/hooks/README.md:24-53`).
+- In `Alphazedehq`, `/home/spectre/alphazede/Alphazedehq/tools/okf/okf` exposes legacy
+  command forms (`check`, `doctor`, `bran-verify-pin`, `bran-shadow`) and uses legacy policy
+  inputs in its adapter layer.
+- BRAN CLI currently exposes `maintain <propose|apply|revalidate>` and typed exits
+  (`Validation`, `Operation`, `Usage`, `Success`) in command help (`crates/bran-cli/src/main.rs:74-77,109-117`).
+- BRAN repair core currently models explicit `RepairTerminal` states, proposal
+  digests, unsafe-path checks, and rollback-on-failed-validation behavior
+  (`crates/bran-core/src/repair/mod.rs:1-17,89-117,189-295`).
+- Canonical retrieval indexes in BRAN core include canonical/status/freshness/authority
+  keys and path/title/tag matching for deterministic source selection
+  (`crates/bran-core/src/graph/query.rs:1596-1620`).
+- Metadata frontmatter handling and parser fallback remain implemented in BRAN core
+  (`crates/bran-core/src/metadata/mod.rs:248,737`).
+
+## Target behavior
+
+- Staged replacement: BRAN becomes canonical internal repository-knowledge and
+  validation implementation; legacy `use-okf` and `tools/okf/okf` remain compatibility
+  adapters only until parity is proven.
+- Strict repository validation is BRAN-native behavior (including required/allowed
+  frontmatter validation, metadata/status coverage, source-link integrity, source tag
+  policy, public/private boundaries, deterministic reports, and typed unavailable/conflict
+  behavior), with adapters only translating invocation/result shape during migration.
+- Self-healing authority is split by ownership:
+  BRAN may auto-rebuild only BRAN-derived state such as indexes, snapshots, caches,
+  reports, and generated validator artifacts.
+- Repository source, metadata, classifications, configurations, and source links are never
+  rewritten silently.
+- BRAN can propose bounded repair operations, then require explicit authority with a digest,
+  then revalidate; validator failure restores original bytes and emits a restoration receipt path.
+
+## Use cases
+
+### UC-1 Validation parity use case
+BRAN-native strict validation handles repository checks and returns deterministic pass/fail
+exit plus structured output for repository boundary violations.
+
+### UC-2 Legacy-compatibility check
+Legacy `use-okf` and `tools/okf/okf` commands remain callable as adapters and map into
+BRAN-native behavior without changing core outcomes during migration.
+
+### UC-3 Retrieval use case
+Queries continue to rank and select canonical evidence deterministically using canonical,
+authority, status, and path/title/tag fields.
+
+### UC-4 Self-heal proposal use case
+`maintain propose` returns digest and target metadata without mutating repository source.
+
+### UC-5 Apply with explicit authority
+`maintain apply` requires a replacement plan and non-empty authority reason, verifies digest
+and staleness, performs mutation, and only reports success after revalidation.
+
+### UC-6 Failure and rollback use case
+Validation failure after apply restores the exact prior target state and returns failure receipts
+with explicit failure terminal state.
+
+### UC-7 Boundary safety use case
+Repository/classification/source-link checks enforce boundaries, with explicit diagnostics for
+unsafe paths, stale source, missing authority marker, and unavailable checks.
+
+## Components
+
+- `crates/bran-cli/src/main.rs`: CLI command surface (`maintain`) and envelope
+  exits.
+- `crates/bran-core/src/repair/mod.rs`: proposal/apply/state machine and restoration receipts.
+- `crates/bran-core/src/metadata/mod.rs`: metadata parsing and header extraction behavior.
+- `crates/bran-core/src/graph/query.rs`: deterministic retrieval path/title/tag/canonical
+  match behavior.
+- `Alphazedehq` compatibility tooling (`/home/spectre/alphazede/Alphazedehq/.grok/hooks/use-okf.sh`,
+  `/home/spectre/alphazede/Alphazedehq/tools/okf/okf`).
+
+## Acceptance criteria
+
+- **AC-1**: Staged replacement keeps BRAN as canonical behavior for repository validation
+  while legacy compatibility remains explicitly adapter-only until explicit parity sign-off.
+- **AC-2**: BRAN strict validation behavior remains behaviorally explicit in core/CLI and
+  continues to enforce frontmatter parsing, source-link handling, and boundary policy.
+- **AC-3**: Repository maintenance flow enforces read-only proposal, explicit authority on apply,
+  digest matching, and revalidation before success.
+- **AC-4**: Validation failures in apply path restore original target content and emit an
+  attributable failure lifecycle value indicating restoration.
+- **AC-5**: Retrieval and compatibility flows preserve stronger-source precedence outcomes and
+  do not require unverified source-policy claims.
+- **AC-6**: No repository rewrite happens without explicit, bounded BRAN-owned authority and
+  compatible revalidation result.
+- **AC-7**: Legacy `use-okf`, `tools/okf/okf`, legacy hooks, and legacy configurations are
+  retired only after every active consumer has migrated to BRAN-native policy and BRAN-backed hook/skill.
+  Required evidence remains BRAN-vs-legacy retrieval and validation parity, plus audit that no active code,
+  skill, hook, or CI reference uses legacy entrypoints/configuration outside explicitly historical documents.
+
+## Risks and open questions
+
+- **RISK-1**: [Non-blocking] Active consumers can progress on different schedules; one consumer delay can
+  delay global adapter removal but does not invalidate completed migration evidence from completed consumers.
+- **RISK-2**: [Non-blocking] Hook behavior migration requires careful implementation of fail-open
+  fallback and compatibility-only semantics, but owner-confirmed posture is now fixed.
+- **RISK-3**: [Non-blocking] Publication sequencing is owner-authorized and constrained by public-boundary
+  review, with no remaining migration-blocking ambiguity.
+- **RISK-4**: [Non-blocking] Native schema filename/serialization details remain design concerns and are
+  intentionally deferred until implementation design review.
+- **RISK-5**: [Non-blocking] Compatibility parity evidence cadence will remain a planning and QA scheduling
+  pressure rather than a hard migration blocker.
+
+## Owner decisions
+
+1. Staged replacement. BRAN becomes the canonical internal repository-knowledge and
+   validation implementation. The legacy `use-okf` skill and `tools/okf/okf` command remain
+   deprecated compatibility adapters only until consumer parity is proven and owner resolves retirement
+   criteria. There is no hard same-change cutover.
+2. Strict repository validation is native BRAN Core/CLI behavior, not a call through to the legacy
+   validator. It must preserve required/allowed frontmatter validation, canonical/legacy/excluded/unclassified
+   coverage, source-link integrity, repository tag/status policy, public/private boundary enforcement,
+   deterministic reports, and compatible typed exit behavior. The compatibility adapter may translate
+   old invocations/results during migration.
+3. Self-healing authority is split by ownership. BRAN may automatically rebuild only BRAN-owned derived
+  state such as indexes, snapshots, caches, reports, and generated validator artifacts. Repository source,
+  metadata, classifications, configuration, and source links are never silently rewritten. BRAN may propose a
+  bounded repair; apply requires explicit authority and the exact proposal digest, then revalidation.
+  Validation failure restores the exact original bytes and emits an attributable receipt.
+
+4. Configuration relationship. BRAN owns a new native repository-policy schema. Existing
+   `tools/okf/config.yaml` inputs are migration-only and accepted read-only through the
+   compatibility adapter. They are never automatically rewritten. Repository conversion is deliberate
+   and occurs only after parity evidence. Exact native filename and serialization remain a design
+   concern unless owner input is genuinely required.
+5. Hook behavior. Preserve the existing use-okf hook logic while replacing its implementation
+   with BRAN: SessionStart lightweight availability, relevant-keyword UserPromptSubmit, and
+   relevant-file PostToolUse; dynamic managed-repository discovery; trusted executable resolved from
+   the hook's physical checkout or owner-approved stable path; bounded timeouts; compact output;
+   graceful unavailable fallback; always exit success/fail-open; no hook-driven source mutation.
+   Strict failures remain exclusive to explicit BRAN validation or configured CI.
+6. Adoption/publication order. Adopt an exact locally built BRAN artifact first using a checksum pin
+  and stable local path. Run compatibility/shadow and consumer parity before public publication. A public
+  download/install is later release-install verification, not a prerequisite for internal adoption.
+  Publication remains owner-authorized and occurs only after migration parity and public-boundary review.
+
+7. Legacy retirement is evidence-based, not date-based. There is no arbitrary migration window or adapter
+   retirement date. Retirement of legacy `use-okf`, `tools/okf/okf`, legacy hooks, and legacy
+   configurations occurs only when every active consumer repository has deliberately migrated to BRAN-native
+   policy and BRAN-backed hook/skill. Required evidence includes:
+   (a) BRAN-vs-legacy validation and retrieval compatibility parity passes; and
+   (b) confirmed absence of active code, skill, hook, or CI references to legacy entrypoints/configuration
+       outside explicitly historical documents. A migration problem in one repository can delay only that repository
+   and final global adapter removal, without invalidating completed migration evidence from other repositories.
+   Active migration inventory confirmed by focused discovery: Alphazedehq, alphazede-sports, betbot,
+   developers, hgts, and alphazede-markets.
+
+## Sequencing
+
+- Run compatibility inventory and parity evidence collection for retrieval and validation.
+- Confirm repair lifecycle and rollback invariants with explicit failure/restore traces.
+- Run per-repository BRAN-native migration and retire legacy entrypoints only when owner decision 7
+  conditions and evidence are met; unresolved repositories remain on adapter pathways until complete.
+
+## Evidence consulted
+
+- `/home/spectre/alphazede/Alphazedehq/.grok/hooks/use-okf.sh:7-20,26-57,81-99,125-187`
+- `/home/spectre/alphazede/Alphazedehq/.grok/hooks/use-okf.json:1-38`
+- `/home/spectre/alphazede/Alphazedehq/.grok/hooks/README.md:24-53`
+- `/home/spectre/alphazede/Alphazedehq/tools/okf/okf:56-85,88-174`
+- `/home/spectre/alphazede/Alphazedehq/tools/okf/config.yaml:1`
+- `/home/spectre/alphazede/alphazede-sports/tools/okf/config.yaml:1`
+- `/home/spectre/alphazede/betbot/tools/okf/config.yaml:1`
+- `/home/spectre/alphazede/developers/tools/okf/config.yaml:1`
+- `/home/spectre/alphazede/hgts/tools/okf/config.yaml:1`
+- `/home/spectre/alphazede/alphazede-markets/tools/okf/config.yaml:1`
+- `/home/spectre/alphazede/Alphazedehq/AGENTS.md:106-123`
+- `/home/spectre/alphazede/bran/AGENTS.md:32-44`
+- `/home/spectre/alphazede/bran/docs/plans/AGENTS.md:1-24`
+- `/home/spectre/alphazede/bran/crates/bran-core/src/metadata/mod.rs:248,737`
+- `/home/spectre/alphazede/bran/crates/bran-core/src/graph/query.rs:1596,1600,1617-1620`
+- `/home/spectre/alphazede/bran/crates/bran-core/src/repair/mod.rs:4,19,123,180-188,189-297`
+- `/home/spectre/alphazede/bran/crates/bran-cli/src/main.rs:76,1994,2032,2124,2381`
+
+## Handoff to design-driven-build
+
+- **CDD pressure**: preserve staged replacement versus hard cutover, and boundary between proven parity
+  and completed owner decisions.
+- **SecDD pressure**: typed repair failures, authority validation, stale-digest/conflict handling, and
+  rollback-receipt requirements.
+- **RDD pressure**: retrieval precedence and compatibility adapter behavior (`legacy` vs `canonical`),
+  with parity invariants preserved under owner decision 7 and active-consumer sequencing.
+- **ODD pressure**: command surface/API posture and exit-state contracts (`Validation`, `Operation`,
+  `Usage`, `Success`) across maintenance and adapter boundaries.
+- **OOPDSA focus**: ownership boundaries for repair state, adapter layer split, and explicit authority
+  transitions from proposal to revalidation/receipt.
+- **SEIT obligations**: include positive and negative parity cases, legacy compatibility cases,
+  validation failures, stale-source and stale-digest cases, and rollback assertions with evidence
+  retention.
+
+## See also
+
+- `/home/spectre/alphazede/Alphazedehq/.grok/hooks/use-okf.sh`
+- `/home/spectre/alphazede/Alphazedehq/.grok/hooks/use-okf.json`
+- `/home/spectre/alphazede/Alphazedehq/tools/okf/okf`
+- `/home/spectre/alphazede/bran/crates/bran-cli/src/main.rs`
+- `/home/spectre/alphazede/bran/crates/bran-core/src/repair/mod.rs`
+
design.md
---
+type: design
+name: bran-okf-migration
+status: amended
+date: 2026-07-21
+applies_to: bran
+plan_spec: ./plan-spec.md
+lenses_applied: [CDD, SecDD, RDD, ODD]
+lenses_skipped: [BizDD, DDD, EDD, GDD, PDD]
+---
+
+## Synthesis
+
+BRAN becomes the sole owner of repository-knowledge policy, validation, retrieval,
+and bounded repair semantics. A thin compatibility boundary preserves the legacy
+`use-okf` skill, hook triggers, `tools/okf/okf` entrypoint, and
+`tools/okf/config.yaml` inputs while consumers migrate. Compatibility code may
+translate requests and results, but it may not implement validation rules, ranking,
+repair authority, or source mutation.
+
+The design has four layers:
+
+1. `bran-core` owns the native policy model, deterministic validation, retrieval
+   precedence, derived-state rebuilding, and repair state machine.
+2. `bran-cli` owns versioned command envelopes, typed exits, native policy loading,
+   and explicit maintenance authorization input.
+3. A legacy adapter owns only old command/configuration translation and parity
+   comparison. It never rewrites legacy configuration.
+4. Repository hooks discover the pinned BRAN executable and invoke bounded,
+   fail-open advisory operations. Explicit CLI validation and CI remain strict.
+
+The native repository policy is `.bran/policy.yaml`, with an explicit
+`schema_version`. It uses BRAN terms and is validated before repository scanning.
+The choice reuses BRAN's existing dependency-free YAML value/parser surface,
+keeps policy human-reviewable, and avoids claiming the legacy OKF file is the native
+contract. Generated JSON schemas and reports remain BRAN-owned derived artifacts.
+
+The pre-lens test stance remains contract-first and offline: frozen repositories
+must prove native validation, legacy parity, source precedence, hook degradation,
+and exact repair rollback without providers, network access, or live consumer
+mutation. Lens analysis adds threat-boundary, fault-injection, receipt, and
+observability assertions.
+
+## Use Cases and Communication Flows
+
+### Flow 1 - Native validation
+
+```text
+caller -> bran CLI -> .bran/policy.yaml loader -> repository scanner
+       -> normalized bundle -> BRAN strict validator -> deterministic envelope + exit
+```
+
+Text equivalent: an explicit CLI or CI call loads and validates the versioned native
+policy before scanning. BRAN normalizes repository evidence, runs strict rules, and
+returns ordered diagnostics. Policy, scan, or validation errors remain distinct and
+only the selected profile controls the terminal exit.
+
+### Flow 2 - Legacy adapter during staged migration
+
+```text
+legacy caller -> use-okf/tools/okf adapter -> legacy config reader
+              -> normalized BRAN policy request -> BRAN core/CLI
+              -> legacy-shaped result + parity receipt
+```
+
+Text equivalent: the adapter accepts the old command and configuration without
+rewriting either. It translates them into BRAN-native requests, invokes the same
+core behavior as native callers, and translates the result shape. Shadow mode records
+both outcomes and differences; it never gives the legacy implementation authority
+over BRAN behavior.
+
+### Flow 3 - Advisory hook
+
+```text
+SessionStart | relevant prompt | relevant edit
+  -> dynamic repository discovery -> trusted pinned BRAN binary
+  -> bounded advisory query/check -> compact message
+  -> unavailable/timeout/malformed result => warning or silence, exit 0
+```
+
+Text equivalent: the existing three hook triggers remain. The hook resolves the
+managed repository and trusted executable, applies its configured timeout, and emits
+compact advice. Missing BRAN, timeout, invalid telemetry, or validation findings do
+not block the agent and never mutate repository source.
+
+### Flow 4 - Authorized repair and recovery
+
+```text
+maintain propose (read only) -> immutable proposal + digest
+owner-reviewed authority + exact digest -> maintain apply
+  -> stale/path checks -> staged write -> native revalidation
+  -> pass: success receipt
+  -> fail: exact rollback -> restoration receipt + validation failure
+```
+
+Text equivalent: proposal captures target, replacement, and original bytes without a
+write. Apply requires explicit authority and the exact proposal digest. It refuses
+stale or unsafe targets, stages the write, revalidates, and reports success only after
+validation. Failed validation restores the exact original state and retains an
+attributable failure receipt.
+
+### Flow 5 - Consumer retirement
+
+```text
+consumer inventory -> native policy + BRAN hook/skill migration
+  -> validation parity + retrieval parity -> active-reference audit
+  -> per-consumer complete -> all consumers complete -> owner removal approval
+```
+
+Text equivalent: each consumer moves independently and retains its evidence. A delayed
+consumer stays on the adapter without invalidating completed consumers. Global removal
+requires all six consumers, parity evidence, absence of active legacy references, and
+owner approval.
+
+## Test Strategy
+
+### Pre-lens stance
+
+Use deterministic fixtures and contract tests. Native BRAN behavior must be testable
+without hooks or adapters; adapters must be testable against the same frozen corpus;
+and repair behavior must retain byte-level evidence across all terminal states.
+
+### Lens revisions
+
+- CDD adds schema-version, command-envelope, typed-exit, and adapter contract tests.
+- SecDD adds traversal, symlink, stale digest/source, authority, secret redaction, and
+  public-boundary negative cases.
+- RDD adds timeout, unavailable binary, malformed output, partial write, failed
+  validation, rollback failure, and retry/idempotency cases.
+- ODD adds deterministic receipt fields, parity deltas, missing-observability handling,
+  and first-command diagnostic procedures.
+
+### Per-slice approach
+
+| Design area | Primary test layer | Cross-cutting proof |
+| --- | --- | --- |
+| Native policy and validation | core unit, schema, conformance | deterministic diagnostics and exits |
+| CLI maintenance contracts | CLI contract and fault fixtures | authority, digest, rollback receipts |
+| Legacy adapter and configuration | characterization and parity | no rewrite; same semantic outcome |
+| Hooks and skill | shell fixtures and integration | trigger parity, bounded timeout, exit 0 |
+| Consumer migration | repository procedure and audit | preserved per-consumer evidence |
+
+### Cross-cutting checks
+
+All cases run offline against disposable fixtures. Tests compare semantic outcomes,
+not timestamps or path ordering accidents. Missing optional telemetry is retained as
+`unavailable` and cannot change validation success. Public-boundary scans cover plans,
+receipts, hook output, fixtures, and release artifacts.
+
+## CDD
+
+- **Surfaces touched.** `.bran/policy.yaml`; BRAN validation and maintenance CLI
+  envelopes; `RepairProposal`, `RepairReceipt`, and `RepairTerminal`; legacy
+  `tools/okf/okf` commands/config; `use-okf` skill and hook trigger/result behavior.
+- **Contracts.** `DES-1`: the native policy begins with `schema_version`, rejects an
+  unsupported version as a typed usage/configuration error, and models frontmatter,
+  coverage classes, source links, tags/status, and public boundaries. `DES-2`: CLI
+  commands return deterministic JSON envelopes and typed exits `0` success, `1`
+  validation, `2` usage/configuration, and `3` operation/unavailable. `DES-3`:
+  proposal is read-only; apply accepts the same target/replacement, exact digest, and
+  non-blank authority; revalidation alone performs no source mutation. `DES-4`: the
+  legacy adapter translates old inputs and outputs only and records parity differences.
+- **Idempotency and ordering.** Validation and retrieval are read-only and repeatable.
+  Derived-state rebuilds replace only BRAN-owned artifacts deterministically. Applying
+  an already-consumed proposal encounters stale source rather than repeating a write.
+  Diagnostics and parity rows sort by repository-relative path, code, then message.
+- **Compatibility commitments.** Legacy calls remain accepted per consumer until AC-7
+  evidence and owner approval. Unknown legacy fields are preserved or diagnosed, never
+  silently discarded when they affect behavior. Native policy has no promise to serialize
+  back to the legacy format.
+- **Versioning strategy.** Native policy and structured receipts carry explicit schema
+  versions. CLI command names and typed exits are stable within the initial native schema.
+  Adapter compatibility is versioned by its mapping tests and release pin.
+- **Interface option input.** Native policy location/serialization requires the global
+  Interface Option Check. Maintenance authority and hook triggers retain approved shapes.
+- **Validation and tests.** Parser/schema tests live in `bran-core`; CLI envelope and exit
+  tests in `bran-cli`; adapter and hook characterization tests remain beside their
+  compatibility surfaces until retirement.
+- **Generated code provenance.** JSON schemas/reports are generated or checked from the
+  BRAN-owned model by repository tooling. Generated artifacts never become policy input.
+- **Notable omissions.** No network API, service protocol, or provider contract is added.
+
+## SecDD
+
+- **Threat model.** A repository author may craft paths, symlinks, metadata, or links to
+  escape the root or cross public/private boundaries. A stale or malicious caller may
+  replay a proposal or forge authority text. A compromised compatibility script may try
+  to bypass native validation. Accidental output may expose private paths or corpus text.
+- **Trust boundaries and validation.** `DES-5`: all policy paths become normalized
+  repository-relative paths and are checked against the canonical root without following
+  symlink escapes. Legacy configuration is untrusted adapter input and must pass the
+  native policy validator. Only BRAN core decides validation and repair terminal state.
+- **Authn / authz.** Offline read-only commands require no identity. Source apply requires
+  an explicit invocation authority reason and exact digest; no hook or adapter infers it.
+  Publication, release, and adapter removal remain owner-authorized operations.
+- **Secrets.** No new secret is introduced. Hooks use a checksum-pinned local binary and a
+  sanitized environment. Policy, receipts, logs, and fixtures must reject or redact auth
+  state, credentials, host-private paths, and hidden evaluation material.
+- **Sensitive data.** Private repository content stays local. Diagnostics contain bounded
+  repository-relative locators and rule codes, not arbitrary source bodies.
+- **Audit trail.** Repair receipts record schema version, digest, target, authority tag,
+  and lifecycle. Parity records name consumer, BRAN pin, corpus/policy identity, outcome,
+  and semantic differences. Receipts are evidence, not permission tokens.
+- **Abuse cases.** Traversal, absolute paths, NULs, symlink ancestors, stale snapshots,
+  digest mismatch, blank authority, config ambiguity, secret-like values, and public-link
+  violations are refused before mutation.
+- **Notable omissions.** No remote authentication or cryptographic signer is required for
+  local migration. The digest is an identity/staleness check, not a security signature.
+
+## RDD
+
+- **Failure modes.** `DES-6`: missing/timed-out BRAN affects only the triggering hook and
+  yields advisory unavailable; malformed policy stops explicit validation before scanning;
+  stale source/digest stops apply before writing; I/O failure returns operation failure;
+  failed validation rolls back; rollback failure reports partial-write uncertainty and
+  preserves recovery artifacts. A consumer parity mismatch delays only that consumer.
+- **Timeouts and retry budget.** Hook timeouts remain 12 seconds for SessionStart, 15 for
+  prompt submit, and 20 for post-edit. Hooks do not retry. Explicit commands rely on their
+  caller/CI budget. Apply is never blindly retried; callers must propose again after stale
+  or uncertain outcomes.
+- **Degradation behavior.** Hooks fail open and exit success. Explicit validation and CI
+  fail on native validation errors. Missing metrics or receipts reduce observability but do
+  not rewrite semantic success. Adapter parity mismatch is recorded and blocks only that
+  consumer's retirement.
+- **Recovery and repair.** Derived state may be rebuilt automatically. Source recovery uses
+  exact backup bytes retained through revalidation. Partial-write uncertainty stops further
+  mutation and directs the operator to inspect the receipt/backup before a fresh proposal.
+- **Backup and restore.** No repository-wide backup is introduced. The repair coordinator's
+  same-directory staged backup is the transactional recovery boundary and is deleted only
+  after successful revalidation.
+- **Notable omissions.** No queue, daemon, distributed retry, or background reconciliation.
+
+## ODD
+
+- **Logs.** Structured command envelopes and parity/repair receipts are the operational
+  record. Fields are schema version, command, status, rule/error codes, bounded locators,
+  pin/policy identity, and lifecycle. Source bodies, secrets, auth state, and host-private
+  absolute paths are excluded.
+- **Metrics.** `DES-7`: per consumer retain validation parity, retrieval parity, legacy
+  active-reference count, hook unavailable/timeout count, and migration state. Metrics are
+  bounded by consumer and rule code; repository paths remain evidence fields, not labels.
+- **Traces.** No distributed tracing. A proposal digest correlates propose/apply/revalidate;
+  a parity run ID correlates legacy and BRAN outcomes.
+- **Health checks.** `bran --version` plus release-pin verification answers executable
+  readiness. Native policy parse/validate answers repository readiness. Hook success alone
+  never claims validation readiness.
+- **Dashboards and alerts.** No service dashboard or paging. Migration evidence is a
+  deterministic report; explicit CI failures surface normally. Hook failures are compact
+  warnings and aggregated evidence, not pages.
+- **Operator first-five-minutes runbook stub.** Verify pin, run native validation directly,
+  inspect its typed envelope, then run adapter parity for only the affected consumer.
+- **Questions answerable from telemetry alone.** Which BRAN build ran? Which policy and
+  consumer were checked? Did native and legacy semantics differ? Was source mutated? Was a
+  failed mutation restored? Which consumer still references legacy behavior? Which fields
+  are unavailable?
+- **Notable omissions.** No uptime SLO, telemetry backend, or remote collector.
+
+## Interface Option Check
+
+Three repository-policy interfaces were considered:
+
+| Option | Shape | Compatibility | Main tradeoff |
+| --- | --- | --- | --- |
+| A | `.bran/policy.yaml`, versioned BRAN schema | legacy adapter maps old YAML read-only | explicit ownership and human review; one migration step |
+| B | keep `tools/okf/config.yaml` as native | zero initial path migration | makes legacy names and schema permanent BRAN API |
+| C | infer policy from repository contents | fewer files | ambiguous authority, weak reproducibility, unsafe defaults |
+
+`interface_options: selected - Option A (.bran/policy.yaml)`
+
+`DES-8`: Option A is selected. `bran-core` owns parsing and normalized policy
+semantics; `bran-cli` discovers the file only from an explicit repository root; the
+legacy adapter maps `tools/okf/config.yaml` into the same in-memory policy without
+writing `.bran/policy.yaml`. Schema version, unknown-field diagnostics, deterministic
+serialization fixtures, and migration parity are mandatory. A future format change
+requires a new schema version rather than heuristic parsing.
+
+## OOPDSA Implementation Design
+
+### Requirements trace
+
+| Requirement ID | OOPDSA owner | Proof obligation |
+| --- | --- | --- |
+| AC-1, AC-7 | `LegacyOkfAdapter` and migration inventory | native ownership plus evidence-based retirement |
+| AC-2, AC-5 | `RepositoryPolicyLoader`, `ProfileValidator`, query engine | strict policy and deterministic precedence |
+| AC-3, AC-4, AC-6 | `RepairCoordinator` | explicit authority, exact digest, revalidate, rollback |
+| RISK-1, RISK-5 | `ParityRecorder` | independent consumer state and semantic deltas |
+| RISK-2 | hook adapter | trigger parity and fail-open behavior |
+| RISK-3 | release/public-boundary procedure | no implicit publication |
+| RISK-4 | `RepositoryPolicyLoader` | selected versioned native policy contract |
+
+### Ownership contract
+
+| Object / Service | Responsibility | Owns Data? | Key Methods / Entry Points | Collaborators | Boundary / Interface | Test Focus | Must Not Own |
+| --- | --- | ---: | --- | --- | --- | --- | --- |
+| `RepositoryPolicyLoader` | parse/version/normalize `.bran/policy.yaml` | yes, immutable policy value | `load(root)`, `normalize()` | scanner, validator | filesystem to policy | versions, paths, unknown fields | repository mutation |
+| `ProfileValidator` | evaluate compatibility and strict rules | no | `validate(bundle, profile)` | policy, bundle | normalized evidence to diagnostics | deterministic rules/exits | adapter shapes |
+| query engine | canonical retrieval and precedence | yes, derived index | existing query/packet entrypoints | scanner, graph | query to ranked evidence | rank stability, precedence | policy migration |
+| `RepairCoordinator` | proposal/apply/revalidate/rollback | yes, proposal snapshot and staged backup | `propose`, `apply` | validator | explicit mutation boundary | all terminal states, exact restore | inferred authority |
+| `LegacyOkfAdapter` | translate legacy commands/config/results | no | `check`, `doctor`, shadow/parity | BRAN CLI/core | legacy to native | characterization and parity | validation/ranking rules |
+| hook adapter | preserve triggers and bounded advisory calls | no | SessionStart, UserPromptSubmit, PostToolUse | pinned CLI | agent hook boundary | timeout, unavailable, exit 0 | source mutation or strict gate |
+| `ParityRecorder` | retain per-consumer semantic comparison | yes, derived receipts | `record`, `summarize` | adapter, inventory | evidence ledger | missing fields, deterministic deltas | task success or authority |
+
+### Pattern decisions
+
+| Decision ID | Pressure | Candidate Pattern | Chosen Pattern / Plain Code | Why | Simpler Alternative | Tradeoffs | Review Trigger |
+| --- | --- | --- | --- | --- | --- | --- | --- |
+| CONTRACT-1 | legacy/native shapes differ | Adapter | one thin `LegacyOkfAdapter` | isolates retirement and prevents rule duplication | conditionals in CLI | temporary extra surface | adapter implements semantics |
+| CONTRACT-2 | repair has explicit lifecycle | State machine | retain typed `RepairTerminal` transitions | impossible to claim success before revalidation | booleans/errors | more variants | terminal state loses evidence |
+| CONTRACT-3 | validators need a policy value | immutable value object | `RepositoryPolicy` parsed once | single owner and deterministic consumers | raw YAML maps | schema migration code | consumers read raw fields |
+| CONTRACT-4 | hooks need graceful calls | plain shell boundary | preserve small fail-open script | no daemon/framework needed | shared runtime service | repeated process startup | hook gains mutation/retry |
+| CONTRACT-5 | migration evidence is partial | append-only derived receipts | records available fields plus `unavailable` | observability cannot invalidate work | strict ledger schema | consumers handle missing values | receipt becomes eligibility gate |
+
+### DSA decisions
+
+| Decision ID | Owner | Operation | Expected Scale | Chosen Structure | Chosen Algorithm | Time | Space | Reason | Simpler Alternative | Edge Cases |
+| --- | --- | --- | ---: | --- | --- | --- | --- | --- | --- | --- |
+| CONTRACT-6 | `RepositoryPolicy` | membership/classification | repository paths | ordered maps/sets | normalize then lexical traversal | O(n log n) | O(n) | deterministic diagnostics and overlap detection | vectors | duplicate/overlap/excluded roots |
+| CONTRACT-7 | query engine | precedence/ranking | repository evidence nodes | existing graph indexes + stable tuples | canonical/status/freshness/authority ordering | existing bounded query contract | existing index budget | preserve proven retrieval behavior | full scan/sort | ties, stale and legacy sources |
+| CONTRACT-8 | `ParityRecorder` | semantic diff | six consumers, bounded results | ordered map keyed by semantic identity | normalize, join, compare, lexical emit | O(n log n) | O(n) | ignores formatting/order noise | raw text diff | missing telemetry, duplicate codes |
+| CONTRACT-9 | `RepairCoordinator` | stale detection and rollback | one bounded target | byte snapshot plus staged backup | exact compare, staged replace, validate, restore | O(b) | O(b) | exact recovery is more important than cleverness | timestamps | absent file, same-length edits, rollback I/O failure |
+
+### Invariants and edge cases
+
+- Native and adapter requests with equivalent policy have the same semantic validation
+  and retrieval outcomes.
+- Only BRAN-owned derived paths may be automatically replaced.
+- No apply reaches a write with blank authority, mismatched digest, stale bytes, unsafe
+  path, or symlink escape.
+- Validation failure cannot produce success; successful rollback restores byte identity.
+- Hook timeout, missing executable, malformed output, or metric absence always exits zero.
+- One consumer mismatch cannot erase another consumer's completed evidence.
+- Active legacy references outside historical documents prevent only retirement.
+
+The implementation must satisfy `CONTRACT-1` through `CONTRACT-9`; the prospective
+proof map is owned by `seit.md`.
+
+## Owner-approved product parity amendment — 2026-07-22
+
+`DES-9`: Repository policy is an immutable validated value with two explicit input
+sources. The default native command loads `.bran/policy.yaml` from the explicit
+repository root. `--policy-stdin` reads the same schema without persistence. The
+sources are mutually exclusive, policy validation precedes scanning, stdin is
+bounded, and policy content is not echoed into diagnostics or logs.
+
+`DES-10`: BRAN owns the remaining semantic OKF customer contracts: document coverage
+classification and migration-state rules, preserved frontmatter keys, source/link/
+citation integrity, public-boundary allowlists, packet supersession validation, and
+body-preservation validation. Existing BRAN graph, metadata, packet, and policy types
+are extended rather than duplicating these rules in Python or shell adapters.
+
+`CONTRACT-10`: `LegacyOkfAdapter` converts legacy YAML into the versioned native
+policy schema, sends it through `--policy-stdin`, translates the native envelope back
+to the legacy command result, and records parity. Unknown behavior-affecting fields
+produce a typed configuration failure. The adapter never writes `.bran/policy.yaml`
+and never falls back to a second semantic validator.
+
+Customer-facing consequences are additive: repository policy remains the recommended
+interface, while read-only checkouts, centrally managed CI policy, editors, and
+migration tools can supply an equivalent transient policy. Legacy validator build and
+self-heal machinery, benchmarking, SQZ evaluation, and issue automation remain outside
+the BRAN semantic product boundary.
+
+This owner-approved amendment refines AC-1, AC-2, AC-5, AC-7, RISK-3, and RISK-4.
+The amended implementation must satisfy `CONTRACT-1` through `CONTRACT-10`.
+
+## Design Amendment — 2026-07-22 — Native quoted-scalar interoperability
+
+Implementation exposed an interoperability gap at the native-policy boundary: the
+legacy adapter can serialize quoted YAML, but BRAN's bounded parser currently strips
+delimiters without decoding the quote forms needed to preserve exact values.
+
+`DES-11`: BRAN's single native policy parser owns a bounded, explicitly documented
+quoted-scalar subset. Single-quoted scalars decode doubled apostrophes. Double-quoted
+scalars decode only the minimal escapes required for exact adapter transport (`\"` and
+`\\`); unsupported escapes, literal CR/LF, control characters, and unmatched delimiters
+fail with the existing non-echoing malformed-policy error. Unquoted behavior and policy
+semantics remain unchanged.
+
+`CONTRACT-11`: `LegacyOkfAdapter` selects a lossless representation from that native
+subset, never silently coerces a behavior-affecting value, and returns static field/index
+diagnostics that cannot expose raw policy values, repository paths, operating-system
+errors, or arbitrary child-process output. Equivalent file and stdin policies parse to
+the same immutable `RepositoryPolicy` value.
+
+This amendment changes serialization interoperability and error sanitization only. It
+does not change validation rules, authority, mutation scope, the default
+`.bran/policy.yaml` interface, compatibility-retirement criteria, or publication scope.
+The Interface Option Check remains unchanged because both policy sources still converge
+on the same parser. OOPDSA ownership remains `RepositoryPolicy` plus the thin
+`LegacyOkfAdapter`; the parser uses a bounded linear state machine with O(n) time and
+O(n) output for each quoted scalar.
+
+## Design Amendment — 2026-07-22 — Oversized binary scan isolation
+
+Full-config adapter proof exposed a pre-profile failure on an unrelated 1.9 MiB image.
+Legacy OKF treats non-text assets as outside repository-knowledge validation, while BRAN
+currently applies its text-source byte limit before it can classify an oversized binary
+as unsupported input.
+
+`DES-12`: When a regular file advertises a size above the configured per-file text limit,
+the scanner reads only a fixed bounded prefix before deciding. A prefix containing NUL or
+invalid UTF-8 is recorded as `UnsupportedInput` and the file is not buffered, parsed, or
+charged to accepted-source byte totals. A valid UTF-8 prefix remains subject to the
+existing hard size failure. The same rule applies to full and incremental scans, retains
+symlink/root-escape checks, and never guesses that oversized text is safe.
+
+`CONTRACT-12`: Oversized binary isolation is a scanner input-classification rule, not a
+policy exclusion or adapter exception. The probe is constant-space and bounded O(1) by a
+fixed byte ceiling; accepted text retains existing limits and identity semantics. This
+restores profile evaluation for repositories containing unrelated binary assets without
+weakening protection against oversized textual knowledge inputs.
+
+## Design Amendment — 2026-07-22 — Check-time knowledge-candidate alignment
+
+Full-config adapter proof next exposed an oversized generated `review.html`. BRAN's
+general-purpose repository scanner correctly supports source and other text inputs, but
+the `check` pipeline later discards every entry except the native Markdown knowledge
+formats. Applying accepted-source limits before that existing admissibility decision lets
+non-knowledge generated text block profile evaluation.
+
+`DES-13`: The native `check` pipeline supplies the scanner a deterministic knowledge-
+candidate predicate equal to the predicate used to derive its validation bundle. Paths
+that cannot enter that bundle are not opened, parsed, or charged to check-time accepted-
+source totals. The general-purpose scanner remains unchanged by default so other BRAN
+features can scan source and text files. Full and incremental filtered scans use the same
+predicate, and containment, symlink, file-count, and byte-limit checks remain mandatory
+for every admitted candidate.
+
+`CONTRACT-13`: Knowledge-candidate selection is a BRAN-native check contract, not an
+adapter rule or configurable extension allow/deny facility. One shared predicate owns the
+currently supported Markdown path forms and is reused by scanning and bundle derivation.
+An oversized admitted Markdown document still fails closed; a generated non-candidate
+file cannot prevent profile selection. This removes duplicate downstream filtering and
+generalizes to every customer without changing policy, repository content, or limits.
+
+## Authorization-gated upstream OKF contribution candidates
+
+Implementation produced two reusable format-level lessons that are suitable for a
+separately authorized issue or pull request against the upstream Open Knowledge Format
+specification. They remain proposals, not migration deliverables:
+
+- `UPSTREAM-1 — bundle scan scope`: clarify that non-OKF files may coexist beside a
+  bundle, do not participate in OKF conformance, and should not be opened merely to
+  validate the bundle unless explicitly referenced. This prevents unrelated binary or
+  generated text from blocking conformance while leaving implementation resource limits
+  outside the format contract.
+- `UPSTREAM-2 — layered profile separation`: permit implementations to expose stricter
+  organizational readiness profiles only when their results are reported separately from
+  OKF conformance. An implementation-specific failure must not be characterized as OKF
+  nonconformance when the portable v0.1 floor passes.
+
+BRAN keeps `okf-v0.1` as the portable interoperability outcome and `bran-strict` as the
+additive repository-policy outcome. Both are computed independently and only the selected
+profile controls the command exit. Before BRAN claims complete OKF v0.1 certification, a
+separate bounded follow-up must close the known reserved-file coverage gap: the current
+compatibility profile validates concept frontmatter and `type` but does not yet validate
+the upstream `index.md` and `log.md` structural requirements.
+
+No upstream issue, pull request, comment, push, or publication is authorized by this
+plan. The Conductor must first present the exact proposed upstream text, target, and
+scope, then obtain explicit owner authorization for that external write.
+
+## Design Amendment — 2026-07-23 — Upstream OKF rationale and sequencing
+
+This amendment expands `UPSTREAM-1` and `UPSTREAM-2` into reviewable contribution
+briefs. It does not authorize an external write, add BRAN-specific behavior to OKF, or
+change the completed migration acceptance boundary.
+
+### UPSTREAM-1 — Bundle scan scope
+
+**Problem.** OKF v0.1 defines a knowledge bundle as a directory tree of Markdown files
+and permits the bundle to be a subdirectory of a larger repository. Its conformance
+rules apply to non-reserved Markdown files "in the tree," but the specification does not
+explicitly say that validators can restrict conformance I/O to the designated bundle
+root. Implementations can therefore disagree: one validates only the bundle while
+another recursively opens unrelated repository assets, generated reports, databases, or
+binaries.
+
+**Representative layout.** In the following repository, only `docs/okf/` is the
+designated bundle:
+
+```text
+customer-repository/
+├── docs/okf/
+│   ├── index.md
+│   └── concepts/orders.md
+├── application/
+├── screenshots/
+├── build/
+├── database.sqlite
+└── generated-report.html
+```
+
+The application, screenshots, build outputs, database, and generated report do not
+participate in OKF conformance and need not be opened merely to validate `docs/okf/`.
+Within the designated bundle root, every non-reserved `.md` file still participates
+under the existing specification, reserved files retain their structural obligations,
+and referenced content remains subject to the relevant link or citation behavior.
+
+**Recommended normative direction.** Add a narrow clarification to the bundle-structure
+or conformance section:
+
+> Conformance is evaluated within a designated bundle root. Files outside that root do
+> not participate. Within the bundle root, reserved and non-reserved Markdown files
+> participate as specified; other files may coexist and need not be opened for
+> conformance unless explicitly referenced by a participating document.
+
+**Benefits.** The clarification makes OKF practical in monorepos, prevents unrelated
+binary or generated files from changing format outcomes, reduces unnecessary I/O, and
+gives independent validators the same corpus boundary.
+
+**Non-goals and safety boundary.** This proposal does not standardize BRAN's scanner,
+knowledge-candidate predicate, byte limits, file-count limits, or security policy. It
+does not declare neighboring files safe or exempt them from repository security scans.
+OKF conformance validation and whole-repository security analysis remain separate
+operations.
+
+**Recommended contribution vehicle.** Submit a small specification pull request because
+this clarifies the existing rule that a bundle may be a subdirectory rather than adding
+a new document shape.
+
+### UPSTREAM-2 — Layered profile separation
+
+**Problem.** OKF intentionally defines a permissive interoperability floor. Organizations
+still need stronger readiness, governance, freshness, source-integrity, and
+public-boundary policies. Without profile-reporting guidance, an implementation can
+collapse a stricter organizational failure into a generic failure and incorrectly imply
+that a portable OKF bundle is nonconformant.
+
+**Required outcome separation.** A bundle can legitimately produce two independent
+results:
+
+```text
+OKF v0.1:    PASS
+BRAN Strict: FAIL — missing public_boundary
+```
+
+This means the bundle satisfies the portable format floor but is not ready under one
+implementation's organizational policy. `bran-strict` remains a BRAN profile; it is not
+proposed as an upstream OKF profile.
+
+**Recommended normative direction.** After maintainer discussion, add a short rule to
+the conformance section:
+
+> Implementations MAY provide additional validation profiles beyond OKF conformance.
+> Such profiles MUST report their outcomes separately. Failure of an
+> implementation-specific profile MUST NOT be described as OKF nonconformance when the
+> bundle satisfies the selected OKF version.
+
+**Benefits.** Implementations can add security or operational readiness checks without
+fragmenting the portable format. Producers retain exchange compatibility, consumers can
+distinguish interoperability from organizational readiness, and vendor-specific policy
+cannot silently redefine OKF conformance.
+
+**Non-goals.** This proposal does not standardize `bran-strict`, require organizations to
+offer a strict profile, create a central profile registry, or add BRAN policy fields to
+OKF. Profile identifiers, policy contents, and enforcement mechanisms remain
+implementation-owned.
+
+**Recommended contribution vehicle.** Open a design issue first because profile
+separation adds normative reporting guidance. Draft a small conformance-section pull
+request only after upstream maintainers agree with the distinction.
+
+### Recommended timing
+
+Draft both contributions now, but approach upstream after BRAN is publicly inspectable.
+Before publication, close BRAN's reserved `index.md` and `log.md` validation gap and
+describe the current `okf-v0.1` result only as the OKF v0.1 concept-document
+interoperability floor. Then:
+
+1. publish a stable BRAN release with accurate conformance claims and reproducible tests;
+2. submit `UPSTREAM-1` as a narrow specification clarification;
+3. open `UPSTREAM-2` as a design issue;
+4. submit profile-separation wording only after maintainer agreement.
+
+A public implementation gives maintainers inspectable evidence, while separating the
+two contributions keeps discussion, review, and disposition independent. Every external
+issue, pull request, comment, branch push, or publication still requires the owner's
+explicit approval of the exact text, repository, and destination.
+
seit.md
---
+type: seit
+name: bran-okf-migration
+status: amended
+date: 2026-07-21
+applies_to: bran
+plan_spec: ./plan-spec.md
+design: ./design.md
+---
+
+## Scope
+
+Verification covers the BRAN-native repository policy, strict validation,
+deterministic retrieval precedence, maintenance proposal/apply/revalidate lifecycle,
+derived-state self-healing, legacy command/configuration translation, preserved hook
+behavior, per-consumer parity evidence, and evidence-based adapter retirement.
+
+The release-blocking baseline is offline and deterministic. Public publication,
+installation from a public release, live provider use, direct migration of consumer
+repositories, and final removal of adapters are separate owner-authorized actions.
+
+## Required References
+
+- `./plan-spec.md` - AC-1 through AC-7, RISK-1 through RISK-5, and owner decisions.
+- `./design.md` - DES-1 through DES-8 and CONTRACT-1 through CONTRACT-9.
+- `/home/spectre/alphazede/bran/AGENTS.md` - private BRAN boundary and integrated check.
+- `/home/spectre/alphazede/bran/docs/plans/AGENTS.md` - plan ownership and publication boundary.
+- `/home/spectre/alphazede/bran/crates/bran-core/src/profile.rs` - current dual-profile validation.
+- `/home/spectre/alphazede/bran/crates/bran-core/src/repair/mod.rs` - current repair state machine.
+- `/home/spectre/alphazede/bran/crates/bran-core/src/graph/query.rs` - current retrieval precedence.
+- `/home/spectre/alphazede/bran/crates/bran-cli/src/main.rs` - current command envelope and typed exits.
+- `/home/spectre/alphazede/Alphazedehq/tools/okf/okf` - compatibility command surface.
+- `/home/spectre/alphazede/Alphazedehq/tools/okf/config.yaml` - legacy configuration input.
+- `/home/spectre/alphazede/Alphazedehq/.grok/hooks/use-okf.sh` and
+  `use-okf.json` - hook behavior to preserve.
+
+## Required Commands
+
+Commands marked planned are created by the implementation and must exist before their
+mapped proof row can pass.
+
+- **CMD-POLICY** - planned: `cargo test --manifest-path /home/spectre/alphazede/bran/Cargo.toml -p bran-core repository_policy`
+- **CMD-PROFILE** - `cargo test --manifest-path /home/spectre/alphazede/bran/Cargo.toml -p bran-core profile::tests`
+- **CMD-QUERY** - `cargo test --manifest-path /home/spectre/alphazede/bran/Cargo.toml -p bran-core graph::query::tests`
+- **CMD-PACKET** - `cargo test --manifest-path /home/spectre/alphazede/bran/Cargo.toml -p bran-core packet::tests`
+- **CMD-MIGRATION** - planned: `cargo test --manifest-path /home/spectre/alphazede/bran/Cargo.toml -p bran-core migration::tests`
+- **CMD-SCAN** - `cargo test --manifest-path /home/spectre/alphazede/bran/Cargo.toml -p bran-core scan::tests`
+- **CMD-REPAIR** - `cargo test --manifest-path /home/spectre/alphazede/bran/Cargo.toml -p bran-core repair::tests`
+- **CMD-CLI** - `cargo test --manifest-path /home/spectre/alphazede/bran/Cargo.toml -p bran-cli maintain`
+- **CMD-DERIVED** - planned: `cargo test --manifest-path /home/spectre/alphazede/bran/Cargo.toml -p bran-core derived_state_rebuild`
+- **CMD-ADAPTER** - `python3 /home/spectre/alphazede/Alphazedehq/tools/okf/test_bran_runtime.py`
+- **CMD-HOOK** - `/home/spectre/alphazede/Alphazedehq/.grok/hooks/test-use-okf.sh`
+- **CMD-FAST** - `/home/spectre/alphazede/bran/tools/ci/check.sh --fast`
+- **CMD-PUBLIC** - `python3 /home/spectre/alphazede/bran/tools/ci/public_boundary_check.py`
+- **PROC-PARITY** - For each active consumer, run the pinned BRAN native validation and
+  retrieval corpus, run the legacy adapter against the identical frozen inputs, normalize
+  semantic results, retain the diff receipt, and do not mutate the consumer.
+- **PROC-REFERENCES** - Search active code, skill, hook, CI, and configuration surfaces for
+  `use-okf`, `tools/okf/okf`, and `tools/okf/config.yaml`; classify historical-only hits and
+  retain the repository-relative audit.
+- **PROC-PIN** - Build BRAN locally, compute and record its checksum, install only at the
+  owner-approved stable local path, and verify the invoked binary matches the pin before
+  shadow or hook use.
+- **PROC-ROLLBACK** - In a disposable fixture, preserve target bytes and file-existence state,
+  force validator failure after staged apply, and compare restored state byte-for-byte with
+  the pre-apply state and receipt lifecycle.
+- **PROC-PUBLICATION** - Inspect proposed public files and release assets for private plans,
+  corpora, credentials, auth state, internal paths, hidden grader truth, and unsupported
+  claims; publication remains blocked without explicit owner approval.
+
+## CI Stage Inventory
+
+| Stage | Backing command/procedure | State | Gate |
+| --- | --- | --- | --- |
+| Native policy contracts | CMD-POLICY, CMD-PROFILE | planned plus active baseline | required |
+| Retrieval precedence | CMD-QUERY | active, expanded fixtures planned | required |
+| Repair lifecycle | CMD-REPAIR, CMD-CLI, PROC-ROLLBACK | active, production authority expansion planned | required |
+| Derived-state self-heal | CMD-DERIVED | planned | required |
+| BRAN integrated fast gate | CMD-FAST | active | required |
+| Compatibility adapter | CMD-ADAPTER | active, parity expansion planned | required while adapter exists |
+| Hook characterization | CMD-HOOK | active, BRAN-backed cases planned | required while hooks exist |
+| Consumer parity | PROC-PARITY | planned per consumer | required for that consumer's retirement |
+| Active-reference audit | PROC-REFERENCES | planned per consumer and global | required for retirement |
+| Public boundary | CMD-PUBLIC, PROC-PUBLICATION | active plus manual release review | required before publication |
+
+Missing optional telemetry does not make a stage fail. A required stage fails only on
+its semantic contract, executable error, unauthorized mutation, containment breach,
+unsupported evidence, or genuine material error.
+
+## Integration Test Procedures
+
+### IT-1 - Native policy and deterministic validation
+
+1. Load valid `.bran/policy.yaml` fixtures and verify the normalized policy and stable
+   schema version.
+2. Exercise missing, malformed, unsupported-version, unknown-field, duplicate path,
+   overlapping classification, unsafe path, status/tag, source-link, and public-boundary
+   fixtures.
+3. Run the same fixture repeatedly and under permuted source discovery order.
+4. Require byte-identical ordered diagnostic identities and matching typed exits.
+
+### IT-2 - Legacy translation and semantic parity
+
+1. Freeze legacy `tools/okf/config.yaml` inputs for every supported field and edge case.
+2. Translate to the immutable native policy without creating or rewriting repository files.
+3. Run legacy and native validation/retrieval over identical corpus identities.
+4. Compare normalized rule, locator, classification, source-precedence, and terminal
+   outcomes; retain formatting-only differences separately from semantic differences.
+5. Verify absent telemetry is represented as unavailable and does not alter parity success.
+
+### IT-3 - Hook fail-open behavior
+
+1. Exercise SessionStart, relevant/irrelevant prompt, relevant/irrelevant edit, and dynamic
+   repository discovery.
+2. Exercise valid pin, missing binary, checksum mismatch, timeout, malformed output,
+   validation findings, and unwritable optional receipt directory.
+3. Require bounded compact output, no repository source writes, and exit zero for every hook
+   event.
+4. Run explicit validation separately and prove that genuine findings still exit non-zero.
+
+### IT-4 - Repair authority and recovery
+
+1. Prove proposal is read-only and captures exact absent/present original state.
+2. Reject blank authority, wrong digest, stale same-length edits, traversal, absolute/NUL
+   paths, symlink ancestors, and targets outside the repository root before mutation.
+3. Exercise a successful staged write and require validation-passed receipt only after native
+   revalidation.
+4. Force validation failure for existing and newly created files; require exact restoration
+   and validation-failed/restored receipt.
+5. Force staged-write and rollback I/O failures; require operation/partial-write uncertainty,
+   retained recovery evidence, and no false success.
+
+### IT-5 - Derived-state self-healing
+
+1. Corrupt or remove BRAN-owned index, cache, snapshot, report, and generated validator
+   artifact fixtures.
+2. Rebuild each from unchanged source/policy and compare deterministic output.
+3. Present source, metadata, classification, configuration, and source-link targets to the
+   auto-rebuilder and require refusal plus a proposal-only result.
+4. Verify rebuild failure preserves the prior usable derived artifact when one exists.
+
+### IT-6 - Consumer migration and retirement
+
+1. Inventory Alphazedehq, alphazede-sports, betbot, developers, hgts, and
+   alphazede-markets independently.
+2. Verify the checksum-pinned local BRAN build before any shadow run.
+3. Retain policy identity, corpus identity, BRAN pin, semantic parity result, missing fields,
+   and active-reference audit for each consumer.
+4. Mark only consumers with native policy, BRAN-backed skill/hook, passing parity, and no
+   active legacy reference eligible for retirement.
+5. Prove a failed consumer does not change completed consumer evidence, and global removal
+   remains blocked until all consumers pass and the owner approves.
+
+## Traceability Matrix
+
+| SEIT row ID | Acceptance/risk ID | Design/contract ID | Boundary/test layer | Positive case | Negative/failure case | Command/procedure ID | Evidence |
+| --- | --- | --- | --- | --- | --- | --- | --- |
+| SEIT-1 | AC-1 | DES-4, CONTRACT-1 | adapter contract | old call reaches native behavior | adapter implements divergent rule | CMD-ADAPTER | normalized invocation/result fixture |
+| SEIT-2 | AC-2 | DES-1, DES-8, CONTRACT-3 | core policy/schema | valid native policy passes | malformed/version/path rule fails typed | CMD-POLICY | policy fixture and ordered diagnostics |
+| SEIT-3 | AC-2 | DES-2 | core validation | strict categories pass | frontmatter/source/public violation fails | CMD-PROFILE | dual-profile outcomes and exits |
+| SEIT-4 | AC-3 | DES-3, CONTRACT-2 | repair unit/CLI | exact authorized proposal applies | blank authority or wrong digest refused | CMD-REPAIR, CMD-CLI | terminal-state and mutation trace |
+| SEIT-5 | AC-4 | DES-6, CONTRACT-2, CONTRACT-9 | recovery integration | revalidation passes after stage | validator failure restores exact state | PROC-ROLLBACK | before/after digest and receipt |
+| SEIT-6 | AC-5 | DES-4, CONTRACT-7 | retrieval parity | stronger canonical source wins | permuted/tied input changes outcome | CMD-QUERY, PROC-PARITY | ordered canonical ranks and semantic diff |
+| SEIT-7 | AC-6 | DES-3, DES-5, CONTRACT-9 | mutation security | owned derived rebuild succeeds | source/config auto-rewrite refused | CMD-DERIVED, CMD-REPAIR | path class and write-set receipt |
+| SEIT-8 | AC-7 | DES-7, CONTRACT-5 | migration acceptance | all consumer evidence complete | active legacy reference blocks removal | PROC-PARITY, PROC-REFERENCES | six-consumer matrix and owner decision slot |
+| SEIT-9 | RISK-1 | DES-6, DES-7, CONTRACT-5 | migration isolation | completed consumer remains complete | one mismatch invalidates global evidence | PROC-PARITY | independent consumer states |
+| SEIT-10 | RISK-2 | DES-6, CONTRACT-4 | hook integration | three triggers invoke bounded BRAN | unavailable/timeout blocks agent | CMD-HOOK | exit codes, timings, write audit |
+| SEIT-11 | RISK-3 | DES-5 | release boundary | approved scrubbed artifact remains separate | private material enters proposed release | CMD-PUBLIC, PROC-PUBLICATION | boundary report and approval status |
+| SEIT-12 | RISK-4 | DES-1, DES-8, CONTRACT-3 | interface/schema | native version round-trips | implicit/legacy schema becomes authority | CMD-POLICY | schema fixture and adapter no-write audit |
+| SEIT-13 | RISK-5 | DES-7, CONTRACT-5, CONTRACT-8 | evidence/observability | partial metrics retained | missing metric declares no result | PROC-PARITY | receipt with explicit unavailable fields |
+| SEIT-14 | AC-3, AC-6 | DES-5, CONTRACT-2 | security negative | root-relative regular target accepted | traversal/symlink/stale input mutates | CMD-REPAIR | pre-write path and stale checks |
+| SEIT-15 | AC-1, AC-7 | DES-7 | supply/release identity | invoked BRAN matches checksum pin | unpinned/replaced binary is used | PROC-PIN | artifact checksum and invocation receipt |
+| SEIT-16 | AC-2, RISK-4 | DES-9, CONTRACT-3 | CLI policy input | file and stdin policies produce identical ordered results | missing, conflicting, oversized, malformed, or secret-bearing stdin is accepted or logged | CMD-POLICY, CMD-CLI | input-source identity, typed exit, ordered diagnostics, no-write audit |
+| SEIT-17 | AC-1, AC-5, AC-7 | DES-10, CONTRACT-10 | legacy semantic parity | coverage, metadata, sources, boundaries, packets, and body-preservation outcomes match | adapter drops an affecting field or owns a rule | CMD-POLICY, CMD-PROFILE, CMD-PACKET, CMD-MIGRATION, CMD-ADAPTER, PROC-PARITY | normalized per-contract diff and unsupported-field receipt |
+| SEIT-18 | AC-1, AC-2, AC-7, RISK-4 | DES-11, CONTRACT-11 | native parser and adapter serialization | apostrophes, quotes, backslashes, hashes, colons, and surrounding spaces round-trip identically through file and stdin policy sources | malformed delimiters, unsupported escapes, controls, secret-bearing duplicates, or arbitrary child output are accepted, changed, or echoed | CMD-POLICY, CMD-CLI, CMD-ADAPTER | native parser regression output, adapter sentinel output, real-binary envelope, and no-write audit |
+| SEIT-19 | AC-1, AC-2, AC-7, RISK-4 | DES-12, CONTRACT-12 | scanner input classification | oversized PNG and NUL-bearing binary are bounded-probed, reported unsupported, and do not prevent both profiles from evaluating | oversized valid UTF-8 text, symlink escape, changing file, or binary prefix ambiguity bypasses limits or is fully buffered | CMD-SCAN, CMD-CLI, CMD-ADAPTER | focused scan tests, read/byte accounting, both selected-profile envelopes, and no-write snapshot |
+| SEIT-20 | AC-1, AC-2, AC-7, RISK-4 | DES-13, CONTRACT-13 | native check scan scope | oversized generated non-candidate text is unopened and both profiles evaluate | oversized admitted Markdown, filtered/full mismatch, or a non-check scanner silently drops source text | CMD-SCAN, CMD-CLI, CMD-ADAPTER | shared-predicate unit tests, generic-scanner regression, both selected-profile envelopes, and no-write snapshot |
+
+## Cross-cutting Checks
+
+- Determinism: repeat and permute discovery order; compare semantic output identities.
+- Mutation containment: snapshot the fixture tree before and after every read-only, parity,
+  and hook case.
+- Public/private boundary: scan sources, fixtures, receipts, logs, and proposed artifacts.
+- Unsupported evidence: every cited locator must exist in the frozen corpus; unavailable
+  evidence is explicit.
+- Partial telemetry: preserve present values and mark absent values unavailable without
+  changing semantic validation or task status.
+- Compatibility: native BRAN is the only rule owner; adapters are characterized until
+  evidence-based retirement.
+- Recovery: successful rollback is byte-exact; uncertain rollback cannot report success.
+
+## Optional / Unavailable Tools
+
+- Live provider or network evaluation is unavailable by design and unnecessary.
+- Public release installation is deferred until owner-authorized publication.
+- A centralized telemetry backend is not required; deterministic local receipts suffice.
+- Consumer CI that is unavailable during a migration run is recorded as unavailable; native
+  fixture parity and later repository CI evidence remain separately visible.
+
+## Gate Evidence
+
+Retain command, exact BRAN commit and artifact checksum, policy/corpus identity, exit code,
+structured output, fixture mutation audit, and normalized semantic diff for every required
+row. Required evidence is prospective until implementation executes it. No future success is
+claimed in this design pass.
+
+Pre-implementation readiness requires all planned commands to exist, SEIT-1 through SEIT-17
+to have an implementation owner, `CMD-FAST` to pass on the integrated BRAN diff, compatibility
+tests to pass in their owning repository, and publication to remain unperformed unless the
+owner separately authorizes it.
+
+## SEIT Amendments
+
+### 2026-07-22 owner-approved amendment
+
+The owner approved an additive native `--policy-stdin` source and incorporation of
+semantic legacy OKF capabilities missing from BRAN. SEIT-16 and SEIT-17 cover the new
+input boundary and product-parity obligations. No provider, publication, deployment,
+consumer mutation, legacy removal, or dependency-install authority was added.
+
+### 2026-07-22 delegated native quoted-scalar amendment
+
+The owner delegated bounded product-quality decisions during execution. A real adapter
+invocation proved that standard YAML apostrophe escaping was not decoded by BRAN, and a
+sentinel proved that an adapter error echoed a raw excluded-document path. SEIT-18
+requires the smallest parser and adapter repair plus direct real-binary proof before
+Slice 3.1 can complete.
+
+### 2026-07-22 oversized binary scan-isolation amendment
+
+The unchanged AlphaZedeHQ corpus reached native policy parsing but aborted before profile
+selection on an unrelated oversized PNG. SEIT-19 requires bounded binary classification,
+preserves hard limits for oversized UTF-8 text, and proves that both canonical profiles
+evaluate the unchanged corpus without consumer mutation.
+
+### 2026-07-22 check-time knowledge-candidate amendment
+
+After binary isolation, the unchanged corpus reached an oversized generated
+`review.html` that the native check bundle cannot consume. SEIT-20 aligns only the check-
+time scanner with its existing knowledge-candidate predicate while preserving the
+general-purpose scanner, all accepted Markdown limits, and adapter translation-only
+ownership.
+
implementation.md
---
+type: implementation
+name: bran-okf-migration
+status: draft
+date: 2026-07-21
+plan_spec: ./plan-spec.md
+design: ./design.md
+seit: ./seit.md
+---
+
+# Implementation - BRAN OKF Migration
+
+This is a pipeline plan. Waves are sequential because later compatibility work
+consumes the native BRAN policy, validation, repair, and receipt contracts. All
+slices use the existing Pi route for `deepseek-v4-pro`. Publication, release,
+consumer-repository mutation, and legacy removal are outside this execution authority.
+
+The integrated closeout runs `CMD-FAST` once after all code-bearing slices and uses
+the repository's native read-only review on the integrated diff. `CMD-FAST` remains a
+cross-cutting repository gate rather than a slice-owned semantic proof.
+
+## Wave 1 - Native BRAN ownership
+
+Wave 1 establishes the native policy and deterministic core behavior. Its slices are
+sequential because they share the core module registry and normalized policy contract.
+
+### Slice 1.1 — Native repository policy
+
+**Goal.** Add the versioned BRAN repository-policy model, loader, schema, and frozen fixtures.
+
+**Requirement IDs.** AC-2, RISK-4
+
+**Design IDs.** DES-1, DES-8, CONTRACT-3
+
+**SEIT proof rows.** SEIT-2, SEIT-12
+
+**Type.** /tdd
+
+**Design lenses.** CDD, SecDD
+
+**Implementation role.** Rust policy and schema maintainer
+
+**Agent model route.** Pi (deepseek-v4-pro)
+
+**Agent reasoning level.** high
+
+**Ponytail mode.** full
+
+**Review path.** Focused tests followed by the BRAN native read-only review on the integrated diff.
+
+### 1.1 execution manifest
+
+**Write set.** Only `crates/bran-core/src/policy.rs`, `crates/bran-core/src/lib.rs`, `schemas/bran-repository-policy.schema.json`, `fixtures/policy/valid-v1.yaml`, `fixtures/policy/invalid-version.yaml`, and `fixtures/policy/unsafe-path.yaml`.
+
+**Command IDs.** CMD-POLICY
+
+**Stop condition.** Stop on a schema decision that contradicts DES-8 or requires consumer-source mutation.
+
+**Human decision.** None; ask before changing the selected policy path or serialization.
+
+### Slice 1.2 — Strict validation and retrieval parity
+
+**Goal.** Make native policy drive strict validation, preserve deterministic source precedence,
+reject active packet references to superseded prompts, and verify migration body preservation.
+
+**Requirement IDs.** AC-2, AC-5
+
+**Design IDs.** DES-2, DES-4, DES-10, CONTRACT-7
+
+**SEIT proof rows.** SEIT-3, SEIT-6, SEIT-17
+
+**Type.** /tdd
+
+**Design lenses.** CDD, SecDD, RDD
+
+**Implementation role.** Rust validation and retrieval maintainer
+
+**Agent model route.** Pi (deepseek-v4-pro)
+
+**Agent reasoning level.** high
+
+**Ponytail mode.** full
+
+**Review path.** Focused tests followed by the BRAN native read-only review on the integrated diff.
+
+### 1.2 execution manifest
+
+**Write set.** Only `crates/bran-core/src/profile.rs`, `crates/bran-core/src/graph/query.rs`,
+`crates/bran-core/src/packet/mod.rs`, `crates/bran-core/src/migration.rs`,
+`crates/bran-core/src/lib.rs`, and `fixtures/conformance/bran-policy-parity.fixture`.
+
+**Command IDs.** CMD-PROFILE, CMD-QUERY, CMD-PACKET, CMD-MIGRATION, PROC-PARITY
+
+**Stop condition.** Stop if compatibility requires duplicating native rules in an adapter or changing established retrieval precedence.
+
+**Human decision.** None; ask before weakening a public/private or source-precedence rule.
+
+### Slice 1.3 — Derived-state self-healing
+
+**Goal.** Rebuild only BRAN-owned derived artifacts while refusing automatic source or policy repair.
+
+**Requirement IDs.** AC-6
+
+**Design IDs.** DES-3, DES-5, CONTRACT-9
+
+**SEIT proof rows.** SEIT-7
+
+**Type.** /tdd
+
+**Design lenses.** SecDD, RDD
+
+**Implementation role.** Rust maintenance-state maintainer
+
+**Agent model route.** Pi (deepseek-v4-pro)
+
+**Agent reasoning level.** high
+
+**Ponytail mode.** full
+
+**Review path.** Focused tests followed by the BRAN native read-only review on the integrated diff.
+
+### 1.3 execution manifest
+
+**Write set.** Only `crates/bran-core/src/derived_state.rs`, `crates/bran-core/src/lib.rs`, and `fixtures/derived-state/rebuild-v1.json`.
+
+**Command IDs.** CMD-DERIVED, CMD-REPAIR
+
+**Stop condition.** Stop if a proposed automatic action targets source, metadata, classification, configuration, or source links.
+
+**Human decision.** None; explicit authority is required for any non-derived repair proposal.
+
+## Wave 2 - Authorized repair and CLI contracts
+
+Wave 2 consumes the native validator from Wave 1 and closes the source-mutation
+boundary before any compatibility surface can invoke maintenance behavior.
+
+### Slice 2.1 — Repair and maintenance lifecycle
+
+**Goal.** Complete production-safe proposal, authority, digest, staged apply, revalidation,
+rollback, receipt, typed-exit behavior, and bounded native policy input from stdin.
+
+**Requirement IDs.** AC-3, AC-4, AC-6
+
+**Design IDs.** DES-3, DES-5, DES-6, DES-9, CONTRACT-2, CONTRACT-3, CONTRACT-9
+
+**SEIT proof rows.** SEIT-4, SEIT-5, SEIT-7, SEIT-14, SEIT-16
+
+**Type.** /tdd
+
+**Design lenses.** CDD, SecDD, RDD, ODD
+
+**Implementation role.** Rust repair and CLI security maintainer
+
+**Agent model route.** Pi (deepseek-v4-pro)
+
+**Agent reasoning level.** high
+
+**Ponytail mode.** full
+
+**Review path.** Focused fault tests followed by the BRAN native read-only review on the integrated diff.
+
+### 2.1 execution manifest
+
+**Write set.** Only `crates/bran-core/src/repair/mod.rs`, `crates/bran-cli/src/main.rs`, and `fixtures/repair/rollback-v1.json`.
+
+**Command IDs.** CMD-REPAIR, CMD-CLI, CMD-DERIVED, CMD-POLICY, PROC-ROLLBACK
+
+**Stop condition.** Stop on any false-success state, uncertain rollback without explicit terminal evidence, or inferred mutation authority.
+
+**Human decision.** None; ask before introducing a new authority source or widening mutation targets.
+
+## Wave 3 - AlphaZedeHQ staged adoption
+
+Wave 3 updates the canonical internal skill, shared compatibility tool, and hooks.
+These slices are sequential because they share the adapter invocation and pinned binary.
+No consumer repository is migrated or rewritten in this wave.
+
+### Slice 3.1 — BRAN skill and shared compatibility adapter
+
+**Goal.** Make BRAN the canonical internal knowledge workflow while retaining deprecated OKF entrypoints as translation-only adapters.
+
+**Requirement IDs.** AC-1, AC-7
+
+**Design IDs.** DES-4, DES-7, DES-10, DES-11, DES-12, DES-13, CONTRACT-1, CONTRACT-5, CONTRACT-10, CONTRACT-11, CONTRACT-12, CONTRACT-13
+
+**SEIT proof rows.** SEIT-1, SEIT-8, SEIT-17, SEIT-18, SEIT-19, SEIT-20
+
+**Type.** /tdd
+
+**Design lenses.** CDD, RDD, ODD
+
+**Implementation role.** Rust/Python policy interoperability and agent-skill maintainer
+
+**Agent model route.** Pi (deepseek-v4-pro)
+
+**Agent reasoning level.** high
+
+**Ponytail mode.** full
+
+**Review path.** AlphaZedeHQ focused tests plus native read-only review of the cross-repository integrated diff.
+
+### 3.1 execution manifest
+
+**Write set.** Only `/home/spectre/alphazede/bran/crates/bran-core/src/policy.rs`, `/home/spectre/alphazede/bran/crates/bran-core/src/scan/mod.rs`, `/home/spectre/alphazede/bran/crates/bran-cli/src/main.rs`, `/home/spectre/alphazede/Alphazedehq/skills/use-bran/SKILL.md`, `/home/spectre/alphazede/Alphazedehq/skills/use-okf/SKILL.md`, `/home/spectre/alphazede/Alphazedehq/tools/okf/okf`, `/home/spectre/alphazede/Alphazedehq/tools/okf/bran_runtime.py`, and `/home/spectre/alphazede/Alphazedehq/tools/okf/test_bran_runtime.py`. Keep the bounded BRAN parser/scanner packets and dependent AlphaZedeHQ adapter packet sequential in their respective task worktrees.
+
+**Command IDs.** CMD-POLICY, CMD-SCAN, CMD-CLI, CMD-ADAPTER, PROC-PARITY, PROC-REFERENCES
+
+**Stop condition.** Stop if the adapter becomes a semantic rule owner, rewrites legacy configuration, or retires an entrypoint without AC-7 evidence.
+
+**Human decision.** None; publication and final legacy removal remain owner decisions.
+
+### Slice 3.2 — BRAN-backed fail-open hooks
+
+**Goal.** Preserve the existing trigger and timeout behavior through a native BRAN hook with deprecated OKF forwarding compatibility.
+
+**Requirement IDs.** AC-1, RISK-2
+
+**Design IDs.** DES-4, DES-6, CONTRACT-1, CONTRACT-4
+
+**SEIT proof rows.** SEIT-1, SEIT-10
+
+**Type.** /tdd
+
+**Design lenses.** CDD, SecDD, RDD, ODD
+
+**Implementation role.** Shell hook and compatibility maintainer
+
+**Agent model route.** Pi (deepseek-v4-pro)
+
+**Agent reasoning level.** high
+
+**Ponytail mode.** full
+
+**Review path.** AlphaZedeHQ shell fixtures plus native read-only review of the cross-repository integrated diff.
+
+### 3.2 execution manifest
+
+**Write set.** Only `/home/spectre/alphazede/Alphazedehq/.grok/hooks/use-bran.sh`, `/home/spectre/alphazede/Alphazedehq/.grok/hooks/use-bran.json`, `/home/spectre/alphazede/Alphazedehq/.grok/hooks/test-use-bran.sh`, `/home/spectre/alphazede/Alphazedehq/.grok/hooks/use-okf.sh`, `/home/spectre/alphazede/Alphazedehq/.grok/hooks/use-okf.json`, `/home/spectre/alphazede/Alphazedehq/.grok/hooks/test-use-okf.sh`, and `/home/spectre/alphazede/Alphazedehq/.grok/hooks/README.md`.
+
+**Command IDs.** CMD-HOOK, CMD-ADAPTER
+
+**Stop condition.** Stop if any hook path blocks agent completion, performs source mutation, retries maintenance, or trusts a target-repository executable.
+
+**Human decision.** None; strict behavior remains limited to explicit validation and configured CI.
+
+### Slice 3.3 — Pinned local adoption and boundary check
+
+**Goal.** Verify the exact local BRAN artifact used by the adapter and hooks while preserving the publication boundary.
+
+**Requirement IDs.** AC-1, AC-7, RISK-3
+
+**Design IDs.** DES-5, DES-7
+
+**SEIT proof rows.** SEIT-11, SEIT-15
+
+**Type.** manual
+
+**Design lenses.** SecDD, ODD
+
+**Implementation role.** Local release provenance operator
+
+**Agent model route.** Pi (deepseek-v4-pro)
+
+**Agent reasoning level.** high
+
+**Ponytail mode.** off
+
+**Review path.** Checksum readback, public-boundary evidence, and native read-only review; no publication review is implied.
+
+### 3.3 execution manifest
+
+**Write set.** No committed repository writes. Owner-approved local runtime artifacts under `/home/spectre/alphazede/Alphazedehq/tools/okf/runtime/` may be created by the adoption procedure. On 2026-07-22 the owner explicitly authorized an uncommitted local `tools/okf/runtime/bran-release-pin.json` even though that path is trackable rather than ignored. The exception permits local pin verification only; the pin must remain uncommitted and does not authorize promotion, publication, push, or deployment.
+
+**Command IDs.** CMD-PUBLIC, PROC-PIN, PROC-PUBLICATION
+
+**Stop condition.** Stop on checksum mismatch, path aliasing, private-boundary leakage, or any action that would publish or promote an artifact.
+
+**Human decision.** Explicit owner approval is required before publication, release, promotion, or public install verification.
+
+## Wave 4 - Consumer evidence and closeout
+
+Wave 4 is read-only. It measures the six active consumers independently and preserves
+incomplete evidence without mutating their source, configuration, hooks, or CI.
+
+### Slice 4.1 — Six-consumer parity and retirement inventory
+
+**Goal.** Produce independent parity and active-reference evidence without prematurely removing compatibility.
+
+**Requirement IDs.** AC-7, RISK-1, RISK-5
+
+**Design IDs.** DES-7, CONTRACT-5, CONTRACT-8
+
+**SEIT proof rows.** SEIT-8, SEIT-9, SEIT-13
+
+**Type.** manual
+
+**Design lenses.** CDD, RDD, ODD
+
+**Implementation role.** Repository migration evidence auditor
+
+**Agent model route.** Pi (deepseek-v4-pro)
+
+**Agent reasoning level.** high
+
+**Ponytail mode.** off
+
+**Review path.** Read-only evidence review followed by the BRAN native integrated-diff review.
+
+### 4.1 execution manifest
+
+**Write set.** No writes required; evidence is retained in the execution transcript until a separately authorized evidence path is approved.
+
+**Command IDs.** PROC-PARITY, PROC-REFERENCES
+
+**Stop condition.** Stop on corpus mismatch, attempted consumer mutation, unsupported parity claim, or loss of completed per-consumer evidence.
+
+**Human decision.** Owner approval is required for every consumer migration and for final global adapter removal.
+
+## Execution closeout
+
+After Wave 4, run `CMD-FAST` once against the integrated BRAN diff and the focused
+AlphaZedeHQ commands referenced by Wave 3. Run one native read-only review across the
+integrated BRAN and AlphaZedeHQ diffs. Do not run a provider evaluation, publish BRAN,
+promote a release, modify the six consumer repositories, or remove legacy adapters.
+
+If implementation exposes only missing proof coverage, append a SEIT-only amendment
+through `design-driven-build`. If it changes policy, authority, compatibility,
+security, or acceptance, stop for the appropriate design amendment.
+
+### Authorization-gated upstream follow-up
+
+After local migration closeout, preserve draft candidates `UPSTREAM-1` (bundle scan
+scope) and `UPSTREAM-2` (strict-profile separation) from `design.md`. Before any GitHub
+issue, pull request, comment, branch push, or other external publication, present the
+exact proposed text and destination to the owner and obtain explicit authorization.
+Upstream contribution work is not part of this eight-slice execution and cannot delay,
+weaken, or reclassify local migration evidence.
+
+Separately plan and authorize complete reserved `index.md`/`log.md` structural validation
+before describing `okf-v0.1` as full upstream conformance certification. Until then,
+describe it as the OKF v0.1 concept-document interoperability floor.
+
+
diff --git a/docs/plans/2026-07-21-bran-okf-migration/seit.md b/docs/plans/2026-07-21-bran-okf-migration/seit.md new file mode 100644 index 0000000..a9ccc1a --- /dev/null +++ b/docs/plans/2026-07-21-bran-okf-migration/seit.md @@ -0,0 +1,243 @@ +--- +type: seit +name: bran-okf-migration +status: amended +date: 2026-07-21 +applies_to: bran +plan_spec: ./plan-spec.md +design: ./design.md +--- + +## Scope + +Verification covers the BRAN-native repository policy, strict validation, +deterministic retrieval precedence, maintenance proposal/apply/revalidate lifecycle, +derived-state self-healing, legacy command/configuration translation, preserved hook +behavior, per-consumer parity evidence, and evidence-based adapter retirement. + +The release-blocking baseline is offline and deterministic. Public publication, +installation from a public release, live provider use, direct migration of consumer +repositories, and final removal of adapters are separate owner-authorized actions. + +## Required References + +- `./plan-spec.md` - AC-1 through AC-7, RISK-1 through RISK-5, and owner decisions. +- `./design.md` - DES-1 through DES-8 and CONTRACT-1 through CONTRACT-9. +- `/home/spectre/alphazede/bran/AGENTS.md` - private BRAN boundary and integrated check. +- `/home/spectre/alphazede/bran/docs/plans/AGENTS.md` - plan ownership and publication boundary. +- `/home/spectre/alphazede/bran/crates/bran-core/src/profile.rs` - current dual-profile validation. +- `/home/spectre/alphazede/bran/crates/bran-core/src/repair/mod.rs` - current repair state machine. +- `/home/spectre/alphazede/bran/crates/bran-core/src/graph/query.rs` - current retrieval precedence. +- `/home/spectre/alphazede/bran/crates/bran-cli/src/main.rs` - current command envelope and typed exits. +- `/home/spectre/alphazede/Alphazedehq/tools/okf/okf` - compatibility command surface. +- `/home/spectre/alphazede/Alphazedehq/tools/okf/config.yaml` - legacy configuration input. +- `/home/spectre/alphazede/Alphazedehq/.grok/hooks/use-okf.sh` and + `use-okf.json` - hook behavior to preserve. + +## Required Commands + +Commands marked planned are created by the implementation and must exist before their +mapped proof row can pass. + +- **CMD-POLICY** - planned: `cargo test --manifest-path /home/spectre/alphazede/bran/Cargo.toml -p bran-core repository_policy` +- **CMD-PROFILE** - `cargo test --manifest-path /home/spectre/alphazede/bran/Cargo.toml -p bran-core profile::tests` +- **CMD-QUERY** - `cargo test --manifest-path /home/spectre/alphazede/bran/Cargo.toml -p bran-core graph::query::tests` +- **CMD-PACKET** - `cargo test --manifest-path /home/spectre/alphazede/bran/Cargo.toml -p bran-core packet::tests` +- **CMD-MIGRATION** - planned: `cargo test --manifest-path /home/spectre/alphazede/bran/Cargo.toml -p bran-core migration::tests` +- **CMD-SCAN** - `cargo test --manifest-path /home/spectre/alphazede/bran/Cargo.toml -p bran-core scan::tests` +- **CMD-REPAIR** - `cargo test --manifest-path /home/spectre/alphazede/bran/Cargo.toml -p bran-core repair::tests` +- **CMD-CLI** - `cargo test --manifest-path /home/spectre/alphazede/bran/Cargo.toml -p bran-cli maintain` +- **CMD-DERIVED** - planned: `cargo test --manifest-path /home/spectre/alphazede/bran/Cargo.toml -p bran-core derived_state_rebuild` +- **CMD-ADAPTER** - `python3 /home/spectre/alphazede/Alphazedehq/tools/okf/test_bran_runtime.py` +- **CMD-HOOK** - `/home/spectre/alphazede/Alphazedehq/.grok/hooks/test-use-okf.sh` +- **CMD-FAST** - `/home/spectre/alphazede/bran/tools/ci/check.sh --fast` +- **CMD-PUBLIC** - `python3 /home/spectre/alphazede/bran/tools/ci/public_boundary_check.py` +- **PROC-PARITY** - For each active consumer, run the pinned BRAN native validation and + retrieval corpus, run the legacy adapter against the identical frozen inputs, normalize + semantic results, retain the diff receipt, and do not mutate the consumer. +- **PROC-REFERENCES** - Search active code, skill, hook, CI, and configuration surfaces for + `use-okf`, `tools/okf/okf`, and `tools/okf/config.yaml`; classify historical-only hits and + retain the repository-relative audit. +- **PROC-PIN** - Build BRAN locally, compute and record its checksum, install only at the + owner-approved stable local path, and verify the invoked binary matches the pin before + shadow or hook use. +- **PROC-ROLLBACK** - In a disposable fixture, preserve target bytes and file-existence state, + force validator failure after staged apply, and compare restored state byte-for-byte with + the pre-apply state and receipt lifecycle. +- **PROC-PUBLICATION** - Inspect proposed public files and release assets for private plans, + corpora, credentials, auth state, internal paths, hidden grader truth, and unsupported + claims; publication remains blocked without explicit owner approval. + +## CI Stage Inventory + +| Stage | Backing command/procedure | State | Gate | +| --- | --- | --- | --- | +| Native policy contracts | CMD-POLICY, CMD-PROFILE | planned plus active baseline | required | +| Retrieval precedence | CMD-QUERY | active, expanded fixtures planned | required | +| Repair lifecycle | CMD-REPAIR, CMD-CLI, PROC-ROLLBACK | active, production authority expansion planned | required | +| Derived-state self-heal | CMD-DERIVED | planned | required | +| BRAN integrated fast gate | CMD-FAST | active | required | +| Compatibility adapter | CMD-ADAPTER | active, parity expansion planned | required while adapter exists | +| Hook characterization | CMD-HOOK | active, BRAN-backed cases planned | required while hooks exist | +| Consumer parity | PROC-PARITY | planned per consumer | required for that consumer's retirement | +| Active-reference audit | PROC-REFERENCES | planned per consumer and global | required for retirement | +| Public boundary | CMD-PUBLIC, PROC-PUBLICATION | active plus manual release review | required before publication | + +Missing optional telemetry does not make a stage fail. A required stage fails only on +its semantic contract, executable error, unauthorized mutation, containment breach, +unsupported evidence, or genuine material error. + +## Integration Test Procedures + +### IT-1 - Native policy and deterministic validation + +1. Load valid `.bran/policy.yaml` fixtures and verify the normalized policy and stable + schema version. +2. Exercise missing, malformed, unsupported-version, unknown-field, duplicate path, + overlapping classification, unsafe path, status/tag, source-link, and public-boundary + fixtures. +3. Run the same fixture repeatedly and under permuted source discovery order. +4. Require byte-identical ordered diagnostic identities and matching typed exits. + +### IT-2 - Legacy translation and semantic parity + +1. Freeze legacy `tools/okf/config.yaml` inputs for every supported field and edge case. +2. Translate to the immutable native policy without creating or rewriting repository files. +3. Run legacy and native validation/retrieval over identical corpus identities. +4. Compare normalized rule, locator, classification, source-precedence, and terminal + outcomes; retain formatting-only differences separately from semantic differences. +5. Verify absent telemetry is represented as unavailable and does not alter parity success. + +### IT-3 - Hook fail-open behavior + +1. Exercise SessionStart, relevant/irrelevant prompt, relevant/irrelevant edit, and dynamic + repository discovery. +2. Exercise valid pin, missing binary, checksum mismatch, timeout, malformed output, + validation findings, and unwritable optional receipt directory. +3. Require bounded compact output, no repository source writes, and exit zero for every hook + event. +4. Run explicit validation separately and prove that genuine findings still exit non-zero. + +### IT-4 - Repair authority and recovery + +1. Prove proposal is read-only and captures exact absent/present original state. +2. Reject blank authority, wrong digest, stale same-length edits, traversal, absolute/NUL + paths, symlink ancestors, and targets outside the repository root before mutation. +3. Exercise a successful staged write and require validation-passed receipt only after native + revalidation. +4. Force validation failure for existing and newly created files; require exact restoration + and validation-failed/restored receipt. +5. Force staged-write and rollback I/O failures; require operation/partial-write uncertainty, + retained recovery evidence, and no false success. + +### IT-5 - Derived-state self-healing + +1. Corrupt or remove BRAN-owned index, cache, snapshot, report, and generated validator + artifact fixtures. +2. Rebuild each from unchanged source/policy and compare deterministic output. +3. Present source, metadata, classification, configuration, and source-link targets to the + auto-rebuilder and require refusal plus a proposal-only result. +4. Verify rebuild failure preserves the prior usable derived artifact when one exists. + +### IT-6 - Consumer migration and retirement + +1. Inventory Alphazedehq, alphazede-sports, betbot, developers, hgts, and + alphazede-markets independently. +2. Verify the checksum-pinned local BRAN build before any shadow run. +3. Retain policy identity, corpus identity, BRAN pin, semantic parity result, missing fields, + and active-reference audit for each consumer. +4. Mark only consumers with native policy, BRAN-backed skill/hook, passing parity, and no + active legacy reference eligible for retirement. +5. Prove a failed consumer does not change completed consumer evidence, and global removal + remains blocked until all consumers pass and the owner approves. + +## Traceability Matrix + +| SEIT row ID | Acceptance/risk ID | Design/contract ID | Boundary/test layer | Positive case | Negative/failure case | Command/procedure ID | Evidence | +| --- | --- | --- | --- | --- | --- | --- | --- | +| SEIT-1 | AC-1 | DES-4, CONTRACT-1 | adapter contract | old call reaches native behavior | adapter implements divergent rule | CMD-ADAPTER | normalized invocation/result fixture | +| SEIT-2 | AC-2 | DES-1, DES-8, CONTRACT-3 | core policy/schema | valid native policy passes | malformed/version/path rule fails typed | CMD-POLICY | policy fixture and ordered diagnostics | +| SEIT-3 | AC-2 | DES-2 | core validation | strict categories pass | frontmatter/source/public violation fails | CMD-PROFILE | dual-profile outcomes and exits | +| SEIT-4 | AC-3 | DES-3, CONTRACT-2 | repair unit/CLI | exact authorized proposal applies | blank authority or wrong digest refused | CMD-REPAIR, CMD-CLI | terminal-state and mutation trace | +| SEIT-5 | AC-4 | DES-6, CONTRACT-2, CONTRACT-9 | recovery integration | revalidation passes after stage | validator failure restores exact state | PROC-ROLLBACK | before/after digest and receipt | +| SEIT-6 | AC-5 | DES-4, CONTRACT-7 | retrieval parity | stronger canonical source wins | permuted/tied input changes outcome | CMD-QUERY, PROC-PARITY | ordered canonical ranks and semantic diff | +| SEIT-7 | AC-6 | DES-3, DES-5, CONTRACT-9 | mutation security | owned derived rebuild succeeds | source/config auto-rewrite refused | CMD-DERIVED, CMD-REPAIR | path class and write-set receipt | +| SEIT-8 | AC-7 | DES-7, CONTRACT-5 | migration acceptance | all consumer evidence complete | active legacy reference blocks removal | PROC-PARITY, PROC-REFERENCES | six-consumer matrix and owner decision slot | +| SEIT-9 | RISK-1 | DES-6, DES-7, CONTRACT-5 | migration isolation | completed consumer remains complete | one mismatch invalidates global evidence | PROC-PARITY | independent consumer states | +| SEIT-10 | RISK-2 | DES-6, CONTRACT-4 | hook integration | three triggers invoke bounded BRAN | unavailable/timeout blocks agent | CMD-HOOK | exit codes, timings, write audit | +| SEIT-11 | RISK-3 | DES-5 | release boundary | approved scrubbed artifact remains separate | private material enters proposed release | CMD-PUBLIC, PROC-PUBLICATION | boundary report and approval status | +| SEIT-12 | RISK-4 | DES-1, DES-8, CONTRACT-3 | interface/schema | native version round-trips | implicit/legacy schema becomes authority | CMD-POLICY | schema fixture and adapter no-write audit | +| SEIT-13 | RISK-5 | DES-7, CONTRACT-5, CONTRACT-8 | evidence/observability | partial metrics retained | missing metric declares no result | PROC-PARITY | receipt with explicit unavailable fields | +| SEIT-14 | AC-3, AC-6 | DES-5, CONTRACT-2 | security negative | root-relative regular target accepted | traversal/symlink/stale input mutates | CMD-REPAIR | pre-write path and stale checks | +| SEIT-15 | AC-1, AC-7 | DES-7 | supply/release identity | invoked BRAN matches checksum pin | unpinned/replaced binary is used | PROC-PIN | artifact checksum and invocation receipt | +| SEIT-16 | AC-2, RISK-4 | DES-9, CONTRACT-3 | CLI policy input | file and stdin policies produce identical ordered results | missing, conflicting, oversized, malformed, or secret-bearing stdin is accepted or logged | CMD-POLICY, CMD-CLI | input-source identity, typed exit, ordered diagnostics, no-write audit | +| SEIT-17 | AC-1, AC-5, AC-7 | DES-10, CONTRACT-10 | legacy semantic parity | coverage, metadata, sources, boundaries, packets, and body-preservation outcomes match | adapter drops an affecting field or owns a rule | CMD-POLICY, CMD-PROFILE, CMD-PACKET, CMD-MIGRATION, CMD-ADAPTER, PROC-PARITY | normalized per-contract diff and unsupported-field receipt | +| SEIT-18 | AC-1, AC-2, AC-7, RISK-4 | DES-11, CONTRACT-11 | native parser and adapter serialization | apostrophes, quotes, backslashes, hashes, colons, and surrounding spaces round-trip identically through file and stdin policy sources | malformed delimiters, unsupported escapes, controls, secret-bearing duplicates, or arbitrary child output are accepted, changed, or echoed | CMD-POLICY, CMD-CLI, CMD-ADAPTER | native parser regression output, adapter sentinel output, real-binary envelope, and no-write audit | +| SEIT-19 | AC-1, AC-2, AC-7, RISK-4 | DES-12, CONTRACT-12 | scanner input classification | oversized PNG and NUL-bearing binary are bounded-probed, reported unsupported, and do not prevent both profiles from evaluating | oversized valid UTF-8 text, symlink escape, changing file, or binary prefix ambiguity bypasses limits or is fully buffered | CMD-SCAN, CMD-CLI, CMD-ADAPTER | focused scan tests, read/byte accounting, both selected-profile envelopes, and no-write snapshot | +| SEIT-20 | AC-1, AC-2, AC-7, RISK-4 | DES-13, CONTRACT-13 | native check scan scope | oversized generated non-candidate text is unopened and both profiles evaluate | oversized admitted Markdown, filtered/full mismatch, or a non-check scanner silently drops source text | CMD-SCAN, CMD-CLI, CMD-ADAPTER | shared-predicate unit tests, generic-scanner regression, both selected-profile envelopes, and no-write snapshot | + +## Cross-cutting Checks + +- Determinism: repeat and permute discovery order; compare semantic output identities. +- Mutation containment: snapshot the fixture tree before and after every read-only, parity, + and hook case. +- Public/private boundary: scan sources, fixtures, receipts, logs, and proposed artifacts. +- Unsupported evidence: every cited locator must exist in the frozen corpus; unavailable + evidence is explicit. +- Partial telemetry: preserve present values and mark absent values unavailable without + changing semantic validation or task status. +- Compatibility: native BRAN is the only rule owner; adapters are characterized until + evidence-based retirement. +- Recovery: successful rollback is byte-exact; uncertain rollback cannot report success. + +## Optional / Unavailable Tools + +- Live provider or network evaluation is unavailable by design and unnecessary. +- Public release installation is deferred until owner-authorized publication. +- A centralized telemetry backend is not required; deterministic local receipts suffice. +- Consumer CI that is unavailable during a migration run is recorded as unavailable; native + fixture parity and later repository CI evidence remain separately visible. + +## Gate Evidence + +Retain command, exact BRAN commit and artifact checksum, policy/corpus identity, exit code, +structured output, fixture mutation audit, and normalized semantic diff for every required +row. Required evidence is prospective until implementation executes it. No future success is +claimed in this design pass. + +Pre-implementation readiness requires all planned commands to exist, SEIT-1 through SEIT-17 +to have an implementation owner, `CMD-FAST` to pass on the integrated BRAN diff, compatibility +tests to pass in their owning repository, and publication to remain unperformed unless the +owner separately authorizes it. + +## SEIT Amendments + +### 2026-07-22 owner-approved amendment + +The owner approved an additive native `--policy-stdin` source and incorporation of +semantic legacy OKF capabilities missing from BRAN. SEIT-16 and SEIT-17 cover the new +input boundary and product-parity obligations. No provider, publication, deployment, +consumer mutation, legacy removal, or dependency-install authority was added. + +### 2026-07-22 delegated native quoted-scalar amendment + +The owner delegated bounded product-quality decisions during execution. A real adapter +invocation proved that standard YAML apostrophe escaping was not decoded by BRAN, and a +sentinel proved that an adapter error echoed a raw excluded-document path. SEIT-18 +requires the smallest parser and adapter repair plus direct real-binary proof before +Slice 3.1 can complete. + +### 2026-07-22 oversized binary scan-isolation amendment + +The unchanged AlphaZedeHQ corpus reached native policy parsing but aborted before profile +selection on an unrelated oversized PNG. SEIT-19 requires bounded binary classification, +preserves hard limits for oversized UTF-8 text, and proves that both canonical profiles +evaluate the unchanged corpus without consumer mutation. + +### 2026-07-22 check-time knowledge-candidate amendment + +After binary isolation, the unchanged corpus reached an oversized generated +`review.html` that the native check bundle cannot consume. SEIT-20 aligns only the check- +time scanner with its existing knowledge-candidate predicate while preserving the +general-purpose scanner, all accepted Markdown limits, and adapter translation-only +ownership. diff --git a/docs/plans/2026-07-22-bran-okf-final-cutover/design.md b/docs/plans/2026-07-22-bran-okf-final-cutover/design.md new file mode 100644 index 0000000..e089c46 --- /dev/null +++ b/docs/plans/2026-07-22-bran-okf-final-cutover/design.md @@ -0,0 +1,619 @@ +--- +type: design +name: bran-okf-final-cutover +status: complete +date: 2026-07-23 +applies_to: bran +plan_spec: ./plan-spec.md +lenses_applied: [CDD, SecDD, RDD, ODD] +lenses_skipped: [BizDD, DDD, EDD, GDD, PDD] +oopdsa: mandatory +planning_route: codex gpt-5.6-sol +planning_reasoning: high +--- + +## Synthesis + +The final cutover is a gated evidence pipeline, not a flag flip. BRAN first +closes its portable conformance and repository gate gaps, then produces an exact +sealed release, then migrates six consumers independently, and only then becomes +eligible for separately approved global compatibility retirement. + +Four rules govern the route: + +1. `okf-v0.1` is the portable result and `bran-strict` is an additive result. + They are computed and reported independently. +2. Release identity is the tuple of source commit, tag, lockfile digest, + platform artifact digests, signer fingerprint, and immutable manifest. +3. A consumer is complete only after exact installation, validation and + retrieval parity, reference audit, and byte/configuration rollback proof. +4. Missing or unavailable evidence is a typed blocked state. It is never + normalized into success. + +The route reuses the staged-migration ownership model: `bran-core` owns policy, +profiles, deterministic scanning, retrieval, and semantic outcomes; `bran-cli` +owns command envelopes; checked-in release tools own build/seal verification; +consumer-local adapters and hooks translate or invoke but do not redefine BRAN +semantics. + +## Approved lens record + +The owner approved CDD, SecDD, RDD, and ODD with mandatory OOPDSA hardening. + +- **CDD** governs profile, receipt, manifest, policy, adapter, and command + contracts. +- **SecDD** governs root containment, public/private policy, signatures, + checksums, symlinks, credentials, publication authority, and rollback. +- **RDD** governs unavailable evidence, interrupted installation, partial + consumer progress, idempotency, recovery, and retirement barriers. +- **ODD** governs deterministic receipts, exact command evidence, claim state, + first-failure diagnostics, and retained provenance. +- **OOPDSA** fixes ownership, state transitions, deterministic collections, + rule precedence, and wave scheduling without adding a framework. + +BizDD, DDD, EDD, GDD, and PDD are skipped because this route adds no business +model, new domain language, event platform, game mechanics, or performance +target. Consumer and policy boundaries are already explicit in the approved +specification. + +## Current evidence and claim state + +Evidence was verified from `/home/spectre/alphazede/bran` on 2026-07-23: + +- `python3 tools/ci/test_budget_check.py tools/ci/test-budget.json` (`CMD-BUDGET`) + currently fails (exits 1) because the existing checker requires per-unit-test + registration against the obsolete fixed ceiling, contradicting the unbuilt target inventory. +- `./tools/ci/check.sh --fast` (`CMD-FAST`) stops at `CMD-BUDGET` first due to this + test budget check failure. +- `python3 tools/ci/public_boundary_check.py` (`CMD-PUBLIC`) failed when run directly + because it resolved `bran/fixtures/...` beneath the BRAN checkout, producing + `/home/spectre/alphazede/bran/bran/fixtures/...`. +- `DocKind` already distinguishes `index.md` and `log.md`, while the portable + profile explicitly applies its current frontmatter/type requirement only to + concept documents. +- Release build, release contract, release seal, schema, and exact-tag fixtures + already exist under `tools/ci/`, `schemas/`, and `fixtures/release/`. + +Therefore: + +- `CMD-BUDGET` and `CMD-FAST` are **currently failing** (test-budget no-ceiling inventory remains **planned and unproven**); +- `CMD-PUBLIC` is **currently failing**; +- reserved-document conformance, publication, consumer parity, and retirement + remain **planned and unproven**; and +- retrieval parity and HGTS remain **unavailable**. + +## Design decisions + +### Shared gates and profile semantics + +- **DES-001 — Independent profile outcomes.** `ProfileValidator` returns a + separate ordered diagnostic set for `okf-v0.1` and `bran-strict`. Selecting + one profile controls the command exit; it does not erase or reclassify the + other result. +- **DES-002 — Normative reserved-document rules.** Portable `index.md` and + `log.md` validation is implemented as an OKF-specific reserved-document + validator invoked only by the `okf-v0.1` path. Its rules and fixtures must + cite the frozen upstream v0.1 source used by the implementation. If the + normative source is unavailable or ambiguous, implementation stops rather + than guessing a portable rule. +- **DES-003 — Deterministic reserved diagnostics.** Reserved-document + diagnostics use stable codes, repository-relative paths, and ordering by + path, code, then message. Strict-only readiness fields remain outside the + portable validator. +- **DES-004 — Budget inventory as fast regression gate.** `tools/ci/test-budget.json` + defines a deterministic inventory of named CI journeys, direct CI commands, and + owned fixtures rather than one registry row per Rust unit test, eliminating fixed + plan, phase, and slice test-count ceilings. `CMD-BUDGET` runs as the first check + in `CMD-FAST`, enforcing deterministic negative evidence (failing on missing or + duplicate journeys, direct commands, or fixture ownership). All Rust unit tests + remain mandatory and fully executed through `CMD-FAST` workspace test commands; + removing per-test registry accounting does not skip or weaken Rust unit test execution. +- **DES-005 — Physical BRAN root for public checks.** `CMD-PUBLIC` derives the + BRAN checkout root from the physical checker path, not the caller's current + directory or an assumed `bran/` parent layout. All enumerated paths and + fixture constants are BRAN-root-relative. Git enumeration is scoped from + that root and rejects absolute, parent-traversal, and symlink escapes. + +### Release, publication, installation, and rollback + +- **DES-006 — Existing exact-release contract is canonical.** Reuse + `build-release.sh`, `release-check.sh`, `release_seal.py`, + `release_contract_check.py`, and + `schemas/bran-release-manifest.schema.json`. Do not create a parallel + manifest or packaging format. +- **DES-007 — Reproducible package inputs.** Each platform archive is built + from a clean exact tagged commit with `Cargo.lock`, `--locked`, a declared + target triple, normalized archive metadata, and the existing five-platform + asset naming contract. +- **DES-008 — Sealed provenance chain.** Publication eligibility requires the + five archive digests, exact `SHA256SUMS`, verified OpenPGP signature and + fingerprint, source commit, lockfile digest, tag-to-commit equality, clean + worktree, immutable direct asset URLs, and SLSA-v1-shaped provenance already + represented by the release manifest. +- **DES-009 — Publication is an owner-gated side effect.** Local build and + unsigned dry-run evidence may be produced inside an approved implementation + slice. Tag creation, signing with owner keys, upload, release publication, + promotion, or public install verification stops for approval of the exact + tag, commit, digest set, fingerprint, destination, and public-boundary + receipt. +- **DES-010 — Verified two-slot installation.** A consumer stages the selected + archive in a new immutable version directory, verifies the manifest, + signature, archive digest, member shape, and `bran --version`, then changes + one consumer-local pin or stable link. The prior pin and bytes remain + untouched until consumer acceptance passes. +- **DES-011 — Rollback is a tested transition.** Rollback restores the recorded + prior pin/configuration, verifies the restored digest and command behavior, + reruns the consumer's focused gate, and emits a receipt. Failed verification + leaves the consumer blocked and retains both versions for recovery. + +### Consumer migration and evidence gaps + +- **DES-012 — One immutable consumer identity.** Every consumer slice begins + with a canonical checkout path, repository identity, exact revision, + cleanliness record, active legacy surface inventory, and selected BRAN + artifact digest. A mismatch stops before mutation. +- **DES-013 — Frozen semantic parity.** Native and legacy validation/retrieval + run read-only over the same frozen corpus. A small normalizer removes only + representation differences defined in `CONTRACT-007`; raw outputs are always + retained. Semantic differences remain failures. +- **DES-014 — Typed consumer gate state.** Each consumer ends in exactly one of + `passed`, `failed`, `unavailable`, or `rolled_back`. Only `passed` contributes + to global retirement eligibility. +- **DES-015 — Granular AlphaZede Sports boundary rules.** Native policy uses + repository-relative path rules with an explicit classification. Rules are + normalized and sorted by path specificity; the most-specific rule wins. + Equal-specificity disagreement, unmatched required paths, invalid paths, or + symlink escape is a configuration failure. A default classification must be + explicit rather than inferred. +- **DES-016 — BetBot uses an owner-approved content split first.** The route + does not raise BRAN's global text ceiling. The BetBot slice proposes an exact + semantic split of the oversized knowledge document, preserves stable + locators/relationships through explicit redirects or index links, verifies + retrieval and content identity obligations, and can restore exact prior + bytes. If a safe split cannot be approved and proven, BetBot remains blocked; + bounded streaming is a future design, not an implicit fallback. +- **DES-017 — Retrieval unavailable is not parity.** Missing runner, + unsupported legacy query, absent corpus, timeout, or malformed output yields + a typed `unavailable` parity row and blocks that consumer. +- **DES-018 — HGTS absence is terminal for its slice only.** The HGTS slice may + do only identity/discovery checks until the checkout exists. It cannot use a + substitute repository, cached claim, or inferred pass. +- **DES-019 — Disjoint consumer writers.** A consumer slice owns only its + checkout and consumer-local evidence. Shared BRAN release and proposal + surfaces complete earlier under exclusive ownership. Consumer slices may run + concurrently only when their resolved write sets are pairwise disjoint. + +### Compatibility, retirement, upstream proposals, and planning + +- **DES-020 — Compatibility lease.** Adapters, legacy hooks, `use-okf`, + legacy entrypoints, configurations, and prior binaries form a retained + compatibility set. A consumer migration may stop invoking a legacy surface + only after its gate passes, but may not delete the surface. +- **DES-021 — Retirement barrier.** Global retirement evaluates six immutable + consumer receipts plus a fresh active-reference audit. Any non-passing + receipt, unexpected reference, rollback failure, or unavailable repository + keeps the barrier closed. +- **DES-022 — Retirement is a separate destructive transaction.** The final + slice has an exact deletion/write manifest, recovery archive, restoration + rehearsal, owner approval, apply step, and post-removal integrated gate. + Removal is never embedded in a consumer slice. +- **DES-023 — Two proposal drafts, two later owner gates.** Draft + `UPSTREAM-OKF-BUNDLE-SCOPE` as a narrow normative clarification and + `UPSTREAM-OKF-LAYERED-PROFILES` as a design issue. Keep them local before + release; recommend submission only after portable conformance and stable + public release evidence. Each external submission requires approval of exact + text and destination. +- **DES-024 — Canonical plan source.** The authoritative artifacts live only + in `docs/plans/2026-07-22-bran-okf-final-cutover`. The stale auto-slugged path + may be used only as a temporary Bearing receipt alias if the runtime cannot + yet retarget it; it must not hold divergent content and must be removed + before planning completion. +- **DES-025 — Evidence state is explicit.** Every receipt labels observations + as `planned`, `passed`, `failed`, `unavailable`, or `rolled_back`, with + command ID, revision, inputs, exit, and retained evidence locator. A plan or + prior receipt cannot be promoted into current passing evidence. + +## Stable contracts + +- **CONTRACT-001 — ProfileOutcome.** Fields: + `schema_version`, `profile`, `status`, `selected`, `diagnostics[]`, + `bundle_identity`, `command_id`. `profile` is exactly `okf-v0.1` or + `bran-strict`; status is computed independently. +- **CONTRACT-002 — ReservedDocumentDiagnostic.** Fields: + `path`, `kind`, `code`, `message`, `normative_locator`. `kind` is `index` or + `log`; no strict-only field code is allowed in the portable result. +- **CONTRACT-003 — GateReceipt.** Fields: + `command_id`, `repository`, `revision`, `started_at`, `exit_code`, `status`, + `input_digests`, `evidence_paths`, `first_failure`. Deterministic evidence + excludes credentials and raw private corpus bodies. +- **CONTRACT-004 — ReleaseIdentity.** Exact tuple: + `tag`, `source_commit`, `lockfile_sha256`, five platform archive SHA-256 + values, `SHA256SUMS` digest, signature digest, signer fingerprint, signed + time, manifest digest, and immutable asset URLs. +- **CONTRACT-005 — InstallSnapshot.** Fields: + `consumer`, `consumer_revision`, `release_identity`, `prior_pin`, + `prior_digest`, `staged_path`, `selected_pin`, `selected_digest`, + `verification_status`. +- **CONTRACT-006 — RollbackReceipt.** Fields: + `consumer`, `trigger`, `from_digest`, `to_digest`, `restored_paths`, + `byte_checks`, `commands`, `status`. Success requires all restored digests + and focused commands to pass. +- **CONTRACT-007 — ParityReceipt.** Fields: + `consumer`, `corpus_digest`, `native_command`, `legacy_command`, + `native_raw`, `legacy_raw`, `normalizer_version`, `semantic_rows`, + `validation_status`, `retrieval_status`, `overall_status`. Normalization may + map field names, exit categories, and deterministic ordering only; it may not + discard selected locator, precedence, diagnostic code, conflict, or + unavailable state. +- **CONTRACT-008 — BoundaryRuleSet.** Fields: + `schema_version`, `default`, and ordered entries of + `repository_relative_path`, `match_kind`, `classification`. Paths are + normalized, root-contained, and conflict-checked before scanning. +- **CONTRACT-009 — OversizedDocumentPlan.** Fields: + `consumer`, `source_path`, `source_digest`, `size`, `split_paths`, + `relationship_map`, `semantic_checks`, `rollback_digest`, `owner_approval`. + It cannot authorize a global ceiling increase. +- **CONTRACT-010 — ConsumerGateReceipt.** Fields: + `consumer`, `repository`, `revision`, `release_identity`, `install`, + `validation_parity`, `retrieval_parity`, `hook_check`, `reference_audit`, + `rollback`, `status`, `blockers`. +- **CONTRACT-011 — RetirementManifest.** Fields: + six `ConsumerGateReceipt` identities, active-reference audit digest, exact + writes/deletions, recovery archive digest, restoration proof, owner approval + reference, apply and post-apply commands. +- **CONTRACT-012 — UpstreamProposalDraft.** Fields: + `proposal_id`, `kind`, `problem`, `normative_text`, `examples`, + `non_goals`, `local_evidence`, `recommended_timing`, `submission_status`. + `submission_status` remains `not-authorized` in planning. +- **CONTRACT-013 — RouteTrace.** Each requirement maps to design decision, + contract, SEIT case, command/procedure, prospective slice, evidence, stop + condition, and rollback or explicit non-applicability. + +## Use Cases and Communication Flows + +### UC-1 — Repair and prove shared gates + +```text +frozen OKF source -> reserved-rule fixtures -> ProfileValidator + -> okf-v0.1 outcome + -> bran-strict outcome (separate) + +BRAN physical script path -> BRAN root -> scoped git enumeration + -> public-boundary scan -> GateReceipt + +named journey/command/fixture inventory -> test-budget inventory -> inventory proof +shared results -> CMD-FAST -> pass or first-failure receipt +``` + +The reserved validator refuses uncited rules. The public checker never derives +its root from an AlphaZede parent layout. The budget check remains first in +`CMD-FAST`, so registry drift fails before expensive tests. + +### UC-2 — Build, seal, approve, and publish + +```text +clean exact commit + exact tag + Cargo.lock + -> five deterministic platform archives + -> SHA256SUMS -> owner-controlled signature + -> release manifest + provenance + -> local seal verification + -> owner publication approval + -> immutable release upload + -> exact public download and SHA/version verification +``` + +Unsigned dry-run evidence is not a stable release. A manifest mismatch, floating +URL, dirty tree, wrong tag, missing target, signer mismatch, or public-boundary +failure stops before publication. + +### UC-3 — Install and migrate one consumer + +```text +consumer identity + approved release identity + prior install snapshot + -> stage archive -> verify signature/digest/member/version + -> switch one local pin + -> native and legacy checks on frozen corpus + -> semantic parity + hook check + reference audit + -> rollback rehearsal + -> ConsumerGateReceipt +``` + +The consumer slice writes only its own repository. Failure after pin selection +triggers rollback; failure before selection leaves the prior install untouched. + +### UC-4 — Handle blocked consumer evidence + +```text +AlphaZede Sports -> resolve explicit granular rules -> prove allow/deny/conflict +BetBot -> approve exact content split -> prove locators/retrieval/rollback +retrieval runner missing -> unavailable parity row +HGTS missing -> unavailable consumer receipt +``` + +Unavailable rows are retained with first-failure evidence. They block only the +affected consumer and the retirement barrier. + +### UC-5 — Evaluate and execute retirement + +```text +six passing immutable consumer receipts + + fresh zero-active-reference audit + + recovery archive and restoration rehearsal + -> owner approval of exact retirement manifest + -> apply deletion/write set + -> integrated gates + -> retirement success or exact restoration +``` + +No component of this flow runs during planning. The owner approval is specific +to the final manifest, not inherited from consumer approvals. + +### UC-6 — Draft and later submit upstream proposals + +```text +local conformance evidence -> two local proposal drafts +stable public release -> submission recommendation +exact text + destination -> separate owner approval +approval -> external submission (later authority only) +``` + +The bundle-scope clarification precedes the layered-profile design issue in the +recommended external sequence. Neither proposal changes local conformance +evidence retroactively. + +## Interface Option Check + +| Surface | Options considered | Selected interface | Material reason | +| --- | --- | --- | --- | +| Reserved-document validation | legacy delegation; separate command; core profile subvalidator | core `okf-v0.1` subvalidator | One semantic owner, same envelope, offline conformance; avoids adapter-owned rules. | +| Public checker root | caller CWD; Git parent discovery; physical checker path | physical BRAN checker path plus scoped Git enumeration | Works in standalone and nested checkouts and removes the live doubled-`bran` failure. | +| Release contract | new package format; checksum-only; existing exact signed manifest | existing five-archive signed manifest and seal | Already tested, deterministic, exact-tagged, and provenance-aware. | +| Installation | overwrite binary; package-manager latest; verified version slot plus pin | verified version slot plus atomic consumer-local pin | Preserves prior bytes and makes rollback exact. | +| Parity | compare prose; central hard-coded consumer logic; shared semantic receipt with repo-local commands | shared receipt and normalizer, repo-local invocation | Common acceptance without hiding repository-specific commands. | +| AlphaZede Sports boundary | global label; per-file duplication; ordered path rules | explicit default plus most-specific path rules | Expresses granular subtrees deterministically and fails on ambiguity. | +| BetBot oversized document | global cap increase; new streaming parser; owner-approved semantic split | semantic split with exact rollback | Smallest bounded route; no global safety regression or speculative parser. | +| Retirement | delete during each migration; fixed date; global evidence barrier | separate evidence-barrier transaction | Preserves compatibility until every consumer passes and gives one rollback boundary. | +| Upstream contribution | submit immediately; one combined proposal; two staged drafts | two drafts, later separate submissions | Keeps clarification and design debate distinct and respects publication evidence. | + +## CDD + +- Contracts are versioned and exact: profiles, gate receipts, release identity, + installs, parity, consumer completion, retirement, and proposals. +- Adapters translate into `CONTRACT-001` and `CONTRACT-007`; they do not own + validation or retrieval rules. +- Unknown fields that affect behavior are diagnosed rather than silently + dropped. +- Schema/semantic-oracle pairs remain synchronized; generated representations + do not become authority. +- Stable IDs survive implementation slicing and review generation. + +## SecDD + +- Treat repositories, archives, manifests, policy paths, hooks, legacy output, + and proposal text as untrusted input. +- Normalize paths lexically, bind them to a canonical root, reject absolute and + parent traversal, and reject symlink escape before reading or writing. +- Never print credentials, raw auth state, private corpus bodies, hidden truth, + or unsanitized provider traces into receipts. +- Exact digest and signature verification occurs before installation selection. +- Publication and deletion are separate owner-authorized side effects. +- Compatibility and prior install bytes remain recovery assets until final + proof succeeds. + +## RDD + +- Every multi-step operation is a state machine with a terminal typed state. +- Build, seal, install, parity, and retirement commands are retry-safe when + inputs are identical; mismatched identities stop rather than overwrite. +- Consumer progress is monotonic per immutable receipt but global readiness is + recomputed from all six receipts and a fresh reference audit. +- Interrupted installation leaves either the prior selected pin or a blocked + staged version; it cannot report success without readback. +- Rollback uncertainty is failure, never success with a warning. + +## ODD + +- Each command emits or is wrapped by `CONTRACT-003` with exact revision, + input digests, exit, first failure, and evidence locators. +- Public claims derive from current receipts, not plan text. +- The review distinguishes planned, passed, failed, unavailable, and + rolled-back states. +- Deterministic ordering and content-free digests allow comparison without + leaking private bodies. +- Missing optional telemetry does not alter semantic status. + +## OOPDSA Implementation Design + +### Ownership model + +- `ProfileValidator` owns `ProfileOutcome`; an `OkfReservedValidator` strategy + contributes only portable reserved-document diagnostics. +- `PublicSurfaceRoot` is a value object constructed from the physical checker + path and used by the public checker; callers cannot inject a broader root. +- Existing release scripts and `ReleaseIdentity` own release proof. No + `ReleaseManager` framework is introduced. +- `ConsumerMigration` coordinates one `InstallSnapshot`, `ParityReceipt`, + reference audit, and `RollbackReceipt`. +- `RetirementBarrier` is a pure evaluator over six consumer receipts and a + fresh audit. A separate retirement procedure performs authorized writes. + +### State machines + +```text +Release: planned -> built -> sealed -> approved -> published -> verified + \-> failed + +Consumer: discovered -> approved -> staged -> selected -> parity_checked + -> rollback_proven -> passed + \-> unavailable | failed -> rolled_back + +Retirement: ineligible -> eligible -> approved -> applied -> verified + \-> restoring -> restored | failed +``` + +Transitions require the exact preceding identity; there is no boolean +`ready=true` shortcut. + +### Patterns used + +- **Strategy:** portable reserved validation and strict readiness validation + share bundle input while preserving separate rule sets and outcomes. +- **Adapter:** legacy commands/configuration map into native requests and + semantic receipts only. +- **State machine:** release, consumer, and retirement lifecycles expose + partial and recovery states. +- **Value objects:** revisions, digests, normalized repository paths, consumer + IDs, and profile IDs reject malformed values at construction. + +No dependency-injection framework, event bus, database, service, or generic +workflow engine is added. + +### Deterministic data structures and algorithms + +- Use `BTreeMap`/`BTreeSet` for diagnostics, profile rows, asset names, + reference audits, and consumer identities. +- Sort diagnostics by `(path, code, message)` and parity rows by semantic key. +- Normalize boundary rules once, reject duplicate/conflicting normalized paths, + then sort by descending path-component count and lexical path. The first + matching rule wins; equal-specific conflicts are invalid. +- Compute SHA-256 in bounded chunks. Do not load release archives or oversized + inputs solely to hash them. +- Represent implementation dependencies as a DAG. Use Kahn topological sorting + with lexical slice-ID tie-breaking; reject cycles and overlapping write sets + before execution. +- Compare exact write sets with normalized path-prefix intersection, treating + a repository root as overlapping all descendants. + +Complexity remains bounded by repository paths, rules, assets, and slices: +sorting is `O(n log n)`, matching is `O(r * p)` for small policy rule sets, and +hashing is `O(bytes)` with bounded memory. + +## Prospective execution waves + +Implementation drafting must preserve this dependency shape: + +1. **Wave 1 — Shared gate truth:** reserved conformance, public-root repair, + budget regression, independent profile reporting. +2. **Wave 2 — Local proposal drafts and release readiness:** two proposal + drafts, release build/seal proof, publication packet. +3. **Wave 3 — Owner-gated publication and exact public verification:** no + consumer mutation before a stable release identity exists. +4. **Wave 4 — Six disjoint consumer migrations:** parallel only after exact + write-set comparison and per-consumer approval. +5. **Wave 5 — Global evidence audit:** six receipts, fresh references, + rollback archive, retirement manifest. +6. **Wave 6 — Separately approved retirement:** destructive apply and + restoration path. + +## Design stop conditions + +Stop when: + +- normative reserved-file rules cannot be cited; +- the public checker must broaden beyond the BRAN/public export surface; +- an exact source/tag/artifact/signature identity cannot be proven; +- a consumer identity, revision, write set, or prior install cannot be read; +- parity requires discarding semantic differences; +- a boundary conflict or oversized-document split lacks an explicit safe + resolution and rollback; +- HGTS or retrieval evidence remains unavailable for a claimed passing gate; +- any writer overlaps another active writer; +- compatibility removal is proposed before six passing receipts; +- publication, consumer mutation, proposal submission, or retirement lacks its + exact owner approval; or +- the Bearing runtime would force divergent artifacts into the rejected + auto-slugged plan directory. + +## Handoff to implementation drafting + +### Role and outcome + +Act as the bounded Bearing implementation-drafting agent. Reuse this design and +`seit.md`; create traceable implementation slices only after the design/SEIT +checkpoint validates. + +### Scope and authority + +Write only `implementation.md` in the canonical plan directory. Do not execute, +publish, mutate consumers, submit proposals, remove compatibility, or hand-edit +`review.html`. Use only owner-supported route labels and reasoning levels. + +### Execute now + +Map each prospective SEIT row to one bounded slice with an exact write set, +dependency wave, model route, verification commands, retained evidence, stop +condition, owner gate, and rollback. Give each consumer exactly one migration +slice and reject overlapping writers. + +### Verification and evidence + +Prove complete bidirectional traceability, valid wave order, six consumer +slices, supported assignments, and a separate final retirement slice. Bearing, +not the agent, generates the baseline and final `review.html`. + +### Return or stop conditions + +Return only `implementation.md` and the Bearing-generated review artifacts at +the supplied checkpoint. Stop before execution and on any authority expansion, +unsupported model route, missing traceability, overlapping write set, or +runtime attempt to continue a divergent duplicate plan. + +## 2026-07-23 Slice 2.1 wire-contract clarification + +This section provides the exact append-only wire-contract clarification for Slice 2.1 to settle JSON wire shapes, evidence locator/digest bindings, reference classifications, and revision-bound freshness semantics without introducing new requirements, contracts, slices, design IDs, paths, commands, external authority, or consumer-specific semantics. + +### 1. Common encoding and evidence binding + +- **Encoding and key validation:** Every manifest and receipt is UTF-8 JSON. Duplicate keys within any JSON object are strictly rejected. Behavioral objects use exact documented keys; any unrecognized or unknown behavioral key causes verification failure. +- **Digests and revisions:** Digests are exact lowercase 64-character hexadecimal SHA-256 strings. Revisions are exact lowercase Git object IDs of 40 or 64 hexadecimal characters. +- **Evidence locators:** Evidence locators are normalized POSIX paths relative to the supplied evidence directory. Locators cannot be absolute, empty, single dot (`.`), parent traversal (`..`), or contain backslashes (`\`), and must resolve to non-symlink regular files physically contained within that evidence directory. +- **Evidence digest pairing:** Every evidence locator is paired with its SHA-256 digest. The verifier recomputes all evidence digests in bounded chunks during execution. The verifier never emits raw evidence bodies in receipts or diagnostic output. +- **Inert commands:** Commands embedded in receipts are inert strings or structured command records. Verifier modes treat commands strictly as read-only evidence and never execute them. +- **Canonical ordering and JSON hashing:** Deterministic canonical ordering is lexical by consumer, path, and semantic key. Duplicate keys, duplicate locators, or duplicate consumers cause immediate verification failure. Wherever canonical compact JSON is hashed, it is defined uniformly as UTF-8 `json.dumps(value, sort_keys=True, separators=(",", ":"), ensure_ascii=False)` bytes, with arrays already in their required lexical order. + +### 2. ReleaseIdentity wire shape (CONTRACT-004) + +`ReleaseIdentity` is an exact JSON object containing these top-level keys: +`tag`, `source_commit`, `lockfile_sha256`, `archives`, `checksums_sha256`, `signature_sha256`, `signer_fingerprint`, `signed_at`, `manifest_sha256`, `asset_urls`. + +- `archives` is an exact object keyed by the five approved target triples (`x86_64-unknown-linux-gnu`, `aarch64-unknown-linux-gnu`, `x86_64-apple-darwin`, `aarch64-apple-darwin`, `x86_64-pc-windows-msvc`), with each value being its lowercase 64-hex SHA-256 digest. +- `asset_urls` is an exact lexically sorted array of immutable direct URL strings for the five target archives plus `SHA256SUMS`, `SHA256SUMS.sig`, and `bran-release-manifest.json` (8 URLs total). URLs using `latest`, query parameters, URL fragments, duplicate entries, or tag mismatches are strictly rejected. +- Equality of `ReleaseIdentity` requires exact byte/field equality across this entire normalized object; tag-only identity matches are rejected. + +### 3. ConsumerGateReceipt wire shape (CONTRACT-010) + +`ConsumerGateReceipt` is an exact JSON object with the top-level keys: +`consumer`, `repository`, `revision`, `release_identity`, `install`, `validation_parity`, `retrieval_parity`, `hook_check`, `reference_audit`, `rollback`, `status`, `blockers`. + +- `consumer` is any nonempty stable identifier string. `repository` is the canonical repository identity string. `revision` must equal the CLI revision argument and current clean checkout HEAD. +- `status` is one of the four-state vocabulary: `passed`, `failed`, `unavailable`, `rolled_back`. Only `passed` permits a successful exit code (0). +- `blockers` is a lexically sorted array of unique string blocker codes. `blockers` must be empty if and only if `status` is `passed`. + +### 4. Nested object wire shapes + +- **InstallSnapshot (CONTRACT-005):** Exact top-level keys: `consumer`, `consumer_revision`, `release_identity`, `prior_pin`, `prior_digest`, `staged_path`, `selected_pin`, `selected_digest`, `verification_status`. `staged_path` and `prior_pin` are evidence locators relative to the supplied evidence directory; their bytes must hash to `selected_digest` and `prior_digest` respectively. `selected_pin` is a nonempty inert string identifying the selected pin. `verification_status` is `passed` only when `staged_path` bytes hash to `selected_digest`, `prior_pin` bytes hash to `prior_digest`, the exact `ReleaseIdentity` matches, and prior pin/digest values are retained. This tool verifies a captured snapshot and does not switch the pin. +- **ParityReceipt (CONTRACT-007):** Exact top-level keys: `consumer`, `corpus_digest`, `native_command`, `legacy_command`, `native_raw`, `legacy_raw`, `normalizer_version`, `semantic_rows`, `validation_status`, `retrieval_status`, `overall_status`. `native_raw` and `legacy_raw` are evidence locator/digest objects. Raw evidence files must be UTF-8 JSON arrays whose normalized entries correspond one-to-one with semantic rows, allowing only the documented field-name, exit-category, and ordering transformations. `semantic_rows` is a lexically sorted list of objects containing `semantic_key`, `native`, and `legacy`. Every `semantic_rows[].native` and `.legacy` is an exact object with always-present keys `locator`, `precedence`, `diagnostic_code`, `conflict`, `unavailable`, plus `outcome` (nullable values are allowed, but the keys cannot be dropped). `normalizer_version` is a nonempty pinned version string. States (`validation_status`, `retrieval_status`, `overall_status`) use the four-state vocabulary (`passed`, `failed`, `unavailable`, `rolled_back`); any non-passing status blocks. The two `ConsumerGateReceipt` parity fields (`validation_parity`, `retrieval_parity`) are independently validated receipts over the same `consumer` and `corpus_digest`, nested under the authoritative `ConsumerGateReceipt` `ReleaseIdentity`; neither raw output may be absent. +- **Hook check:** Exact JSON object with keys `commands`, `evidence`, `status`. `commands` is an array of inert nonempty string commands, `evidence` is an array of locator/digest objects, and `status` must be `passed`. +- **Reference audit:** Exact JSON object with keys `consumer`, `revision`, `expected_compatibility`, `matches`, `inventory_digest`, `evidence`, `status`. `expected_compatibility` is a sorted unique list of exact objects with `path` and `kind`; paths are normalized consumer-relative POSIX paths and `kind` uses the existing kind vocabulary (`code`, `skill`, `hook`, `ci`, `configuration`, `historical-documentation`). `matches` is a sorted list of objects containing `path`, `line`, `kind`, `classification`, `match_sha256`. `match_sha256` is the SHA-256 of the exact matched source line bytes read from the clean consumer checkout at `path` and `line`, recomputed by the verifier. `kind` must be one of `code`, `skill`, `hook`, `ci`, `configuration`, `historical-documentation`. `classification` must be one of `native-active`, `compatibility-active`, `historical`, `unexpected-active`, `unclassified`. Passing status permits only `native-active`, `compatibility-active`, and `historical`, requires a matching `compatibility-active` match for every expected object in `expected_compatibility` and no `compatibility-active` match absent from that list, and rejects any `unexpected-active` or `unclassified` entries. This is manifest-driven and has no built-in per-consumer list. `inventory_digest` is SHA-256 of compact UTF-8 JSON encoding (`json.dumps(matches, sort_keys=True, separators=(",", ":"), ensure_ascii=False)` bytes) of the sorted `matches` array. +- **RollbackReceipt (CONTRACT-006):** Exact top-level keys: `consumer`, `trigger`, `from_digest`, `to_digest`, `restored_paths`, `byte_checks`, `commands`, `status`. Every `restored_paths` item is an exact object with keys `path`, `sha256`, `source`; `source` must be `evidence` or `consumer`. Evidence paths resolve beneath the evidence root; consumer paths resolve beneath the clean consumer checkout; both reject symlinks and path traversal escapes, and their bytes are hashed to `sha256`. `byte_checks` is a sorted list of records with keys `path`, `expected`, `actual`, `status`. `commands` is a sorted list of records with keys `command`, `exit_code`, `status`, `evidence`. Passing requires exact `from_digest` and `to_digest` matching, all byte checks and commands passing with status `passed`, and no missing items. + +### 5. RetirementManifest wire shape (CONTRACT-011) + +`RetirementManifest` is an exact JSON object with keys: +`consumers`, `active_reference_audit`, `writes`, `deletions`, `recovery_archive`, `restoration_proof`, `owner_approval_reference`, `apply_commands`, `post_apply_commands`. + +- `consumers` is an exact array of six sorted consumer summary objects containing `consumer`, `repository`, `revision`, `release_identity`, `receipt`, `receipt_sha256`, `status` for `Alphazedehq`, `alphazede-sports`, `betbot`, `developers`, `hgts`, and `alphazede-markets`. Each referenced `receipt` is bound to a regular evidence file and independently validates as a passing `ConsumerGateReceipt` with matching revision and release identity. +- `active_reference_audit`, `recovery_archive`, and `restoration_proof` are evidence locator/digest objects. +- The file referenced by `active_reference_audit` is strict JSON with exact keys `consumers`, `status`. Its `consumers` array contains the exact six sorted objects with `consumer`, `repository`, `revision`, `release_identity`, `inventory_digest`, `status`, each matching the corresponding independently validated `ConsumerGateReceipt`; top-level and per-consumer status must be `passed`. +- The file referenced by `restoration_proof` is strict JSON with exact keys `byte_checks`, `commands`, `status`, using the same byte-check and command-record shapes as `RollbackReceipt`, and every item and status must pass. +- `recovery_archive` references the actual non-symlink regular archive file beneath the evidence directory and its digest is recomputed. +- `writes` and `deletions` are exact sorted unique lists of normalized repository-relative paths, validated as data structures only. +- `owner_approval_reference` is a nonempty inert string reference proving the manifest carries an approval tracking string; its presence does not imply verifier grant or confirmation of owner approval. +- `apply_commands` and `post_apply_commands` are arrays of nonempty inert strings and are never executed by `verify`. +- Retirement eligibility requires exact identity equality among these six current consumer receipts and the global audit (`active_reference_audit`), matching revision and release identity, live digest recomputation for all referenced evidence files, and passing status across all receipts and audits (no wall-clock threshold). Eligibility does not authorize execution of retirement commands. + +### 6. Freshness and read-only verifier semantics + +- **Identity-bound freshness:** Freshness is identity-bound rather than wall-clock-based. An audit or receipt is fresh if and only if its recorded revision equals the CLI revision argument and current clean checkout HEAD, its `ReleaseIdentity` equals the selected release identity, and every evidence file digest is recomputed from the supplied evidence directory during the current verifier invocation. Freshness for retirement is proven by exact identity equality among the six current receipts and the global audit plus live digest recomputation, with no wall-clock threshold. +- **Unavailable telemetry:** Missing or incomplete optional telemetry produces an `unavailable` state and is never normalized into a semantic pass. +- **Read-only enforcement:** Verifier modes (`install-verify`, `parity`, `reference-audit`, `rollback`, and retirement `verify`) are strictly read-only. They never generate receipts, alter pins, restore files, execute commands, sign artifacts, publish assets, upload packages, or mutate any repository or evidence directory. diff --git a/docs/plans/2026-07-22-bran-okf-final-cutover/implementation.md b/docs/plans/2026-07-22-bran-okf-final-cutover/implementation.md new file mode 100644 index 0000000..32a9a3c --- /dev/null +++ b/docs/plans/2026-07-22-bran-okf-final-cutover/implementation.md @@ -0,0 +1,475 @@ +--- +type: implementation +name: bran-okf-final-cutover +status: complete +date: 2026-07-23 +applies_to: bran +plan_spec: ./plan-spec.md +design: ./design.md +seit: ./seit.md +planning_route: codex gpt-5.6-sol +planning_reasoning: high +--- + +## Dependencies + +- Wave 1: Slice 1.1, then Slice 1.2. +- Wave 2: Slice 2.1 and Slice 2.2 after Wave 1. +- Wave 3: Slice 3.1 after Wave 2. +- Wave 4: Slice 4.1, Slice 4.2, Slice 4.3, Slice 4.4, Slice 4.5, and Slice 4.6 after Wave 3; their writers are disjoint. +- Wave 5: Slice 5.1 after every Wave 4 consumer reaches a terminal receipt. +- Wave 6: Slice 6.1 only after Slice 5.1 proves eligibility and the owner separately approves retirement. + +## Phase 1 — Shared BRAN gates + +### Slice 1.1 — Portable reserved-document conformance + +**Goal.** Close the portable reserved `index.md` and `log.md` coverage gap while keeping strict results independent. + +**Requirement IDs.** AC-002, AC-008; REQ-GATE-001, REQ-GATE-005. + +**Design IDs.** DES-001, DES-002, DES-003, CONTRACT-001, CONTRACT-002. + +**SEIT proof rows.** SEIT-001, SEIT-002, SEIT-003. + +**Type.** code + +**Design lenses.** CDD, SecDD, RDD, ODD, OOPDSA. + +**Implementation role.** Crewmate + +**Agent model route.** codex gpt-5.6-terra + +**Agent reasoning level.** medium + +**Ponytail mode.** full + +**Review path.** Harness-native read-only reviewer; Surveyor fallback only when unavailable. + +### 1.1 execution manifest + +**Write set.** Write only `crates/bran-core/src/profile.rs`, `fixtures/conformance/okf-v0.1-index-valid.fixture`, `fixtures/conformance/okf-v0.1-index-invalid.fixture`, `fixtures/conformance/okf-v0.1-log-valid.fixture`, `fixtures/conformance/okf-v0.1-log-invalid.fixture`, `tools/ci/test-budget.json`. + +**Command IDs.** CMD-OKF-PORTABLE, CMD-PROFILES. + +**Stop condition.** Stop if the normative portable structure cannot be cited, a strict-only rule enters the portable result, or the write set must expand. + +**Human decision.** None after the normative source and exact write set are verified; otherwise stop for owner scope direction. + +### Slice 1.2 — Public-root repair and fast-gate regression + +**Goal.** Remove the doubled-path failure and update `tools/ci/test-budget.json` and `tools/ci/test_budget_check.py` as a deterministic inventory of named CI journeys, direct CI commands, and owned fixtures—not one registry row per Rust unit test. Preserve `CMD-BUDGET` as the first fast-gate check, proving deterministic negative failure on missing/duplicate journeys, direct commands, or fixture ownership, while all Rust unit tests remain mandatory through `CMD-FAST` workspace test commands. + +**Requirement IDs.** AC-002; REQ-GATE-002, REQ-GATE-003, REQ-GATE-004, REQ-GATE-005. + +**Design IDs.** DES-004, DES-005, CONTRACT-003. + +**SEIT proof rows.** SEIT-004, SEIT-005, SEIT-006. + +**Type.** code + +**Design lenses.** CDD, SecDD, RDD, ODD, OOPDSA. + +**Implementation role.** Crewmate + +**Agent model route.** codex gpt-5.6-terra + +**Agent reasoning level.** medium + +**Ponytail mode.** full + +**Review path.** Harness-native read-only reviewer; Surveyor fallback only when unavailable. + +### 1.2 execution manifest + +**Write set.** Write only `tools/ci/public_boundary_check.py`, `tools/ci/test-budget.json`, `tools/ci/test_budget_check.py`, `crates/bran-core/src/migration.rs`, `crates/bran-core/src/packet/mod.rs`, `crates/bran-core/src/policy.rs`, `crates/bran-core/src/profile.rs`, `crates/bran-core/src/scan/mod.rs`, `crates/bran-cli/src/main.rs`. + +**Command IDs.** CMD-BUDGET, CMD-PUBLIC, CMD-FAST. + +**Stop condition.** Stop if the checker must scan outside the BRAN/public export surface, depends on caller CWD, or the budget check no longer fails first on missing or duplicate inventory entries. Stop if the clippy repair requires semantic behavior change or lint suppression. + +**Human decision.** None unless the public export boundary itself must change. + +## Phase 2 — Cutover contracts and proposal drafts + +### Slice 2.1 — Cutover verification tools + +**Goal.** Add the bounded offline verifiers required for exact release, consumer parity, reference, rollback, retirement, and route receipts. + +**Requirement IDs.** AC-001, AC-003, AC-004, AC-005, AC-006; REQ-REL-003, REQ-REL-004, REQ-REL-005, REQ-CONS-002, REQ-CONS-003, REQ-CONS-004, REQ-CONS-005, REQ-CONS-006, REQ-PARITY-001, REQ-COMPAT-001, REQ-RETIRE-001, REQ-PLAN-002, REQ-PLAN-003, REQ-PLAN-004. + +**Design IDs.** DES-010, DES-011, DES-013, DES-014, DES-017, DES-019, DES-021, DES-025, CONTRACT-005, CONTRACT-006, CONTRACT-007, CONTRACT-010, CONTRACT-011, CONTRACT-013. + +**SEIT proof rows.** SEIT-010, SEIT-011, SEIT-012, SEIT-019, SEIT-020, SEIT-021, SEIT-023, SEIT-029, SEIT-031. + +**Type.** code + +**Design lenses.** CDD, SecDD, RDD, ODD, OOPDSA. + +**Implementation role.** Crewmate + +**Agent model route.** codex gpt-5.6-terra + +**Agent reasoning level.** medium + +**Ponytail mode.** full + +**Review path.** Harness-native read-only reviewer; Surveyor fallback only when unavailable. + +### 2.1 execution manifest + +**Write set.** Write only `tools/cutover/verify_release.py`, `tools/cutover/consumer_gate.py`, `tools/cutover/retirement_gate.py`, `tools/cutover/validate_route.py`, `tools/ci/test-budget.json`. + +**Command IDs.** CMD-EXACT-SHA, CMD-INSTALL-VERIFY, CMD-CONSUMER-PARITY, CMD-REFERENCE-AUDIT, CMD-ROLLBACK, CMD-RETIREMENT-PROOF, CMD-ROUTE-TRACE. + +**Stop condition.** Stop on a dependency, network requirement, hidden consumer rule, write-capable default, semantic-normalization loss, or path outside the exact write set. + +**Human decision.** None; every later side-effect mode remains separately gated. + +### Slice 2.2 — Upstream OKF proposal drafts + +**Goal.** Draft the bundle-scope clarification and layered-profile issue without external submission. + +**Requirement IDs.** AC-007, AC-008; REQ-UPSTREAM-001, REQ-UPSTREAM-002, REQ-UPSTREAM-003. + +**Design IDs.** DES-001, DES-009, DES-023, CONTRACT-001, CONTRACT-012. + +**SEIT proof rows.** SEIT-026, SEIT-027, SEIT-028. + +**Type.** documentation + +**Design lenses.** CDD, SecDD, RDD, ODD. + +**Implementation role.** Crewmate + +**Agent model route.** agy agent default + +**Agent reasoning level.** medium + +**Ponytail mode.** off + +**Review path.** Harness-native read-only reviewer; Surveyor fallback only when unavailable. + +### 2.2 execution manifest + +**Write set.** Write only `docs/integrations/proposals/okf-bundle-scan-scope.md`, `docs/integrations/proposals/okf-layered-profile-separation.md`. + +**Command IDs.** PROC-PROPOSAL-DRAFTS, CMD-PROFILES. + +**Stop condition.** Stop if either draft claims uncited normative behavior, combines the proposals, or implies submission/publication authority. + +**Human decision.** Separate owner approval is required later for each exact external text and destination. + +## Phase 3 — Stable release + +### Slice 3.1 — Reproducible seal, publication gate, and exact public verification + +**Goal.** Build and seal the exact multi-platform release, stop for publication approval, then verify immutable public assets. + +**Requirement IDs.** AC-003; REQ-REL-001, REQ-REL-002, REQ-REL-003, REQ-REL-006, REQ-UPSTREAM-003. + +**Design IDs.** DES-006, DES-007, DES-008, DES-009, CONTRACT-004. + +**SEIT proof rows.** SEIT-007, SEIT-008, SEIT-009. + +**Type.** operational + +**Design lenses.** CDD, SecDD, RDD, ODD. + +**Implementation role.** Crewmate + +**Agent model route.** agy agent default + +**Agent reasoning level.** medium + +**Ponytail mode.** off + +**Review path.** Harness-native read-only reviewer; Surveyor fallback only when unavailable. + +### 3.1 execution manifest + +**Write set.** No writes required in the repository; release archives, seal evidence, and public readback receipts remain outside the source checkout. + +**Command IDs.** CMD-RELEASE-PLAN, CMD-RELEASE-BUILD-LINUX-X86, CMD-RELEASE-BUILD-LINUX-ARM, CMD-RELEASE-BUILD-MAC-X86, CMD-RELEASE-BUILD-MAC-ARM, CMD-RELEASE-BUILD-WINDOWS-X86, CMD-RELEASE-CONTRACT, CMD-RELEASE-DRY-SEAL, CMD-RELEASE-SEAL, CMD-EXACT-SHA, PROC-PUBLICATION. + +**Stop condition.** Stop on dirty source, missing target, non-reproducible archive, identity/signature/public-boundary mismatch, floating URL, or approval drift. + +**Human decision.** Owner approval of the exact tag, source SHA, digest set, fingerprint, destination, and boundary receipt is required before signing, uploading, publishing, or public installation verification. + +## Phase 4 — Disjoint consumer migrations + +### Slice 4.1 — AlphazedeHQ migration and parity + +**Goal.** Install the exact release, switch the BRAN-backed advisory path, prove parity and rollback, and retain every compatibility surface. + +**Requirement IDs.** AC-004, AC-005, AC-006; REQ-REL-004, REQ-REL-005, REQ-CONS-001, REQ-CONS-003, REQ-CONS-004, REQ-CONS-005, REQ-CONS-006, REQ-CONS-007, REQ-PARITY-001, REQ-COMPAT-001, REQ-COMPAT-002. + +**Design IDs.** DES-010, DES-011, DES-012, DES-013, DES-014, DES-017, DES-019, DES-020, CONTRACT-005, CONTRACT-006, CONTRACT-007, CONTRACT-010, CONTRACT-013. + +**SEIT proof rows.** SEIT-010, SEIT-011, SEIT-012, SEIT-013, SEIT-019, SEIT-020, SEIT-021, SEIT-022. + +**Type.** consumer + +**Design lenses.** CDD, SecDD, RDD, ODD, OOPDSA. + +**Implementation role.** Crewmate + +**Agent model route.** codex gpt-5.6-terra + +**Agent reasoning level.** medium + +**Ponytail mode.** full + +**Review path.** Harness-native read-only reviewer; Surveyor fallback only when unavailable. + +### 4.1 execution manifest + +**Write set.** Within the AlphazedeHQ checkout write only `.bran/policy.yaml`, `.bran/evidence/bran-cutover.json`, `.grok/hooks/use-okf.sh`, `.grok/hooks/use-okf.json`, `tools/okf/runtime/bran-release-pin.json`. + +**Command IDs.** CMD-EXACT-SHA, CMD-INSTALL-VERIFY, CMD-CONSUMER-PARITY, CMD-REFERENCE-AUDIT, CMD-ROLLBACK, CMD-ROUTE-TRACE, PROC-PARITY-ALPHAZEDEHQ. + +**Stop condition.** Stop on repository/revision mismatch, unavailable retrieval, hook contract drift, unexpected active reference, parity failure, or rollback mismatch. + +**Human decision.** Owner approval of this checkout, revision, artifact digest, exact write set, commands, and rollback is required before mutation. + +### Slice 4.2 — AlphaZede Sports migration and granular boundary parity + +**Goal.** Install the exact release and prove the repository's granular public-boundary policy, parity, references, and rollback. + +**Requirement IDs.** AC-004, AC-005, AC-006; REQ-REL-004, REQ-REL-005, REQ-CONS-001, REQ-CONS-003, REQ-CONS-004, REQ-CONS-005, REQ-CONS-006, REQ-CONS-007, REQ-AZS-001, REQ-PARITY-001, REQ-COMPAT-001, REQ-COMPAT-002. + +**Design IDs.** DES-010, DES-011, DES-012, DES-013, DES-014, DES-015, DES-017, DES-019, DES-020, CONTRACT-005, CONTRACT-006, CONTRACT-007, CONTRACT-008, CONTRACT-010, CONTRACT-013. + +**SEIT proof rows.** SEIT-010, SEIT-011, SEIT-012, SEIT-014, SEIT-019, SEIT-020, SEIT-021, SEIT-022. + +**Type.** consumer + +**Design lenses.** CDD, SecDD, RDD, ODD, OOPDSA. + +**Implementation role.** Crewmate + +**Agent model route.** codex gpt-5.6-terra + +**Agent reasoning level.** medium + +**Ponytail mode.** full + +**Review path.** Harness-native read-only reviewer; Surveyor fallback only when unavailable. + +### 4.2 execution manifest + +**Write set.** Within the alphazede-sports checkout write only `.bran/policy.yaml`, `.bran/evidence/bran-cutover.json`, `tools/okf/runtime/bran-release-pin.json`. + +**Command IDs.** CMD-EXACT-SHA, CMD-INSTALL-VERIFY, CMD-CONSUMER-PARITY, CMD-REFERENCE-AUDIT, CMD-ROLLBACK, CMD-ROUTE-TRACE, PROC-PARITY-ALPHAZEDE-SPORTS. + +**Stop condition.** Stop on repository/revision mismatch, ambiguous boundary precedence, unmatched required path, unavailable retrieval, parity/reference failure, or rollback mismatch. + +**Human decision.** Owner approval of this checkout, revision, boundary rules, artifact digest, exact write set, commands, and rollback is required before mutation. + +### Slice 4.3 — BetBot migration and oversized-document resolution + +**Goal.** Install the exact release and resolve the oversized knowledge document without raising BRAN's global limit, then prove parity and rollback. + +**Requirement IDs.** AC-004, AC-005, AC-006; REQ-REL-004, REQ-REL-005, REQ-CONS-001, REQ-CONS-003, REQ-CONS-004, REQ-CONS-005, REQ-CONS-006, REQ-CONS-007, REQ-BETBOT-001, REQ-PARITY-001, REQ-COMPAT-001, REQ-COMPAT-002. + +**Design IDs.** DES-010, DES-011, DES-012, DES-013, DES-014, DES-016, DES-017, DES-019, DES-020, CONTRACT-005, CONTRACT-006, CONTRACT-007, CONTRACT-009, CONTRACT-010, CONTRACT-013. + +**SEIT proof rows.** SEIT-010, SEIT-011, SEIT-012, SEIT-015, SEIT-019, SEIT-020, SEIT-021, SEIT-022. + +**Type.** consumer + +**Design lenses.** CDD, SecDD, RDD, ODD, OOPDSA. + +**Implementation role.** Crewmate + +**Agent model route.** codex gpt-5.6-terra + +**Agent reasoning level.** medium + +**Ponytail mode.** full + +**Review path.** Harness-native read-only reviewer; Surveyor fallback only when unavailable. + +### 4.3 execution manifest + +**Write set.** Within the BetBot checkout write only `.bran/policy.yaml`, `.bran/evidence/bran-cutover.json`, `.bran/migrations/oversized-document-plan.json`, `docs/okf`, `tools/okf/runtime/bran-release-pin.json`. + +**Command IDs.** CMD-EXACT-SHA, CMD-INSTALL-VERIFY, CMD-CONSUMER-PARITY, CMD-REFERENCE-AUDIT, CMD-ROLLBACK, CMD-ROUTE-TRACE, PROC-PARITY-BETBOT. + +**Stop condition.** Stop if the exact oversized source is outside `docs/okf`, the semantic split lacks owner approval, locators/relationships change without mapping, retrieval is unavailable, parity fails, or rollback differs. + +**Human decision.** Owner approval of the exact source and split paths, checkout revision, artifact digest, write set, commands, and rollback is required before mutation. + +### Slice 4.4 — developers public consumer migration and parity + +**Goal.** Install the exact public release and prove exported-source identity, parity, references, and rollback. + +**Requirement IDs.** AC-004, AC-005, AC-006; REQ-REL-004, REQ-REL-005, REQ-CONS-001, REQ-CONS-003, REQ-CONS-004, REQ-CONS-005, REQ-CONS-006, REQ-CONS-007, REQ-PARITY-001, REQ-COMPAT-001, REQ-COMPAT-002. + +**Design IDs.** DES-010, DES-011, DES-012, DES-013, DES-014, DES-017, DES-019, DES-020, CONTRACT-005, CONTRACT-006, CONTRACT-007, CONTRACT-010, CONTRACT-013. + +**SEIT proof rows.** SEIT-010, SEIT-011, SEIT-012, SEIT-016, SEIT-019, SEIT-020, SEIT-021, SEIT-022. + +**Type.** consumer + +**Design lenses.** CDD, SecDD, RDD, ODD, OOPDSA. + +**Implementation role.** Crewmate + +**Agent model route.** codex gpt-5.6-terra + +**Agent reasoning level.** medium + +**Ponytail mode.** full + +**Review path.** Harness-native read-only reviewer; Surveyor fallback only when unavailable. + +### 4.4 execution manifest + +**Write set.** Within the developers checkout write only `.bran/policy.yaml`, `.bran/evidence/bran-cutover.json`, `tools/okf/runtime/bran-release-pin.json`. + +**Command IDs.** CMD-EXACT-SHA, CMD-INSTALL-VERIFY, CMD-CONSUMER-PARITY, CMD-REFERENCE-AUDIT, CMD-ROLLBACK, CMD-ROUTE-TRACE, PROC-PARITY-DEVELOPERS. + +**Stop condition.** Stop on repository/revision mismatch, export/source identity mismatch, floating asset, unavailable retrieval, parity/reference failure, or rollback mismatch. + +**Human decision.** Owner approval of this checkout, revision, artifact digest, exact write set, commands, and rollback is required before mutation. + +### Slice 4.5 — HGTS discovery, migration, and parity + +**Goal.** Verify HGTS identity when available, then install and prove parity and rollback without substituting another checkout. + +**Requirement IDs.** AC-004, AC-005, AC-006; REQ-REL-004, REQ-REL-005, REQ-CONS-001, REQ-CONS-003, REQ-CONS-004, REQ-CONS-005, REQ-CONS-006, REQ-CONS-007, REQ-HGTS-001, REQ-PARITY-001, REQ-COMPAT-001, REQ-COMPAT-002. + +**Design IDs.** DES-010, DES-011, DES-012, DES-013, DES-014, DES-017, DES-018, DES-019, DES-020, CONTRACT-005, CONTRACT-006, CONTRACT-007, CONTRACT-010, CONTRACT-013. + +**SEIT proof rows.** SEIT-010, SEIT-011, SEIT-012, SEIT-017, SEIT-019, SEIT-020, SEIT-021, SEIT-022. + +**Type.** consumer + +**Design lenses.** CDD, SecDD, RDD, ODD, OOPDSA. + +**Implementation role.** Crewmate + +**Agent model route.** codex gpt-5.6-terra + +**Agent reasoning level.** medium + +**Ponytail mode.** full + +**Review path.** Harness-native read-only reviewer; Surveyor fallback only when unavailable. + +### 4.5 execution manifest + +**Write set.** When HGTS is absent, write nothing; after identity and owner approval, within the HGTS checkout write only `.bran/policy.yaml`, `.bran/evidence/bran-cutover.json`, `tools/okf/runtime/bran-release-pin.json`. + +**Command IDs.** CMD-EXACT-SHA, CMD-INSTALL-VERIFY, CMD-CONSUMER-PARITY, CMD-REFERENCE-AUDIT, CMD-ROLLBACK, CMD-ROUTE-TRACE, PROC-PARITY-HGTS. + +**Stop condition.** Stop with `unavailable` while HGTS is absent, or on identity/revision mismatch, unavailable retrieval, parity/reference failure, or rollback mismatch. + +**Human decision.** Owner approval of the verified checkout, revision, artifact digest, exact write set, commands, and rollback is required before any HGTS mutation. + +### Slice 4.6 — alphazede-markets migration and parity + +**Goal.** Install the exact release and prove policy, validation/retrieval parity, references, and rollback. + +**Requirement IDs.** AC-004, AC-005, AC-006; REQ-REL-004, REQ-REL-005, REQ-CONS-001, REQ-CONS-003, REQ-CONS-004, REQ-CONS-005, REQ-CONS-006, REQ-CONS-007, REQ-PARITY-001, REQ-COMPAT-001, REQ-COMPAT-002. + +**Design IDs.** DES-010, DES-011, DES-012, DES-013, DES-014, DES-017, DES-019, DES-020, CONTRACT-005, CONTRACT-006, CONTRACT-007, CONTRACT-010, CONTRACT-013. + +**SEIT proof rows.** SEIT-010, SEIT-011, SEIT-012, SEIT-018, SEIT-019, SEIT-020, SEIT-021, SEIT-022. + +**Type.** consumer + +**Design lenses.** CDD, SecDD, RDD, ODD, OOPDSA. + +**Implementation role.** Crewmate + +**Agent model route.** codex gpt-5.6-terra + +**Agent reasoning level.** medium + +**Ponytail mode.** full + +**Review path.** Harness-native read-only reviewer; Surveyor fallback only when unavailable. + +### 4.6 execution manifest + +**Write set.** Within the alphazede-markets checkout write only `.bran/policy.yaml`, `.bran/evidence/bran-cutover.json`, `tools/okf/runtime/bran-release-pin.json`. + +**Command IDs.** CMD-EXACT-SHA, CMD-INSTALL-VERIFY, CMD-CONSUMER-PARITY, CMD-REFERENCE-AUDIT, CMD-ROLLBACK, CMD-ROUTE-TRACE, PROC-PARITY-ALPHAZEDE-MARKETS. + +**Stop condition.** Stop on repository/revision mismatch, unavailable retrieval, policy/parity/reference failure, or rollback mismatch. + +**Human decision.** Owner approval of this checkout, revision, artifact digest, exact write set, commands, and rollback is required before mutation. + +## Phase 5 — Global evidence barrier + +### Slice 5.1 — Retirement eligibility and restoration rehearsal + +**Goal.** Aggregate six immutable consumer receipts, audit active references, and prove restoration before retirement can be recommended. + +**Requirement IDs.** AC-004, AC-005, AC-006; REQ-CONS-006, REQ-COMPAT-001, REQ-RETIRE-001, REQ-RETIRE-002, REQ-RETIRE-003. + +**Design IDs.** DES-011, DES-020, DES-021, DES-022, CONTRACT-006, CONTRACT-010, CONTRACT-011. + +**SEIT proof rows.** SEIT-021, SEIT-022, SEIT-023, SEIT-024, SEIT-029. + +**Type.** operational + +**Design lenses.** CDD, SecDD, RDD, ODD, OOPDSA. + +**Implementation role.** Crewmate + +**Agent model route.** agy agent default + +**Agent reasoning level.** medium + +**Ponytail mode.** off + +**Review path.** Harness-native read-only reviewer; Surveyor fallback only when unavailable. + +### 5.1 execution manifest + +**Write set.** No writes required in consumer repositories; the retirement manifest, reference audit, and restoration rehearsal remain owner-reviewable runtime evidence. + +**Command IDs.** CMD-REFERENCE-AUDIT, CMD-RETIREMENT-PROOF, PROC-RETIREMENT. + +**Stop condition.** Stop on any non-passing, stale, missing, or unavailable consumer receipt, unexpected active reference, recovery archive mismatch, or failed restoration rehearsal. + +**Human decision.** No removal is authorized; return the exact retirement packet for a separate owner decision. + +## Phase 6 — Separately approved global retirement + +### Slice 6.1 — Compatibility retirement transaction + +**Goal.** After separate approval, apply the exact global retirement manifest, run integrated gates, and restore on any failure. + +**Requirement IDs.** AC-006; REQ-COMPAT-001, REQ-COMPAT-002, REQ-RETIRE-001, REQ-RETIRE-002, REQ-RETIRE-003. + +**Design IDs.** DES-011, DES-021, DES-022, CONTRACT-006, CONTRACT-011. + +**SEIT proof rows.** SEIT-023, SEIT-024, SEIT-025. + +**Type.** destructive + +**Design lenses.** CDD, SecDD, RDD, ODD, OOPDSA. + +**Implementation role.** Crewmate + +**Agent model route.** agy agent default + +**Agent reasoning level.** medium + +**Ponytail mode.** off + +**Review path.** Harness-native read-only reviewer; Surveyor fallback only when unavailable. + +### 6.1 execution manifest + +**Write set.** Across the owner-approved Alphazede workspace write only `Alphazedehq/.grok/hooks/use-okf.sh`, `Alphazedehq/.grok/hooks/use-okf.json`, `Alphazedehq/skills/use-okf`, `Alphazedehq/tools/okf/okf`, `Alphazedehq/tools/okf/config.yaml`, `alphazede-sports/tools/okf/config.yaml`, `betbot/tools/okf/config.yaml`, `developers/tools/okf/config.yaml`, `hgts/tools/okf/config.yaml`, `alphazede-markets/tools/okf/config.yaml`. + +**Command IDs.** CMD-RETIREMENT-PROOF, PROC-RETIREMENT, CMD-FAST. + +**Stop condition.** Stop before writes without six passing receipts and exact approval; after writes, stop and restore on manifest drift, extra deletion, active reference, or any integrated-gate failure. + +**Human decision.** Separate explicit owner approval of the exact retirement manifest, deletion targets, recovery archive, restoration proof, commands, and evidence is mandatory. diff --git a/docs/plans/2026-07-22-bran-okf-final-cutover/plan-spec.md b/docs/plans/2026-07-22-bran-okf-final-cutover/plan-spec.md new file mode 100644 index 0000000..4768617 --- /dev/null +++ b/docs/plans/2026-07-22-bran-okf-final-cutover/plan-spec.md @@ -0,0 +1,631 @@ +--- +type: plan-spec +name: bran-okf-final-cutover +status: gathered +date: 2026-07-22 +applies_to: bran +parent_plan: ../2026-07-21-bran-okf-migration/plan-spec.md +planning_provider: codex +planning_model: gpt-5.6-sol +planning_reasoning: high +--- + +## Problem + +The staged BRAN/OKF migration established BRAN-native validation, retrieval, +repair, compatibility, and evidence-based retirement contracts, but the final +cutover is not yet eligible to execute. + +Shared BRAN gates still have known blockers: + +- portable OKF-v0.1 conformance does not yet prove the reserved `index.md` and + `log.md` structures; +- `CMD-FAST` is blocked by test-budget-registry drift; and +- `CMD-PUBLIC` is blocked by a stale repository path. + +Publication, installation, per-consumer parity, and global retirement also lack +one complete reproducible route. Consumer evidence is incomplete in material +ways: AlphaZede Sports needs granular public-boundary policy, BetBot has an +oversized document, retrieval parity is unavailable, and HGTS is absent. + +The final plan must close those gaps without treating unavailable evidence as a +pass, weakening either validation profile, overlapping consumer writers, or +removing compatibility before every consumer is ready. + +## Goal + +Produce an executable, evidence-backed final-cutover route that: + +1. repairs and proves the shared BRAN gates; +2. creates a reproducible, attributable BRAN release and exact-SHA consumer + installation procedure with rollback; +3. migrates and validates each active consumer in one bounded, independently + gated slice; +4. retains every compatibility surface until all consumer gates pass; +5. makes global compatibility retirement a separately approved final slice; + and +6. drafts two bounded upstream OKF proposals without conflating local + `bran-strict` results with portable `okf-v0.1` conformance. + +The planning journey is complete only when `plan-spec.md`, `design.md`, +`seit.md`, `implementation.md`, and `review.html` exist in the canonical plan +directory, validate together, and are returned for owner route selection. +Planning completion does not authorize execution. + +## Current truth + +### Established + +- The completed staged-migration plan is + `docs/plans/2026-07-21-bran-okf-migration/`. +- That plan fixes the active consumer inventory as: + `Alphazedehq`, `alphazede-sports`, `betbot`, `developers`, `hgts`, and + `alphazede-markets`. +- BRAN already distinguishes reserved `index.md` and `log.md` document kinds in + `crates/bran-core/src/bundle.rs`. +- `okf-v0.1` and `bran-strict` are separate profiles; strict-only failures must + not be reported as portable OKF failures. +- The established shared command IDs include: + `CMD-FAST` = `./tools/ci/check.sh --fast` and + `CMD-PUBLIC` = `python3 tools/ci/public_boundary_check.py`, resolved from the + BRAN repository root. +- Legacy retirement is evidence-based rather than date-based. + +### Known failing or blocked + +- **BLK-GATE-001:** portable OKF conformance lacks complete reserved + `index.md`/`log.md` proof. +- **BLK-GATE-002:** `CMD-FAST` has a test-budget-registry blocker. +- **BLK-GATE-003:** `CMD-PUBLIC` has a stale-path blocker. +- **BLK-AZS-001:** AlphaZede Sports lacks accepted granular public-boundary + policy evidence. +- **BLK-BETBOT-001:** BetBot contains an oversized document that prevents a + clean parity claim under the current bounded-input behavior. +- **BLK-PARITY-001:** retrieval parity evidence is unavailable. +- **BLK-HGTS-001:** the HGTS consumer checkout is absent, so its current state + and parity cannot be attested. +- **BLK-PLAN-001:** the current Bearing run state still identifies + `docs/plans/2026-07-23-create-or-resume-the-complete-planning-journey-for-bran-s-final-okf-cuto` + as its validated `planDirectory`, while the owner selected this + `2026-07-22-bran-okf-final-cutover` directory as canonical. The runtime path + must be retargeted or treated only as a temporary receipt pointer before Map + the Route writes artifacts; it is not authority to continue the duplicate. + +These blockers are pending work, not evidence that the affected capability +passed. + +### Not performed or authorized + +No final-cutover implementation, publication, push, deployment, merge, +consumer-repository mutation, public proposal submission, compatibility +removal, release promotion, or global retirement has been performed or +authorized by this plan. + +## Scope + +### In scope for the complete plan + +- BRAN source, conformance fixtures, tests, and CI metadata needed to clear the + shared gates. +- Reproducible build, seal, provenance, publication, installation, + exact-revision verification, and rollback procedures. +- One migration and parity-validation slice for each of the six consumers. +- Consumer-local policy/configuration, hooks, and installation changes only + inside that consumer's later owner-approved slice. +- Retention and eventual separately approved retirement of compatibility + adapters, legacy hooks, `use-okf`, legacy entrypoints, and legacy + configuration. +- Drafts for the upstream OKF bundle-scan-scope and layered-profile-separation + proposals. +- Stable requirement IDs, design decisions, SEIT proof cases, command IDs, + exact write sets, dependency waves, stop conditions, owner approvals, and + rollback criteria across the final artifact set. + +### Out of scope for this planning journey + +- Implementing any planned change. +- Mutating a consumer repository. +- Building or publishing a live release. +- Pushing, deploying, merging, promoting, or installing an artifact. +- Submitting either upstream proposal. +- Removing or disabling compatibility software. +- Starting Explorer or Expedition. +- Creating plan-local prompt artifacts. + +## Authority + +- Gather Supplies may update only this canonical `plan-spec.md`. +- Map the Route may create or update only `design.md`, `seit.md`, + `implementation.md`, and `review.html` in this canonical directory, plus + traceability corrections to this specification if validation requires them. +- The selected top-level planning and review route is + `codex gpt-5.6-sol` with `high` reasoning. +- `implementation.md` must assign the owner-selected execution routes by work + type: `codex gpt-5.6-terra` with `medium` reasoning for coding and + consumer-mutation slices, and `agy agent default` with `medium` + reasoning for documentation, operational, and destructive slices. These are + execution assignments; the planning/review route remains + `codex gpt-5.6-sol` with `high` reasoning. Silent fallback is prohibited. +- No planning artifact grants implementation or external-write authority. +- Each consumer migration, public publication, upstream submission, and global + retirement requires its own explicit owner approval at the gate identified + below. + +## Owner decisions and assumptions + +### Fixed owner decisions + +1. **Canonical directory.** The only plan directory is + `docs/plans/2026-07-22-bran-okf-final-cutover`. Preserve its existing + `plan-spec.md` history, do not continue the auto-slugged duplicate, and leave + no duplicate plan directory when the planning journey completes. +2. **Staged replacement remains binding.** BRAN is canonical, while legacy + surfaces remain compatibility-only until consumer parity and final approval. +3. **No hard retirement date.** Evidence, not elapsed time, controls consumer + completion and global retirement. +4. **Profile separation.** Report `okf-v0.1` and `bran-strict` independently. +5. **Proposal sequencing.** Draft both upstream proposals before publication, + but recommend submission only after portable conformance evidence and a + stable public BRAN release exist. +6. **Execution routing.** Use Terra Medium for coding and consumer-mutation + slices. Use Agy Medium for documentation, operational, and destructive + slices. Record requested and effective identity for every packet and stop + rather than silently substituting a model. + +### Safe assumptions + +- The six-consumer inventory from the staged-migration plan remains + authoritative. +- An unavailable, absent, skipped, oversized, or policy-incomplete check is a + blocked gate, never a pass or implicit waiver. +- HGTS remains in the inventory while absent. Its absence blocks its own gate + and global retirement without invalidating completed evidence for other + consumers. +- AlphaZede Sports boundary granularity and BetBot's oversized document must be + resolved through explicit policy/content handling and proof. The route may + not add an undocumented exemption or silently raise a safety limit. +- Consumer slices may proceed independently after shared gates and publication + prerequisites pass, but no two slices may write the same repository or shared + release surface concurrently. +- The duplicate auto-slugged plan directory is cleanup work for the planning + workflow. It must not be used as a source of authority and must be removed + only after canonical artifacts are present and preservation checks pass. + +## Requirements + +### Shared BRAN gates + +- **REQ-GATE-001 — Reserved-document conformance.** Add portable + `okf-v0.1` valid and invalid proof cases for reserved `index.md` and `log.md` + structures. The proof must run without a provider account or owner-local + configuration and must report `okf-v0.1` independently from `bran-strict`. +- **REQ-GATE-002 — Fast-gate registry.** Define `tools/ci/test-budget.json` as + a deterministic inventory of named CI journeys, direct CI commands, and owned + fixtures—not one registry row per Rust unit test. `CMD-BUDGET` remains the first + fast-gate check in `CMD-FAST`, failing deterministically on any missing or + duplicate journey, direct command, or fixture ownership. All Rust unit tests + remain mandatory through the existing `CMD-FAST` workspace test command, ensuring + that removing per-test registry accounting does not skip or weaken test execution. +- **REQ-GATE-003 — Public-boundary path.** Resolve the `CMD-PUBLIC` stale path + using repository-root-relative, portable path handling. Acceptance requires + the command to pass from a clean checkout without an AlphaZede parent layout + assumption. +- **REQ-GATE-004 — Gate isolation.** Shared gate repairs may write only BRAN + source, fixtures, tests, schemas, and CI metadata explicitly listed in their + implementation slices. They may not mutate consumers or remove compatibility. +- **REQ-GATE-005 — Offline determinism.** All shared conformance, fast-gate, + and public-boundary proofs must remain deterministic and runnable without a + provider account. + +### Publication and provenance + +- **REQ-REL-001 — Reproducible artifact.** Define one source revision, clean + build procedure, toolchain inputs, artifact identity, checksum, and retained + build receipt sufficient for an independent rebuild comparison. +- **REQ-REL-002 — Public-boundary seal.** Publication eligibility requires + clean conformance, `CMD-FAST`, `CMD-PUBLIC`, release-contract, credential, + private-corpus, hidden-truth, and raw-provider-trace checks. +- **REQ-REL-003 — Exact revision.** Bind the release tag or release identifier, + source commit SHA, artifact SHA-256, manifest, and installed binary version + into one verification chain. A tag name alone is insufficient. +- **REQ-REL-004 — Installation.** Define a repeatable per-consumer install or + pin procedure that uses the sealed artifact, verifies its digest before use, + records the prior installation, and produces an installation receipt. +- **REQ-REL-005 — Rollback.** Define and prove restoration to the exact prior + consumer pin/binary/configuration without deleting the new artifact or legacy + fallback until post-rollback validation passes. +- **REQ-REL-006 — Publication approval.** Stop before any public release, + upload, promotion, or public install test until the owner approves the exact + revision, artifact digest, destination, manifest, and public-boundary receipt. + +### Consumer migration and parity + +- **REQ-CONS-001 — One slice per consumer.** `implementation.md` must contain + exactly one bounded migration-and-parity slice for each of: + `Alphazedehq`, `alphazede-sports`, `betbot`, `developers`, `hgts`, and + `alphazede-markets`. +- **REQ-CONS-002 — Non-overlapping writers.** Each consumer slice owns only + that consumer's checkout and consumer-local evidence directory. Shared BRAN + release/proposal surfaces must be completed in earlier exclusive slices. +- **REQ-CONS-003 — Frozen comparison.** Each consumer gate must compare pinned + BRAN-native validation and retrieval with the legacy adapter over identical + frozen inputs, normalize only representation differences, and retain raw and + normalized receipts. +- **REQ-CONS-004 — Required parity.** A consumer passes only when validation + outcomes, retrieval selection/precedence, typed unavailable/conflict states, + hook behavior, installation identity, and rollback proof meet the designed + parity contract. +- **REQ-CONS-005 — Reference audit.** Each passing consumer must retain an + audit of active code, skill, hook, CI, and configuration references. Legacy + references may remain during migration only when identified as active + compatibility surfaces or historical documentation. +- **REQ-CONS-006 — Independent progress.** A blocked consumer does not erase + another consumer's passing evidence, but it blocks global retirement. +- **REQ-CONS-007 — Consumer approval.** Stop before mutating each consumer + until the owner approves that slice's exact repository, revision, write set, + artifact digest, verification commands, and rollback procedure. + +### Explicit evidence gaps + +- **REQ-AZS-001 — Granular boundary policy.** The AlphaZede Sports slice must + define and prove the minimum native BRAN policy granularity needed to express + its public/private path distinctions. It must include positive, negative, + inheritance/precedence, and ambiguous-policy cases and may not weaken the + shared public-boundary gate. +- **REQ-BETBOT-001 — Oversized document.** The BetBot slice must preserve the + current bounded-input safety contract while resolving the oversized document + through an explicitly designed content, policy, or bounded streaming route. + It must prove deterministic failure before the change, bounded success after + it, unchanged content identity where required, and rollback. +- **REQ-PARITY-001 — Retrieval availability.** Retrieval parity must have a + runnable deterministic corpus and retained BRAN/legacy comparison receipt. + If the legacy or native side is unavailable, the consumer remains blocked + with a typed unavailable result. +- **REQ-HGTS-001 — Absent consumer.** The HGTS slice must begin with checkout + identity, revision, and ownership verification. If HGTS remains absent, the + slice returns `unavailable`, performs no substitution or inferred pass, and + keeps global retirement blocked. + +### Compatibility and retirement + +- **REQ-COMPAT-001 — Retention.** Compatibility adapters, legacy hooks, + `use-okf`, legacy entrypoints, and legacy configuration remain present and + recoverable until all six consumer gates pass. +- **REQ-COMPAT-002 — No early disabling.** A migrated consumer may switch its + active pin only after its gate and rollback proof pass; it may not delete the + legacy fallback during its migration slice. +- **REQ-RETIRE-001 — Separate final slice.** Global retirement must be its own + final implementation slice after all consumer receipts and reference audits + pass. It may not be folded into a consumer or release slice. +- **REQ-RETIRE-002 — Explicit approval.** The retirement slice requires + separate owner approval of exact write sets, deletion targets, retained + historical references, rollback archive, verification commands, and the + integrated evidence manifest. +- **REQ-RETIRE-003 — Rollback before removal.** Prove restoration from the + proposed retirement state before deleting or disabling any compatibility + surface. Failed restoration or any active reference stops retirement. + +### Upstream proposals + +- **REQ-UPSTREAM-001 — Bundle scan scope.** Draft a proposal that specifies + whether portable OKF scanning applies to one bundle root, nested bundle roots, + or a repository-wide discovery set, including deterministic inclusion, + exclusion, symlink, and reserved-document behavior. +- **REQ-UPSTREAM-002 — Layered profiles.** Draft a proposal that separates the + portable `okf-v0.1` floor from additive implementation profiles such as + `bran-strict`, with independent results and no reclassification of strict-only + failures as portable failures. +- **REQ-UPSTREAM-003 — Submission gate.** Proposal drafts are local planning + artifacts. Recommend submission only after REQ-GATE-001 through + REQ-GATE-005 pass and an owner-approved stable public release satisfies + REQ-REL-001 through REQ-REL-006. Submission still requires separate owner + approval. + +### Route and artifact quality + +- **REQ-PLAN-001 — Complete artifact set.** Map the Route must produce + `design.md`, `seit.md`, `implementation.md`, and `review.html` beside this + specification; no prompt artifacts are required. +- **REQ-PLAN-002 — Traceability.** Every requirement must map to at least one + design decision, SEIT proof case, implementation slice, command/procedure ID, + retained evidence path, stop condition, and rollback or explicit + non-applicability. +- **REQ-PLAN-003 — Command registry.** SEIT must bind exact repository-root + invocations to stable IDs, including at minimum: + `CMD-OKF-PORTABLE`, `CMD-FAST`, `CMD-PUBLIC`, `CMD-RELEASE-BUILD`, + `CMD-RELEASE-SEAL`, `CMD-INSTALL-VERIFY`, `CMD-EXACT-SHA`, + `CMD-ROLLBACK`, six consumer parity procedure IDs, `CMD-REFERENCE-AUDIT`, + and `CMD-RETIREMENT-PROOF`. +- **REQ-PLAN-004 — Waves and write sets.** Implementation must give every + slice an exact write set, dependencies, route/model/reasoning assignment, + semantic verification, cross-cutting commands, retained evidence, stop + condition, owner gate, and rollback. Parallel slices must have disjoint + writers. +- **REQ-PLAN-005 — Review.** Generate a baseline `review.html` after design and + SEIT, regenerate it after implementation, and validate the final artifact set + before returning for owner selection. +- **REQ-PLAN-006 — Canonical cleanup.** Before planning completion, verify all + canonical artifacts are present in + `docs/plans/2026-07-22-bran-okf-final-cutover`, preserve unrelated owner + changes, and remove the duplicate auto-slugged plan directory without + force-removing any unrelated evidence. +- **REQ-PLAN-007 — Planning stop.** Do not start Explorer or Expedition. + Return the validated plan and final review for explicit owner route selection. + +## Acceptance criteria + +- **AC-001:** All requirements have complete bidirectional traceability across + the final five artifacts. +- **AC-002:** The shared gate route proves portable reserved-document + conformance and clears `CMD-FAST` and `CMD-PUBLIC` without parent-layout or + provider-account dependencies. +- **AC-003:** The publication route binds source SHA, artifact digest, manifest, + installation identity, and rollback receipt and stops at an explicit owner + approval. +- **AC-004:** Exactly six consumer slices exist, their write sets do not + overlap, and every slice has validation, retrieval, installation, reference + audit, and rollback proof or a typed blocking result. +- **AC-005:** AlphaZede Sports, BetBot, retrieval parity, and HGTS gaps each map + to explicit proof cases and stop conditions; none is represented as passed + while evidence is unavailable. +- **AC-006:** Compatibility remains until every consumer passes; global + retirement is a separate owner-approved slice with successful rollback proof. +- **AC-007:** Both upstream proposal drafts exist before publication planning + completes, while submission remains gated on portable conformance, stable + public release, and separate owner approval. +- **AC-008:** `okf-v0.1` and `bran-strict` results remain separately visible in + commands, receipts, reviews, and release claims. +- **AC-009:** The final planning artifact set validates in the canonical + directory, the duplicate auto-slugged directory is absent, and no product or + consumer code was changed by planning. +- **AC-010:** The journey stops after owner-facing review and does not begin an + execution route. + +## Required proof classes for SEIT + +Map the Route must include at least: + +- valid and invalid reserved `index.md` and `log.md` portable fixtures; +- registry-complete and intentionally unregistered-test cases; +- repository-root and relocated-checkout public-boundary cases; +- reproducible-build, tampered-artifact, wrong-SHA, wrong-tag, interrupted + install, and exact rollback cases; +- one positive and one negative validation/retrieval parity case per consumer; +- typed unavailable cases for missing retrieval capability and absent HGTS; +- granular boundary allow/deny/ambiguous cases for AlphaZede Sports; +- oversized/rejected, bounded-success, identity, and rollback cases for BetBot; +- legacy reference present/allowed, active/unexpected, and absent cases; +- early-retirement rejection and retirement-rollback cases; and +- independent `okf-v0.1` pass/fail and `bran-strict` pass/fail combinations. + +## Stop conditions + +Stop the affected route or slice when: + +- a required repository, revision, artifact, policy, or parity runner is + unavailable or cannot be identified; +- a command depends on credentials, provider access, owner-local memory, or an + undeclared parent-directory layout; +- the proposed write set overlaps another active writer or exceeds its + repository boundary; +- checksum, exact-SHA, manifest, public-boundary, validation, retrieval, + installation, reference-audit, or rollback evidence fails; +- a plan attempts to classify unavailable evidence as passing; +- an action would publish, push, deploy, merge, mutate a consumer, submit an + upstream proposal, or remove compatibility without its explicit owner gate; +- `bran-strict` evidence is used to claim `okf-v0.1` conformance; or +- the active planning runtime requires new route artifacts to be written in the + rejected auto-slugged directory instead of this canonical directory; or +- preserving unrelated owner changes cannot be proven. + +## Owner approval gates + +The route must stop for explicit owner approval before: + +1. publishing or promoting the exact sealed BRAN release; +2. mutating each of the six consumers; +3. submitting either upstream proposal; and +4. executing the final global retirement slice. + +A recommendation or passing plan review is advice, not approval. + +## Rollback criteria + +- Shared BRAN repairs must be revertible within their exact write sets and leave + existing compatibility behavior callable. +- Release rollback must restore the prior artifact pin and verify the restored + digest and behavior before declaring success. +- Consumer rollback must restore exact prior bytes/configuration/pin and rerun + that consumer's legacy and BRAN gate; retained compatibility is the fallback. +- Retirement rollback must be proven before removal and must restore all active + entrypoints, hooks, skills, configurations, pins, and reference integrity. +- Any byte, digest, behavior, or reference mismatch is rollback failure and + blocks forward progress. + +## Evidence consulted + +- `docs/plans/AGENTS.md` +- `docs/plans/2026-07-21-bran-okf-migration/plan-spec.md` +- `docs/plans/2026-07-21-bran-okf-migration/design.md` +- `docs/plans/2026-07-21-bran-okf-migration/seit.md` +- `docs/plans/2026-07-21-bran-okf-migration/implementation.md` +- `crates/bran-core/src/bundle.rs` +- `crates/bran-core/src/profile.rs` +- `fixtures/conformance/` +- `tools/ci/check.sh` +- `tools/ci/test-budget.json` +- `tools/ci/test_budget_check.py` +- `tools/ci/public_boundary_check.py` + +## Handoff to Map the Route + +### Role and outcome + +Act as the bounded Bearing Map-the-Route planning agent. Produce and validate +the remaining four artifacts in this canonical directory, then stop with an +owner-reviewable route and no execution. + +### Execute now + +1. Read this specification and the completed staged-migration artifacts. +2. Write `design.md` with the minimum decisions needed to satisfy every + requirement and preserve the authority boundaries. +3. Write `seit.md` with exact command/procedure IDs, proof cases, evidence + paths, and complete traceability. +4. Generate the baseline `review.html`. +5. Write `implementation.md` with bounded write sets, dependency waves, + disjoint consumer writers, supported route assignments, owner gates, stop + conditions, and rollback. +6. Regenerate `review.html`, validate all five artifacts, consolidate only + canonical artifacts, and remove the duplicate plan directory. +7. Return the validated artifacts for owner selection. Do not start Explorer or + Expedition. + +### Verification and evidence + +Retain the final traceability result, artifact validation result, review +generation result, and canonical-directory inventory. Clearly separate planned, +currently failing, unavailable, and proven states. + +### Return or stop conditions + +Return only when the five canonical artifacts validate and the duplicate plan +directory is absent. Stop earlier on any authority expansion, unresolved +material owner decision, unavailable required evidence that changes the route, +inability to preserve unrelated owner changes, or a runtime plan-directory +constraint that would force route artifacts into the rejected duplicate. + +## Owner review amendment — 2026-07-23 + +This append-only amendment records the owner's requested planning-package +correction. It supersedes earlier handoff instructions only where they imply +that completed design, SEIT, or implementation work should be repeated. + +### Current truth + +- The canonical directory + `docs/plans/2026-07-22-bran-okf-final-cutover` contains the current + `plan-spec.md`, `design.md`, `seit.md`, and `implementation.md`, but does not + contain `review.html`. +- The temporary Bearing runtime directory + `docs/plans/2026-07-23-create-or-resume-the-complete-planning-journey-for-bran-s-final-okf-cuto` + contains those four Markdown sources plus a generated `review.html`. +- At inspection, each corresponding Markdown source in the two directories was + the same regular-file inode and therefore byte-identical. The observed + digests before this amendment were: + `plan-spec.md` = + `1f84e28b3b9be9b973fb2b2e969ac1722c220e81469bfb392e3f4082a79f37b0`, + `design.md` = + `db9f3ac640d6ccb6428ec30599edcb3385f664121f1d5a8dd892460d9af031a3`, + `seit.md` = + `59026ab4da817496dd97cddd5bf529e73803c8c2e414ff858f56e3545a71b0d4`, + and `implementation.md` = + `a4906dea4afd3c40e5cdc89038c13d81db5f9ee0cf14ddcde78e91e17eb04a7f`. +- The runtime `review.html` digest observed before this amendment was + `87ea2cb4531640015cfcbe9cb6998d9e0ea36aaec23de3ae354f3f37014cb35f`. + This plan-spec amendment makes that review stale until Bearing regenerates + it from the four current canonical sources. +- No implementation slice has been executed. No product code, consumer + repository, publication target, compatibility surface, or upstream + submission was changed by this planning correction. + +### Fixed owner decision + +The owner has not approved execution. Bearing must deterministically regenerate +the complete `review.html` from the current canonical `plan-spec.md`, +`design.md`, `seit.md`, and `implementation.md`, place the resulting regular +file in the canonical directory, and keep any runtime receipt-mirror copy +byte-identical. The four canonical Markdown sources must remain unchanged after +this amendment unless the exact validator reproduces a defect that requires a +minimal traceability correction. + +### Additional requirements + +- **REQ-PLAN-008 — Canonical deterministic review.** Bearing's deterministic + review generator must render `review.html` from the exact current bytes of + the four canonical Markdown sources. The canonical review must embed all four + complete sources, expose working relative artifact links, and remain + unedited by hand. +- **REQ-PLAN-009 — Source preservation.** This append-only owner amendment is + the only authorized Markdown-source change during the review repair. + `design.md`, `seit.md`, and `implementation.md` must retain the digests + recorded above. Any further source change requires a reproduced validator + defect, the narrowest traceability correction, an explicit retained diff, + and another deterministic review generation. +- **REQ-PLAN-010 — Canonical package validation.** Validate the five canonical + artifacts together after review generation and retain the exact validator + output, canonical inventory, source/review digests, embedded-source equality + result, relative-link result, and runtime-mirror equality result. A runtime + review alone is not canonical completion. + +### Additional acceptance criteria + +- **AC-011:** Canonical `review.html` exists as a regular file and is + byte-for-byte the deterministic render of the current canonical + `plan-spec.md`, `design.md`, `seit.md`, and `implementation.md`. +- **AC-012:** The exact five-artifact validator passes in the canonical + directory; `design.md`, `seit.md`, and `implementation.md` retain their + recorded digests; any still-required runtime mirror is byte-identical; and no + implementation or external action begins. + +## Superseding handoff to Map the Route + +### Role and outcome + +Act as the bounded Bearing review-repair agent. Produce the missing canonical +deterministic review, validate the five canonical artifacts together, reconcile +the temporary runtime receipt mirror, and stop without execution. + +### Current truth + +Design, SEIT, and implementation drafting are complete and must not be +repeated. The four Markdown sources are available at both paths as shared +regular files. Canonical `review.html` is missing, and the runtime review is +stale because this amendment changed `plan-spec.md`. + +### Scope and authority + +- Use the selected planning/review route `codex gpt-5.6-sol` with `high` + reasoning. +- Bearing may generate `review.html` and place byte-identical regular-file + instances at the canonical and temporarily required runtime paths. +- Do not hand-edit `review.html`. +- Do not change `design.md`, `seit.md`, or `implementation.md` unless the exact + validator first reproduces a defect. If it does, stop and report the defect + before expanding beyond the narrowest traceability repair. +- Do not execute Explorer, Expedition, any implementation slice, publication, + push, deploy, merge, consumer mutation, proposal submission, or compatibility + retirement. + +### Execute now + +1. Capture the current four canonical source digests and confirm the + corresponding runtime sources are byte-identical regular files. +2. Run Bearing's deterministic review generator from those current source + bytes. +3. Materialize the generated `review.html` as a regular file in the canonical + directory and keep the runtime receipt-mirror review byte-identical while + Bearing still requires that path. +4. Run the exact five-artifact validator against the canonical directory and + retain its complete output. +5. Verify embedded-source equality, working relative links, source-preservation + digests, review equality, and a planning-only scoped status. +6. Remove the temporary runtime directory only when Bearing no longer requires + it and preservation can be proven; otherwise return it as the sole remaining + cleanup blocker rather than deleting required state. + +### Verification and evidence + +Return the canonical five-artifact inventory, exact validator output, all five +digests, source-preservation comparison, canonical/runtime review equality, +relative-link result, and scoped repository status. Label the generated review +and validation as planning evidence, not implementation evidence. + +### Return or stop conditions + +Return for owner route selection only after AC-011 and AC-012 pass. Stop on a +deterministic-render mismatch, missing or stale embedded source, broken +artifact link, non-identical required mirror, unexpected Markdown-source +change, validator failure requiring non-traceability work, authority expansion, +or any attempt to begin execution. A recommendation or passing review is not +owner approval. diff --git a/docs/plans/2026-07-22-bran-okf-final-cutover/review.html b/docs/plans/2026-07-22-bran-okf-final-cutover/review.html new file mode 100644 index 0000000..04ad569 --- /dev/null +++ b/docs/plans/2026-07-22-bran-okf-final-cutover/review.html @@ -0,0 +1,2095 @@ + +Bearing planning review

Bearing planning review

This deterministic view is generated from the four current planning sources.

Plan maps

Planning flow

Text equivalent: acceptance and risks drive design contracts; SEIT maps those contracts to proof; implementation slices reference the map; final QA records actual evidence.

Traceability map

Text equivalent: stable IDs connect each requirement or risk to its design boundary, positive and negative test cases, command, evidence, and bounded execution slice.

Complete planning artifacts

These are the complete source documents used for this review.

plan-spec.md
---
+type: plan-spec
+name: bran-okf-final-cutover
+status: gathered
+date: 2026-07-22
+applies_to: bran
+parent_plan: ../2026-07-21-bran-okf-migration/plan-spec.md
+planning_provider: codex
+planning_model: gpt-5.6-sol
+planning_reasoning: high
+---
+
+## Problem
+
+The staged BRAN/OKF migration established BRAN-native validation, retrieval,
+repair, compatibility, and evidence-based retirement contracts, but the final
+cutover is not yet eligible to execute.
+
+Shared BRAN gates still have known blockers:
+
+- portable OKF-v0.1 conformance does not yet prove the reserved `index.md` and
+  `log.md` structures;
+- `CMD-FAST` is blocked by test-budget-registry drift; and
+- `CMD-PUBLIC` is blocked by a stale repository path.
+
+Publication, installation, per-consumer parity, and global retirement also lack
+one complete reproducible route. Consumer evidence is incomplete in material
+ways: AlphaZede Sports needs granular public-boundary policy, BetBot has an
+oversized document, retrieval parity is unavailable, and HGTS is absent.
+
+The final plan must close those gaps without treating unavailable evidence as a
+pass, weakening either validation profile, overlapping consumer writers, or
+removing compatibility before every consumer is ready.
+
+## Goal
+
+Produce an executable, evidence-backed final-cutover route that:
+
+1. repairs and proves the shared BRAN gates;
+2. creates a reproducible, attributable BRAN release and exact-SHA consumer
+   installation procedure with rollback;
+3. migrates and validates each active consumer in one bounded, independently
+   gated slice;
+4. retains every compatibility surface until all consumer gates pass;
+5. makes global compatibility retirement a separately approved final slice;
+   and
+6. drafts two bounded upstream OKF proposals without conflating local
+   `bran-strict` results with portable `okf-v0.1` conformance.
+
+The planning journey is complete only when `plan-spec.md`, `design.md`,
+`seit.md`, `implementation.md`, and `review.html` exist in the canonical plan
+directory, validate together, and are returned for owner route selection.
+Planning completion does not authorize execution.
+
+## Current truth
+
+### Established
+
+- The completed staged-migration plan is
+  `docs/plans/2026-07-21-bran-okf-migration/`.
+- That plan fixes the active consumer inventory as:
+  `Alphazedehq`, `alphazede-sports`, `betbot`, `developers`, `hgts`, and
+  `alphazede-markets`.
+- BRAN already distinguishes reserved `index.md` and `log.md` document kinds in
+  `crates/bran-core/src/bundle.rs`.
+- `okf-v0.1` and `bran-strict` are separate profiles; strict-only failures must
+  not be reported as portable OKF failures.
+- The established shared command IDs include:
+  `CMD-FAST` = `./tools/ci/check.sh --fast` and
+  `CMD-PUBLIC` = `python3 tools/ci/public_boundary_check.py`, resolved from the
+  BRAN repository root.
+- Legacy retirement is evidence-based rather than date-based.
+
+### Known failing or blocked
+
+- **BLK-GATE-001:** portable OKF conformance lacks complete reserved
+  `index.md`/`log.md` proof.
+- **BLK-GATE-002:** `CMD-FAST` has a test-budget-registry blocker.
+- **BLK-GATE-003:** `CMD-PUBLIC` has a stale-path blocker.
+- **BLK-AZS-001:** AlphaZede Sports lacks accepted granular public-boundary
+  policy evidence.
+- **BLK-BETBOT-001:** BetBot contains an oversized document that prevents a
+  clean parity claim under the current bounded-input behavior.
+- **BLK-PARITY-001:** retrieval parity evidence is unavailable.
+- **BLK-HGTS-001:** the HGTS consumer checkout is absent, so its current state
+  and parity cannot be attested.
+- **BLK-PLAN-001:** the current Bearing run state still identifies
+  `docs/plans/2026-07-23-create-or-resume-the-complete-planning-journey-for-bran-s-final-okf-cuto`
+  as its validated `planDirectory`, while the owner selected this
+  `2026-07-22-bran-okf-final-cutover` directory as canonical. The runtime path
+  must be retargeted or treated only as a temporary receipt pointer before Map
+  the Route writes artifacts; it is not authority to continue the duplicate.
+
+These blockers are pending work, not evidence that the affected capability
+passed.
+
+### Not performed or authorized
+
+No final-cutover implementation, publication, push, deployment, merge,
+consumer-repository mutation, public proposal submission, compatibility
+removal, release promotion, or global retirement has been performed or
+authorized by this plan.
+
+## Scope
+
+### In scope for the complete plan
+
+- BRAN source, conformance fixtures, tests, and CI metadata needed to clear the
+  shared gates.
+- Reproducible build, seal, provenance, publication, installation,
+  exact-revision verification, and rollback procedures.
+- One migration and parity-validation slice for each of the six consumers.
+- Consumer-local policy/configuration, hooks, and installation changes only
+  inside that consumer's later owner-approved slice.
+- Retention and eventual separately approved retirement of compatibility
+  adapters, legacy hooks, `use-okf`, legacy entrypoints, and legacy
+  configuration.
+- Drafts for the upstream OKF bundle-scan-scope and layered-profile-separation
+  proposals.
+- Stable requirement IDs, design decisions, SEIT proof cases, command IDs,
+  exact write sets, dependency waves, stop conditions, owner approvals, and
+  rollback criteria across the final artifact set.
+
+### Out of scope for this planning journey
+
+- Implementing any planned change.
+- Mutating a consumer repository.
+- Building or publishing a live release.
+- Pushing, deploying, merging, promoting, or installing an artifact.
+- Submitting either upstream proposal.
+- Removing or disabling compatibility software.
+- Starting Explorer or Expedition.
+- Creating plan-local prompt artifacts.
+
+## Authority
+
+- Gather Supplies may update only this canonical `plan-spec.md`.
+- Map the Route may create or update only `design.md`, `seit.md`,
+  `implementation.md`, and `review.html` in this canonical directory, plus
+  traceability corrections to this specification if validation requires them.
+- The selected top-level planning and review route is
+  `codex gpt-5.6-sol` with `high` reasoning.
+- `implementation.md` must assign the owner-selected execution routes by work
+  type: `codex gpt-5.6-terra` with `medium` reasoning for coding and
+  consumer-mutation slices, and `agy agent default` with `medium`
+  reasoning for documentation, operational, and destructive slices. These are
+  execution assignments; the planning/review route remains
+  `codex gpt-5.6-sol` with `high` reasoning. Silent fallback is prohibited.
+- No planning artifact grants implementation or external-write authority.
+- Each consumer migration, public publication, upstream submission, and global
+  retirement requires its own explicit owner approval at the gate identified
+  below.
+
+## Owner decisions and assumptions
+
+### Fixed owner decisions
+
+1. **Canonical directory.** The only plan directory is
+   `docs/plans/2026-07-22-bran-okf-final-cutover`. Preserve its existing
+   `plan-spec.md` history, do not continue the auto-slugged duplicate, and leave
+   no duplicate plan directory when the planning journey completes.
+2. **Staged replacement remains binding.** BRAN is canonical, while legacy
+   surfaces remain compatibility-only until consumer parity and final approval.
+3. **No hard retirement date.** Evidence, not elapsed time, controls consumer
+   completion and global retirement.
+4. **Profile separation.** Report `okf-v0.1` and `bran-strict` independently.
+5. **Proposal sequencing.** Draft both upstream proposals before publication,
+   but recommend submission only after portable conformance evidence and a
+   stable public BRAN release exist.
+6. **Execution routing.** Use Terra Medium for coding and consumer-mutation
+   slices. Use Agy Medium for documentation, operational, and destructive
+   slices. Record requested and effective identity for every packet and stop
+   rather than silently substituting a model.
+
+### Safe assumptions
+
+- The six-consumer inventory from the staged-migration plan remains
+  authoritative.
+- An unavailable, absent, skipped, oversized, or policy-incomplete check is a
+  blocked gate, never a pass or implicit waiver.
+- HGTS remains in the inventory while absent. Its absence blocks its own gate
+  and global retirement without invalidating completed evidence for other
+  consumers.
+- AlphaZede Sports boundary granularity and BetBot's oversized document must be
+  resolved through explicit policy/content handling and proof. The route may
+  not add an undocumented exemption or silently raise a safety limit.
+- Consumer slices may proceed independently after shared gates and publication
+  prerequisites pass, but no two slices may write the same repository or shared
+  release surface concurrently.
+- The duplicate auto-slugged plan directory is cleanup work for the planning
+  workflow. It must not be used as a source of authority and must be removed
+  only after canonical artifacts are present and preservation checks pass.
+
+## Requirements
+
+### Shared BRAN gates
+
+- **REQ-GATE-001 — Reserved-document conformance.** Add portable
+  `okf-v0.1` valid and invalid proof cases for reserved `index.md` and `log.md`
+  structures. The proof must run without a provider account or owner-local
+  configuration and must report `okf-v0.1` independently from `bran-strict`.
+- **REQ-GATE-002 — Fast-gate registry.** Define `tools/ci/test-budget.json` as
+  a deterministic inventory of named CI journeys, direct CI commands, and owned
+  fixtures—not one registry row per Rust unit test. `CMD-BUDGET` remains the first
+  fast-gate check in `CMD-FAST`, failing deterministically on any missing or
+  duplicate journey, direct command, or fixture ownership. All Rust unit tests
+  remain mandatory through the existing `CMD-FAST` workspace test command, ensuring
+  that removing per-test registry accounting does not skip or weaken test execution.
+- **REQ-GATE-003 — Public-boundary path.** Resolve the `CMD-PUBLIC` stale path
+  using repository-root-relative, portable path handling. Acceptance requires
+  the command to pass from a clean checkout without an AlphaZede parent layout
+  assumption.
+- **REQ-GATE-004 — Gate isolation.** Shared gate repairs may write only BRAN
+  source, fixtures, tests, schemas, and CI metadata explicitly listed in their
+  implementation slices. They may not mutate consumers or remove compatibility.
+- **REQ-GATE-005 — Offline determinism.** All shared conformance, fast-gate,
+  and public-boundary proofs must remain deterministic and runnable without a
+  provider account.
+
+### Publication and provenance
+
+- **REQ-REL-001 — Reproducible artifact.** Define one source revision, clean
+  build procedure, toolchain inputs, artifact identity, checksum, and retained
+  build receipt sufficient for an independent rebuild comparison.
+- **REQ-REL-002 — Public-boundary seal.** Publication eligibility requires
+  clean conformance, `CMD-FAST`, `CMD-PUBLIC`, release-contract, credential,
+  private-corpus, hidden-truth, and raw-provider-trace checks.
+- **REQ-REL-003 — Exact revision.** Bind the release tag or release identifier,
+  source commit SHA, artifact SHA-256, manifest, and installed binary version
+  into one verification chain. A tag name alone is insufficient.
+- **REQ-REL-004 — Installation.** Define a repeatable per-consumer install or
+  pin procedure that uses the sealed artifact, verifies its digest before use,
+  records the prior installation, and produces an installation receipt.
+- **REQ-REL-005 — Rollback.** Define and prove restoration to the exact prior
+  consumer pin/binary/configuration without deleting the new artifact or legacy
+  fallback until post-rollback validation passes.
+- **REQ-REL-006 — Publication approval.** Stop before any public release,
+  upload, promotion, or public install test until the owner approves the exact
+  revision, artifact digest, destination, manifest, and public-boundary receipt.
+
+### Consumer migration and parity
+
+- **REQ-CONS-001 — One slice per consumer.** `implementation.md` must contain
+  exactly one bounded migration-and-parity slice for each of:
+  `Alphazedehq`, `alphazede-sports`, `betbot`, `developers`, `hgts`, and
+  `alphazede-markets`.
+- **REQ-CONS-002 — Non-overlapping writers.** Each consumer slice owns only
+  that consumer's checkout and consumer-local evidence directory. Shared BRAN
+  release/proposal surfaces must be completed in earlier exclusive slices.
+- **REQ-CONS-003 — Frozen comparison.** Each consumer gate must compare pinned
+  BRAN-native validation and retrieval with the legacy adapter over identical
+  frozen inputs, normalize only representation differences, and retain raw and
+  normalized receipts.
+- **REQ-CONS-004 — Required parity.** A consumer passes only when validation
+  outcomes, retrieval selection/precedence, typed unavailable/conflict states,
+  hook behavior, installation identity, and rollback proof meet the designed
+  parity contract.
+- **REQ-CONS-005 — Reference audit.** Each passing consumer must retain an
+  audit of active code, skill, hook, CI, and configuration references. Legacy
+  references may remain during migration only when identified as active
+  compatibility surfaces or historical documentation.
+- **REQ-CONS-006 — Independent progress.** A blocked consumer does not erase
+  another consumer's passing evidence, but it blocks global retirement.
+- **REQ-CONS-007 — Consumer approval.** Stop before mutating each consumer
+  until the owner approves that slice's exact repository, revision, write set,
+  artifact digest, verification commands, and rollback procedure.
+
+### Explicit evidence gaps
+
+- **REQ-AZS-001 — Granular boundary policy.** The AlphaZede Sports slice must
+  define and prove the minimum native BRAN policy granularity needed to express
+  its public/private path distinctions. It must include positive, negative,
+  inheritance/precedence, and ambiguous-policy cases and may not weaken the
+  shared public-boundary gate.
+- **REQ-BETBOT-001 — Oversized document.** The BetBot slice must preserve the
+  current bounded-input safety contract while resolving the oversized document
+  through an explicitly designed content, policy, or bounded streaming route.
+  It must prove deterministic failure before the change, bounded success after
+  it, unchanged content identity where required, and rollback.
+- **REQ-PARITY-001 — Retrieval availability.** Retrieval parity must have a
+  runnable deterministic corpus and retained BRAN/legacy comparison receipt.
+  If the legacy or native side is unavailable, the consumer remains blocked
+  with a typed unavailable result.
+- **REQ-HGTS-001 — Absent consumer.** The HGTS slice must begin with checkout
+  identity, revision, and ownership verification. If HGTS remains absent, the
+  slice returns `unavailable`, performs no substitution or inferred pass, and
+  keeps global retirement blocked.
+
+### Compatibility and retirement
+
+- **REQ-COMPAT-001 — Retention.** Compatibility adapters, legacy hooks,
+  `use-okf`, legacy entrypoints, and legacy configuration remain present and
+  recoverable until all six consumer gates pass.
+- **REQ-COMPAT-002 — No early disabling.** A migrated consumer may switch its
+  active pin only after its gate and rollback proof pass; it may not delete the
+  legacy fallback during its migration slice.
+- **REQ-RETIRE-001 — Separate final slice.** Global retirement must be its own
+  final implementation slice after all consumer receipts and reference audits
+  pass. It may not be folded into a consumer or release slice.
+- **REQ-RETIRE-002 — Explicit approval.** The retirement slice requires
+  separate owner approval of exact write sets, deletion targets, retained
+  historical references, rollback archive, verification commands, and the
+  integrated evidence manifest.
+- **REQ-RETIRE-003 — Rollback before removal.** Prove restoration from the
+  proposed retirement state before deleting or disabling any compatibility
+  surface. Failed restoration or any active reference stops retirement.
+
+### Upstream proposals
+
+- **REQ-UPSTREAM-001 — Bundle scan scope.** Draft a proposal that specifies
+  whether portable OKF scanning applies to one bundle root, nested bundle roots,
+  or a repository-wide discovery set, including deterministic inclusion,
+  exclusion, symlink, and reserved-document behavior.
+- **REQ-UPSTREAM-002 — Layered profiles.** Draft a proposal that separates the
+  portable `okf-v0.1` floor from additive implementation profiles such as
+  `bran-strict`, with independent results and no reclassification of strict-only
+  failures as portable failures.
+- **REQ-UPSTREAM-003 — Submission gate.** Proposal drafts are local planning
+  artifacts. Recommend submission only after REQ-GATE-001 through
+  REQ-GATE-005 pass and an owner-approved stable public release satisfies
+  REQ-REL-001 through REQ-REL-006. Submission still requires separate owner
+  approval.
+
+### Route and artifact quality
+
+- **REQ-PLAN-001 — Complete artifact set.** Map the Route must produce
+  `design.md`, `seit.md`, `implementation.md`, and `review.html` beside this
+  specification; no prompt artifacts are required.
+- **REQ-PLAN-002 — Traceability.** Every requirement must map to at least one
+  design decision, SEIT proof case, implementation slice, command/procedure ID,
+  retained evidence path, stop condition, and rollback or explicit
+  non-applicability.
+- **REQ-PLAN-003 — Command registry.** SEIT must bind exact repository-root
+  invocations to stable IDs, including at minimum:
+  `CMD-OKF-PORTABLE`, `CMD-FAST`, `CMD-PUBLIC`, `CMD-RELEASE-BUILD`,
+  `CMD-RELEASE-SEAL`, `CMD-INSTALL-VERIFY`, `CMD-EXACT-SHA`,
+  `CMD-ROLLBACK`, six consumer parity procedure IDs, `CMD-REFERENCE-AUDIT`,
+  and `CMD-RETIREMENT-PROOF`.
+- **REQ-PLAN-004 — Waves and write sets.** Implementation must give every
+  slice an exact write set, dependencies, route/model/reasoning assignment,
+  semantic verification, cross-cutting commands, retained evidence, stop
+  condition, owner gate, and rollback. Parallel slices must have disjoint
+  writers.
+- **REQ-PLAN-005 — Review.** Generate a baseline `review.html` after design and
+  SEIT, regenerate it after implementation, and validate the final artifact set
+  before returning for owner selection.
+- **REQ-PLAN-006 — Canonical cleanup.** Before planning completion, verify all
+  canonical artifacts are present in
+  `docs/plans/2026-07-22-bran-okf-final-cutover`, preserve unrelated owner
+  changes, and remove the duplicate auto-slugged plan directory without
+  force-removing any unrelated evidence.
+- **REQ-PLAN-007 — Planning stop.** Do not start Explorer or Expedition.
+  Return the validated plan and final review for explicit owner route selection.
+
+## Acceptance criteria
+
+- **AC-001:** All requirements have complete bidirectional traceability across
+  the final five artifacts.
+- **AC-002:** The shared gate route proves portable reserved-document
+  conformance and clears `CMD-FAST` and `CMD-PUBLIC` without parent-layout or
+  provider-account dependencies.
+- **AC-003:** The publication route binds source SHA, artifact digest, manifest,
+  installation identity, and rollback receipt and stops at an explicit owner
+  approval.
+- **AC-004:** Exactly six consumer slices exist, their write sets do not
+  overlap, and every slice has validation, retrieval, installation, reference
+  audit, and rollback proof or a typed blocking result.
+- **AC-005:** AlphaZede Sports, BetBot, retrieval parity, and HGTS gaps each map
+  to explicit proof cases and stop conditions; none is represented as passed
+  while evidence is unavailable.
+- **AC-006:** Compatibility remains until every consumer passes; global
+  retirement is a separate owner-approved slice with successful rollback proof.
+- **AC-007:** Both upstream proposal drafts exist before publication planning
+  completes, while submission remains gated on portable conformance, stable
+  public release, and separate owner approval.
+- **AC-008:** `okf-v0.1` and `bran-strict` results remain separately visible in
+  commands, receipts, reviews, and release claims.
+- **AC-009:** The final planning artifact set validates in the canonical
+  directory, the duplicate auto-slugged directory is absent, and no product or
+  consumer code was changed by planning.
+- **AC-010:** The journey stops after owner-facing review and does not begin an
+  execution route.
+
+## Required proof classes for SEIT
+
+Map the Route must include at least:
+
+- valid and invalid reserved `index.md` and `log.md` portable fixtures;
+- registry-complete and intentionally unregistered-test cases;
+- repository-root and relocated-checkout public-boundary cases;
+- reproducible-build, tampered-artifact, wrong-SHA, wrong-tag, interrupted
+  install, and exact rollback cases;
+- one positive and one negative validation/retrieval parity case per consumer;
+- typed unavailable cases for missing retrieval capability and absent HGTS;
+- granular boundary allow/deny/ambiguous cases for AlphaZede Sports;
+- oversized/rejected, bounded-success, identity, and rollback cases for BetBot;
+- legacy reference present/allowed, active/unexpected, and absent cases;
+- early-retirement rejection and retirement-rollback cases; and
+- independent `okf-v0.1` pass/fail and `bran-strict` pass/fail combinations.
+
+## Stop conditions
+
+Stop the affected route or slice when:
+
+- a required repository, revision, artifact, policy, or parity runner is
+  unavailable or cannot be identified;
+- a command depends on credentials, provider access, owner-local memory, or an
+  undeclared parent-directory layout;
+- the proposed write set overlaps another active writer or exceeds its
+  repository boundary;
+- checksum, exact-SHA, manifest, public-boundary, validation, retrieval,
+  installation, reference-audit, or rollback evidence fails;
+- a plan attempts to classify unavailable evidence as passing;
+- an action would publish, push, deploy, merge, mutate a consumer, submit an
+  upstream proposal, or remove compatibility without its explicit owner gate;
+- `bran-strict` evidence is used to claim `okf-v0.1` conformance; or
+- the active planning runtime requires new route artifacts to be written in the
+  rejected auto-slugged directory instead of this canonical directory; or
+- preserving unrelated owner changes cannot be proven.
+
+## Owner approval gates
+
+The route must stop for explicit owner approval before:
+
+1. publishing or promoting the exact sealed BRAN release;
+2. mutating each of the six consumers;
+3. submitting either upstream proposal; and
+4. executing the final global retirement slice.
+
+A recommendation or passing plan review is advice, not approval.
+
+## Rollback criteria
+
+- Shared BRAN repairs must be revertible within their exact write sets and leave
+  existing compatibility behavior callable.
+- Release rollback must restore the prior artifact pin and verify the restored
+  digest and behavior before declaring success.
+- Consumer rollback must restore exact prior bytes/configuration/pin and rerun
+  that consumer's legacy and BRAN gate; retained compatibility is the fallback.
+- Retirement rollback must be proven before removal and must restore all active
+  entrypoints, hooks, skills, configurations, pins, and reference integrity.
+- Any byte, digest, behavior, or reference mismatch is rollback failure and
+  blocks forward progress.
+
+## Evidence consulted
+
+- `docs/plans/AGENTS.md`
+- `docs/plans/2026-07-21-bran-okf-migration/plan-spec.md`
+- `docs/plans/2026-07-21-bran-okf-migration/design.md`
+- `docs/plans/2026-07-21-bran-okf-migration/seit.md`
+- `docs/plans/2026-07-21-bran-okf-migration/implementation.md`
+- `crates/bran-core/src/bundle.rs`
+- `crates/bran-core/src/profile.rs`
+- `fixtures/conformance/`
+- `tools/ci/check.sh`
+- `tools/ci/test-budget.json`
+- `tools/ci/test_budget_check.py`
+- `tools/ci/public_boundary_check.py`
+
+## Handoff to Map the Route
+
+### Role and outcome
+
+Act as the bounded Bearing Map-the-Route planning agent. Produce and validate
+the remaining four artifacts in this canonical directory, then stop with an
+owner-reviewable route and no execution.
+
+### Execute now
+
+1. Read this specification and the completed staged-migration artifacts.
+2. Write `design.md` with the minimum decisions needed to satisfy every
+   requirement and preserve the authority boundaries.
+3. Write `seit.md` with exact command/procedure IDs, proof cases, evidence
+   paths, and complete traceability.
+4. Generate the baseline `review.html`.
+5. Write `implementation.md` with bounded write sets, dependency waves,
+   disjoint consumer writers, supported route assignments, owner gates, stop
+   conditions, and rollback.
+6. Regenerate `review.html`, validate all five artifacts, consolidate only
+   canonical artifacts, and remove the duplicate plan directory.
+7. Return the validated artifacts for owner selection. Do not start Explorer or
+   Expedition.
+
+### Verification and evidence
+
+Retain the final traceability result, artifact validation result, review
+generation result, and canonical-directory inventory. Clearly separate planned,
+currently failing, unavailable, and proven states.
+
+### Return or stop conditions
+
+Return only when the five canonical artifacts validate and the duplicate plan
+directory is absent. Stop earlier on any authority expansion, unresolved
+material owner decision, unavailable required evidence that changes the route,
+inability to preserve unrelated owner changes, or a runtime plan-directory
+constraint that would force route artifacts into the rejected duplicate.
+
+## Owner review amendment — 2026-07-23
+
+This append-only amendment records the owner's requested planning-package
+correction. It supersedes earlier handoff instructions only where they imply
+that completed design, SEIT, or implementation work should be repeated.
+
+### Current truth
+
+- The canonical directory
+  `docs/plans/2026-07-22-bran-okf-final-cutover` contains the current
+  `plan-spec.md`, `design.md`, `seit.md`, and `implementation.md`, but does not
+  contain `review.html`.
+- The temporary Bearing runtime directory
+  `docs/plans/2026-07-23-create-or-resume-the-complete-planning-journey-for-bran-s-final-okf-cuto`
+  contains those four Markdown sources plus a generated `review.html`.
+- At inspection, each corresponding Markdown source in the two directories was
+  the same regular-file inode and therefore byte-identical. The observed
+  digests before this amendment were:
+  `plan-spec.md` =
+  `1f84e28b3b9be9b973fb2b2e969ac1722c220e81469bfb392e3f4082a79f37b0`,
+  `design.md` =
+  `db9f3ac640d6ccb6428ec30599edcb3385f664121f1d5a8dd892460d9af031a3`,
+  `seit.md` =
+  `59026ab4da817496dd97cddd5bf529e73803c8c2e414ff858f56e3545a71b0d4`,
+  and `implementation.md` =
+  `a4906dea4afd3c40e5cdc89038c13d81db5f9ee0cf14ddcde78e91e17eb04a7f`.
+- The runtime `review.html` digest observed before this amendment was
+  `87ea2cb4531640015cfcbe9cb6998d9e0ea36aaec23de3ae354f3f37014cb35f`.
+  This plan-spec amendment makes that review stale until Bearing regenerates
+  it from the four current canonical sources.
+- No implementation slice has been executed. No product code, consumer
+  repository, publication target, compatibility surface, or upstream
+  submission was changed by this planning correction.
+
+### Fixed owner decision
+
+The owner has not approved execution. Bearing must deterministically regenerate
+the complete `review.html` from the current canonical `plan-spec.md`,
+`design.md`, `seit.md`, and `implementation.md`, place the resulting regular
+file in the canonical directory, and keep any runtime receipt-mirror copy
+byte-identical. The four canonical Markdown sources must remain unchanged after
+this amendment unless the exact validator reproduces a defect that requires a
+minimal traceability correction.
+
+### Additional requirements
+
+- **REQ-PLAN-008 — Canonical deterministic review.** Bearing's deterministic
+  review generator must render `review.html` from the exact current bytes of
+  the four canonical Markdown sources. The canonical review must embed all four
+  complete sources, expose working relative artifact links, and remain
+  unedited by hand.
+- **REQ-PLAN-009 — Source preservation.** This append-only owner amendment is
+  the only authorized Markdown-source change during the review repair.
+  `design.md`, `seit.md`, and `implementation.md` must retain the digests
+  recorded above. Any further source change requires a reproduced validator
+  defect, the narrowest traceability correction, an explicit retained diff,
+  and another deterministic review generation.
+- **REQ-PLAN-010 — Canonical package validation.** Validate the five canonical
+  artifacts together after review generation and retain the exact validator
+  output, canonical inventory, source/review digests, embedded-source equality
+  result, relative-link result, and runtime-mirror equality result. A runtime
+  review alone is not canonical completion.
+
+### Additional acceptance criteria
+
+- **AC-011:** Canonical `review.html` exists as a regular file and is
+  byte-for-byte the deterministic render of the current canonical
+  `plan-spec.md`, `design.md`, `seit.md`, and `implementation.md`.
+- **AC-012:** The exact five-artifact validator passes in the canonical
+  directory; `design.md`, `seit.md`, and `implementation.md` retain their
+  recorded digests; any still-required runtime mirror is byte-identical; and no
+  implementation or external action begins.
+
+## Superseding handoff to Map the Route
+
+### Role and outcome
+
+Act as the bounded Bearing review-repair agent. Produce the missing canonical
+deterministic review, validate the five canonical artifacts together, reconcile
+the temporary runtime receipt mirror, and stop without execution.
+
+### Current truth
+
+Design, SEIT, and implementation drafting are complete and must not be
+repeated. The four Markdown sources are available at both paths as shared
+regular files. Canonical `review.html` is missing, and the runtime review is
+stale because this amendment changed `plan-spec.md`.
+
+### Scope and authority
+
+- Use the selected planning/review route `codex gpt-5.6-sol` with `high`
+  reasoning.
+- Bearing may generate `review.html` and place byte-identical regular-file
+  instances at the canonical and temporarily required runtime paths.
+- Do not hand-edit `review.html`.
+- Do not change `design.md`, `seit.md`, or `implementation.md` unless the exact
+  validator first reproduces a defect. If it does, stop and report the defect
+  before expanding beyond the narrowest traceability repair.
+- Do not execute Explorer, Expedition, any implementation slice, publication,
+  push, deploy, merge, consumer mutation, proposal submission, or compatibility
+  retirement.
+
+### Execute now
+
+1. Capture the current four canonical source digests and confirm the
+   corresponding runtime sources are byte-identical regular files.
+2. Run Bearing's deterministic review generator from those current source
+   bytes.
+3. Materialize the generated `review.html` as a regular file in the canonical
+   directory and keep the runtime receipt-mirror review byte-identical while
+   Bearing still requires that path.
+4. Run the exact five-artifact validator against the canonical directory and
+   retain its complete output.
+5. Verify embedded-source equality, working relative links, source-preservation
+   digests, review equality, and a planning-only scoped status.
+6. Remove the temporary runtime directory only when Bearing no longer requires
+   it and preservation can be proven; otherwise return it as the sole remaining
+   cleanup blocker rather than deleting required state.
+
+### Verification and evidence
+
+Return the canonical five-artifact inventory, exact validator output, all five
+digests, source-preservation comparison, canonical/runtime review equality,
+relative-link result, and scoped repository status. Label the generated review
+and validation as planning evidence, not implementation evidence.
+
+### Return or stop conditions
+
+Return for owner route selection only after AC-011 and AC-012 pass. Stop on a
+deterministic-render mismatch, missing or stale embedded source, broken
+artifact link, non-identical required mirror, unexpected Markdown-source
+change, validator failure requiring non-traceability work, authority expansion,
+or any attempt to begin execution. A recommendation or passing review is not
+owner approval.
+
design.md
---
+type: design
+name: bran-okf-final-cutover
+status: complete
+date: 2026-07-23
+applies_to: bran
+plan_spec: ./plan-spec.md
+lenses_applied: [CDD, SecDD, RDD, ODD]
+lenses_skipped: [BizDD, DDD, EDD, GDD, PDD]
+oopdsa: mandatory
+planning_route: codex gpt-5.6-sol
+planning_reasoning: high
+---
+
+## Synthesis
+
+The final cutover is a gated evidence pipeline, not a flag flip. BRAN first
+closes its portable conformance and repository gate gaps, then produces an exact
+sealed release, then migrates six consumers independently, and only then becomes
+eligible for separately approved global compatibility retirement.
+
+Four rules govern the route:
+
+1. `okf-v0.1` is the portable result and `bran-strict` is an additive result.
+   They are computed and reported independently.
+2. Release identity is the tuple of source commit, tag, lockfile digest,
+   platform artifact digests, signer fingerprint, and immutable manifest.
+3. A consumer is complete only after exact installation, validation and
+   retrieval parity, reference audit, and byte/configuration rollback proof.
+4. Missing or unavailable evidence is a typed blocked state. It is never
+   normalized into success.
+
+The route reuses the staged-migration ownership model: `bran-core` owns policy,
+profiles, deterministic scanning, retrieval, and semantic outcomes; `bran-cli`
+owns command envelopes; checked-in release tools own build/seal verification;
+consumer-local adapters and hooks translate or invoke but do not redefine BRAN
+semantics.
+
+## Approved lens record
+
+The owner approved CDD, SecDD, RDD, and ODD with mandatory OOPDSA hardening.
+
+- **CDD** governs profile, receipt, manifest, policy, adapter, and command
+  contracts.
+- **SecDD** governs root containment, public/private policy, signatures,
+  checksums, symlinks, credentials, publication authority, and rollback.
+- **RDD** governs unavailable evidence, interrupted installation, partial
+  consumer progress, idempotency, recovery, and retirement barriers.
+- **ODD** governs deterministic receipts, exact command evidence, claim state,
+  first-failure diagnostics, and retained provenance.
+- **OOPDSA** fixes ownership, state transitions, deterministic collections,
+  rule precedence, and wave scheduling without adding a framework.
+
+BizDD, DDD, EDD, GDD, and PDD are skipped because this route adds no business
+model, new domain language, event platform, game mechanics, or performance
+target. Consumer and policy boundaries are already explicit in the approved
+specification.
+
+## Current evidence and claim state
+
+Evidence was verified from `/home/spectre/alphazede/bran` on 2026-07-23:
+
+- `python3 tools/ci/test_budget_check.py tools/ci/test-budget.json` (`CMD-BUDGET`)
+  currently fails (exits 1) because the existing checker requires per-unit-test
+  registration against the obsolete fixed ceiling, contradicting the unbuilt target inventory.
+- `./tools/ci/check.sh --fast` (`CMD-FAST`) stops at `CMD-BUDGET` first due to this
+  test budget check failure.
+- `python3 tools/ci/public_boundary_check.py` (`CMD-PUBLIC`) failed when run directly
+  because it resolved `bran/fixtures/...` beneath the BRAN checkout, producing
+  `/home/spectre/alphazede/bran/bran/fixtures/...`.
+- `DocKind` already distinguishes `index.md` and `log.md`, while the portable
+  profile explicitly applies its current frontmatter/type requirement only to
+  concept documents.
+- Release build, release contract, release seal, schema, and exact-tag fixtures
+  already exist under `tools/ci/`, `schemas/`, and `fixtures/release/`.
+
+Therefore:
+
+- `CMD-BUDGET` and `CMD-FAST` are **currently failing** (test-budget no-ceiling inventory remains **planned and unproven**);
+- `CMD-PUBLIC` is **currently failing**;
+- reserved-document conformance, publication, consumer parity, and retirement
+  remain **planned and unproven**; and
+- retrieval parity and HGTS remain **unavailable**.
+
+## Design decisions
+
+### Shared gates and profile semantics
+
+- **DES-001 — Independent profile outcomes.** `ProfileValidator` returns a
+  separate ordered diagnostic set for `okf-v0.1` and `bran-strict`. Selecting
+  one profile controls the command exit; it does not erase or reclassify the
+  other result.
+- **DES-002 — Normative reserved-document rules.** Portable `index.md` and
+  `log.md` validation is implemented as an OKF-specific reserved-document
+  validator invoked only by the `okf-v0.1` path. Its rules and fixtures must
+  cite the frozen upstream v0.1 source used by the implementation. If the
+  normative source is unavailable or ambiguous, implementation stops rather
+  than guessing a portable rule.
+- **DES-003 — Deterministic reserved diagnostics.** Reserved-document
+  diagnostics use stable codes, repository-relative paths, and ordering by
+  path, code, then message. Strict-only readiness fields remain outside the
+  portable validator.
+- **DES-004 — Budget inventory as fast regression gate.** `tools/ci/test-budget.json`
+  defines a deterministic inventory of named CI journeys, direct CI commands, and
+  owned fixtures rather than one registry row per Rust unit test, eliminating fixed
+  plan, phase, and slice test-count ceilings. `CMD-BUDGET` runs as the first check
+  in `CMD-FAST`, enforcing deterministic negative evidence (failing on missing or
+  duplicate journeys, direct commands, or fixture ownership). All Rust unit tests
+  remain mandatory and fully executed through `CMD-FAST` workspace test commands;
+  removing per-test registry accounting does not skip or weaken Rust unit test execution.
+- **DES-005 — Physical BRAN root for public checks.** `CMD-PUBLIC` derives the
+  BRAN checkout root from the physical checker path, not the caller's current
+  directory or an assumed `bran/` parent layout. All enumerated paths and
+  fixture constants are BRAN-root-relative. Git enumeration is scoped from
+  that root and rejects absolute, parent-traversal, and symlink escapes.
+
+### Release, publication, installation, and rollback
+
+- **DES-006 — Existing exact-release contract is canonical.** Reuse
+  `build-release.sh`, `release-check.sh`, `release_seal.py`,
+  `release_contract_check.py`, and
+  `schemas/bran-release-manifest.schema.json`. Do not create a parallel
+  manifest or packaging format.
+- **DES-007 — Reproducible package inputs.** Each platform archive is built
+  from a clean exact tagged commit with `Cargo.lock`, `--locked`, a declared
+  target triple, normalized archive metadata, and the existing five-platform
+  asset naming contract.
+- **DES-008 — Sealed provenance chain.** Publication eligibility requires the
+  five archive digests, exact `SHA256SUMS`, verified OpenPGP signature and
+  fingerprint, source commit, lockfile digest, tag-to-commit equality, clean
+  worktree, immutable direct asset URLs, and SLSA-v1-shaped provenance already
+  represented by the release manifest.
+- **DES-009 — Publication is an owner-gated side effect.** Local build and
+  unsigned dry-run evidence may be produced inside an approved implementation
+  slice. Tag creation, signing with owner keys, upload, release publication,
+  promotion, or public install verification stops for approval of the exact
+  tag, commit, digest set, fingerprint, destination, and public-boundary
+  receipt.
+- **DES-010 — Verified two-slot installation.** A consumer stages the selected
+  archive in a new immutable version directory, verifies the manifest,
+  signature, archive digest, member shape, and `bran --version`, then changes
+  one consumer-local pin or stable link. The prior pin and bytes remain
+  untouched until consumer acceptance passes.
+- **DES-011 — Rollback is a tested transition.** Rollback restores the recorded
+  prior pin/configuration, verifies the restored digest and command behavior,
+  reruns the consumer's focused gate, and emits a receipt. Failed verification
+  leaves the consumer blocked and retains both versions for recovery.
+
+### Consumer migration and evidence gaps
+
+- **DES-012 — One immutable consumer identity.** Every consumer slice begins
+  with a canonical checkout path, repository identity, exact revision,
+  cleanliness record, active legacy surface inventory, and selected BRAN
+  artifact digest. A mismatch stops before mutation.
+- **DES-013 — Frozen semantic parity.** Native and legacy validation/retrieval
+  run read-only over the same frozen corpus. A small normalizer removes only
+  representation differences defined in `CONTRACT-007`; raw outputs are always
+  retained. Semantic differences remain failures.
+- **DES-014 — Typed consumer gate state.** Each consumer ends in exactly one of
+  `passed`, `failed`, `unavailable`, or `rolled_back`. Only `passed` contributes
+  to global retirement eligibility.
+- **DES-015 — Granular AlphaZede Sports boundary rules.** Native policy uses
+  repository-relative path rules with an explicit classification. Rules are
+  normalized and sorted by path specificity; the most-specific rule wins.
+  Equal-specificity disagreement, unmatched required paths, invalid paths, or
+  symlink escape is a configuration failure. A default classification must be
+  explicit rather than inferred.
+- **DES-016 — BetBot uses an owner-approved content split first.** The route
+  does not raise BRAN's global text ceiling. The BetBot slice proposes an exact
+  semantic split of the oversized knowledge document, preserves stable
+  locators/relationships through explicit redirects or index links, verifies
+  retrieval and content identity obligations, and can restore exact prior
+  bytes. If a safe split cannot be approved and proven, BetBot remains blocked;
+  bounded streaming is a future design, not an implicit fallback.
+- **DES-017 — Retrieval unavailable is not parity.** Missing runner,
+  unsupported legacy query, absent corpus, timeout, or malformed output yields
+  a typed `unavailable` parity row and blocks that consumer.
+- **DES-018 — HGTS absence is terminal for its slice only.** The HGTS slice may
+  do only identity/discovery checks until the checkout exists. It cannot use a
+  substitute repository, cached claim, or inferred pass.
+- **DES-019 — Disjoint consumer writers.** A consumer slice owns only its
+  checkout and consumer-local evidence. Shared BRAN release and proposal
+  surfaces complete earlier under exclusive ownership. Consumer slices may run
+  concurrently only when their resolved write sets are pairwise disjoint.
+
+### Compatibility, retirement, upstream proposals, and planning
+
+- **DES-020 — Compatibility lease.** Adapters, legacy hooks, `use-okf`,
+  legacy entrypoints, configurations, and prior binaries form a retained
+  compatibility set. A consumer migration may stop invoking a legacy surface
+  only after its gate passes, but may not delete the surface.
+- **DES-021 — Retirement barrier.** Global retirement evaluates six immutable
+  consumer receipts plus a fresh active-reference audit. Any non-passing
+  receipt, unexpected reference, rollback failure, or unavailable repository
+  keeps the barrier closed.
+- **DES-022 — Retirement is a separate destructive transaction.** The final
+  slice has an exact deletion/write manifest, recovery archive, restoration
+  rehearsal, owner approval, apply step, and post-removal integrated gate.
+  Removal is never embedded in a consumer slice.
+- **DES-023 — Two proposal drafts, two later owner gates.** Draft
+  `UPSTREAM-OKF-BUNDLE-SCOPE` as a narrow normative clarification and
+  `UPSTREAM-OKF-LAYERED-PROFILES` as a design issue. Keep them local before
+  release; recommend submission only after portable conformance and stable
+  public release evidence. Each external submission requires approval of exact
+  text and destination.
+- **DES-024 — Canonical plan source.** The authoritative artifacts live only
+  in `docs/plans/2026-07-22-bran-okf-final-cutover`. The stale auto-slugged path
+  may be used only as a temporary Bearing receipt alias if the runtime cannot
+  yet retarget it; it must not hold divergent content and must be removed
+  before planning completion.
+- **DES-025 — Evidence state is explicit.** Every receipt labels observations
+  as `planned`, `passed`, `failed`, `unavailable`, or `rolled_back`, with
+  command ID, revision, inputs, exit, and retained evidence locator. A plan or
+  prior receipt cannot be promoted into current passing evidence.
+
+## Stable contracts
+
+- **CONTRACT-001 — ProfileOutcome.** Fields:
+  `schema_version`, `profile`, `status`, `selected`, `diagnostics[]`,
+  `bundle_identity`, `command_id`. `profile` is exactly `okf-v0.1` or
+  `bran-strict`; status is computed independently.
+- **CONTRACT-002 — ReservedDocumentDiagnostic.** Fields:
+  `path`, `kind`, `code`, `message`, `normative_locator`. `kind` is `index` or
+  `log`; no strict-only field code is allowed in the portable result.
+- **CONTRACT-003 — GateReceipt.** Fields:
+  `command_id`, `repository`, `revision`, `started_at`, `exit_code`, `status`,
+  `input_digests`, `evidence_paths`, `first_failure`. Deterministic evidence
+  excludes credentials and raw private corpus bodies.
+- **CONTRACT-004 — ReleaseIdentity.** Exact tuple:
+  `tag`, `source_commit`, `lockfile_sha256`, five platform archive SHA-256
+  values, `SHA256SUMS` digest, signature digest, signer fingerprint, signed
+  time, manifest digest, and immutable asset URLs.
+- **CONTRACT-005 — InstallSnapshot.** Fields:
+  `consumer`, `consumer_revision`, `release_identity`, `prior_pin`,
+  `prior_digest`, `staged_path`, `selected_pin`, `selected_digest`,
+  `verification_status`.
+- **CONTRACT-006 — RollbackReceipt.** Fields:
+  `consumer`, `trigger`, `from_digest`, `to_digest`, `restored_paths`,
+  `byte_checks`, `commands`, `status`. Success requires all restored digests
+  and focused commands to pass.
+- **CONTRACT-007 — ParityReceipt.** Fields:
+  `consumer`, `corpus_digest`, `native_command`, `legacy_command`,
+  `native_raw`, `legacy_raw`, `normalizer_version`, `semantic_rows`,
+  `validation_status`, `retrieval_status`, `overall_status`. Normalization may
+  map field names, exit categories, and deterministic ordering only; it may not
+  discard selected locator, precedence, diagnostic code, conflict, or
+  unavailable state.
+- **CONTRACT-008 — BoundaryRuleSet.** Fields:
+  `schema_version`, `default`, and ordered entries of
+  `repository_relative_path`, `match_kind`, `classification`. Paths are
+  normalized, root-contained, and conflict-checked before scanning.
+- **CONTRACT-009 — OversizedDocumentPlan.** Fields:
+  `consumer`, `source_path`, `source_digest`, `size`, `split_paths`,
+  `relationship_map`, `semantic_checks`, `rollback_digest`, `owner_approval`.
+  It cannot authorize a global ceiling increase.
+- **CONTRACT-010 — ConsumerGateReceipt.** Fields:
+  `consumer`, `repository`, `revision`, `release_identity`, `install`,
+  `validation_parity`, `retrieval_parity`, `hook_check`, `reference_audit`,
+  `rollback`, `status`, `blockers`.
+- **CONTRACT-011 — RetirementManifest.** Fields:
+  six `ConsumerGateReceipt` identities, active-reference audit digest, exact
+  writes/deletions, recovery archive digest, restoration proof, owner approval
+  reference, apply and post-apply commands.
+- **CONTRACT-012 — UpstreamProposalDraft.** Fields:
+  `proposal_id`, `kind`, `problem`, `normative_text`, `examples`,
+  `non_goals`, `local_evidence`, `recommended_timing`, `submission_status`.
+  `submission_status` remains `not-authorized` in planning.
+- **CONTRACT-013 — RouteTrace.** Each requirement maps to design decision,
+  contract, SEIT case, command/procedure, prospective slice, evidence, stop
+  condition, and rollback or explicit non-applicability.
+
+## Use Cases and Communication Flows
+
+### UC-1 — Repair and prove shared gates
+
+```text
+frozen OKF source -> reserved-rule fixtures -> ProfileValidator
+                  -> okf-v0.1 outcome
+                  -> bran-strict outcome (separate)
+
+BRAN physical script path -> BRAN root -> scoped git enumeration
+                          -> public-boundary scan -> GateReceipt
+
+named journey/command/fixture inventory -> test-budget inventory -> inventory proof
+shared results -> CMD-FAST -> pass or first-failure receipt
+```
+
+The reserved validator refuses uncited rules. The public checker never derives
+its root from an AlphaZede parent layout. The budget check remains first in
+`CMD-FAST`, so registry drift fails before expensive tests.
+
+### UC-2 — Build, seal, approve, and publish
+
+```text
+clean exact commit + exact tag + Cargo.lock
+  -> five deterministic platform archives
+  -> SHA256SUMS -> owner-controlled signature
+  -> release manifest + provenance
+  -> local seal verification
+  -> owner publication approval
+  -> immutable release upload
+  -> exact public download and SHA/version verification
+```
+
+Unsigned dry-run evidence is not a stable release. A manifest mismatch, floating
+URL, dirty tree, wrong tag, missing target, signer mismatch, or public-boundary
+failure stops before publication.
+
+### UC-3 — Install and migrate one consumer
+
+```text
+consumer identity + approved release identity + prior install snapshot
+  -> stage archive -> verify signature/digest/member/version
+  -> switch one local pin
+  -> native and legacy checks on frozen corpus
+  -> semantic parity + hook check + reference audit
+  -> rollback rehearsal
+  -> ConsumerGateReceipt
+```
+
+The consumer slice writes only its own repository. Failure after pin selection
+triggers rollback; failure before selection leaves the prior install untouched.
+
+### UC-4 — Handle blocked consumer evidence
+
+```text
+AlphaZede Sports -> resolve explicit granular rules -> prove allow/deny/conflict
+BetBot -> approve exact content split -> prove locators/retrieval/rollback
+retrieval runner missing -> unavailable parity row
+HGTS missing -> unavailable consumer receipt
+```
+
+Unavailable rows are retained with first-failure evidence. They block only the
+affected consumer and the retirement barrier.
+
+### UC-5 — Evaluate and execute retirement
+
+```text
+six passing immutable consumer receipts
+  + fresh zero-active-reference audit
+  + recovery archive and restoration rehearsal
+  -> owner approval of exact retirement manifest
+  -> apply deletion/write set
+  -> integrated gates
+  -> retirement success or exact restoration
+```
+
+No component of this flow runs during planning. The owner approval is specific
+to the final manifest, not inherited from consumer approvals.
+
+### UC-6 — Draft and later submit upstream proposals
+
+```text
+local conformance evidence -> two local proposal drafts
+stable public release -> submission recommendation
+exact text + destination -> separate owner approval
+approval -> external submission (later authority only)
+```
+
+The bundle-scope clarification precedes the layered-profile design issue in the
+recommended external sequence. Neither proposal changes local conformance
+evidence retroactively.
+
+## Interface Option Check
+
+| Surface | Options considered | Selected interface | Material reason |
+| --- | --- | --- | --- |
+| Reserved-document validation | legacy delegation; separate command; core profile subvalidator | core `okf-v0.1` subvalidator | One semantic owner, same envelope, offline conformance; avoids adapter-owned rules. |
+| Public checker root | caller CWD; Git parent discovery; physical checker path | physical BRAN checker path plus scoped Git enumeration | Works in standalone and nested checkouts and removes the live doubled-`bran` failure. |
+| Release contract | new package format; checksum-only; existing exact signed manifest | existing five-archive signed manifest and seal | Already tested, deterministic, exact-tagged, and provenance-aware. |
+| Installation | overwrite binary; package-manager latest; verified version slot plus pin | verified version slot plus atomic consumer-local pin | Preserves prior bytes and makes rollback exact. |
+| Parity | compare prose; central hard-coded consumer logic; shared semantic receipt with repo-local commands | shared receipt and normalizer, repo-local invocation | Common acceptance without hiding repository-specific commands. |
+| AlphaZede Sports boundary | global label; per-file duplication; ordered path rules | explicit default plus most-specific path rules | Expresses granular subtrees deterministically and fails on ambiguity. |
+| BetBot oversized document | global cap increase; new streaming parser; owner-approved semantic split | semantic split with exact rollback | Smallest bounded route; no global safety regression or speculative parser. |
+| Retirement | delete during each migration; fixed date; global evidence barrier | separate evidence-barrier transaction | Preserves compatibility until every consumer passes and gives one rollback boundary. |
+| Upstream contribution | submit immediately; one combined proposal; two staged drafts | two drafts, later separate submissions | Keeps clarification and design debate distinct and respects publication evidence. |
+
+## CDD
+
+- Contracts are versioned and exact: profiles, gate receipts, release identity,
+  installs, parity, consumer completion, retirement, and proposals.
+- Adapters translate into `CONTRACT-001` and `CONTRACT-007`; they do not own
+  validation or retrieval rules.
+- Unknown fields that affect behavior are diagnosed rather than silently
+  dropped.
+- Schema/semantic-oracle pairs remain synchronized; generated representations
+  do not become authority.
+- Stable IDs survive implementation slicing and review generation.
+
+## SecDD
+
+- Treat repositories, archives, manifests, policy paths, hooks, legacy output,
+  and proposal text as untrusted input.
+- Normalize paths lexically, bind them to a canonical root, reject absolute and
+  parent traversal, and reject symlink escape before reading or writing.
+- Never print credentials, raw auth state, private corpus bodies, hidden truth,
+  or unsanitized provider traces into receipts.
+- Exact digest and signature verification occurs before installation selection.
+- Publication and deletion are separate owner-authorized side effects.
+- Compatibility and prior install bytes remain recovery assets until final
+  proof succeeds.
+
+## RDD
+
+- Every multi-step operation is a state machine with a terminal typed state.
+- Build, seal, install, parity, and retirement commands are retry-safe when
+  inputs are identical; mismatched identities stop rather than overwrite.
+- Consumer progress is monotonic per immutable receipt but global readiness is
+  recomputed from all six receipts and a fresh reference audit.
+- Interrupted installation leaves either the prior selected pin or a blocked
+  staged version; it cannot report success without readback.
+- Rollback uncertainty is failure, never success with a warning.
+
+## ODD
+
+- Each command emits or is wrapped by `CONTRACT-003` with exact revision,
+  input digests, exit, first failure, and evidence locators.
+- Public claims derive from current receipts, not plan text.
+- The review distinguishes planned, passed, failed, unavailable, and
+  rolled-back states.
+- Deterministic ordering and content-free digests allow comparison without
+  leaking private bodies.
+- Missing optional telemetry does not alter semantic status.
+
+## OOPDSA Implementation Design
+
+### Ownership model
+
+- `ProfileValidator` owns `ProfileOutcome`; an `OkfReservedValidator` strategy
+  contributes only portable reserved-document diagnostics.
+- `PublicSurfaceRoot` is a value object constructed from the physical checker
+  path and used by the public checker; callers cannot inject a broader root.
+- Existing release scripts and `ReleaseIdentity` own release proof. No
+  `ReleaseManager` framework is introduced.
+- `ConsumerMigration` coordinates one `InstallSnapshot`, `ParityReceipt`,
+  reference audit, and `RollbackReceipt`.
+- `RetirementBarrier` is a pure evaluator over six consumer receipts and a
+  fresh audit. A separate retirement procedure performs authorized writes.
+
+### State machines
+
+```text
+Release: planned -> built -> sealed -> approved -> published -> verified
+                       \-> failed
+
+Consumer: discovered -> approved -> staged -> selected -> parity_checked
+         -> rollback_proven -> passed
+         \-> unavailable | failed -> rolled_back
+
+Retirement: ineligible -> eligible -> approved -> applied -> verified
+                                       \-> restoring -> restored | failed
+```
+
+Transitions require the exact preceding identity; there is no boolean
+`ready=true` shortcut.
+
+### Patterns used
+
+- **Strategy:** portable reserved validation and strict readiness validation
+  share bundle input while preserving separate rule sets and outcomes.
+- **Adapter:** legacy commands/configuration map into native requests and
+  semantic receipts only.
+- **State machine:** release, consumer, and retirement lifecycles expose
+  partial and recovery states.
+- **Value objects:** revisions, digests, normalized repository paths, consumer
+  IDs, and profile IDs reject malformed values at construction.
+
+No dependency-injection framework, event bus, database, service, or generic
+workflow engine is added.
+
+### Deterministic data structures and algorithms
+
+- Use `BTreeMap`/`BTreeSet` for diagnostics, profile rows, asset names,
+  reference audits, and consumer identities.
+- Sort diagnostics by `(path, code, message)` and parity rows by semantic key.
+- Normalize boundary rules once, reject duplicate/conflicting normalized paths,
+  then sort by descending path-component count and lexical path. The first
+  matching rule wins; equal-specific conflicts are invalid.
+- Compute SHA-256 in bounded chunks. Do not load release archives or oversized
+  inputs solely to hash them.
+- Represent implementation dependencies as a DAG. Use Kahn topological sorting
+  with lexical slice-ID tie-breaking; reject cycles and overlapping write sets
+  before execution.
+- Compare exact write sets with normalized path-prefix intersection, treating
+  a repository root as overlapping all descendants.
+
+Complexity remains bounded by repository paths, rules, assets, and slices:
+sorting is `O(n log n)`, matching is `O(r * p)` for small policy rule sets, and
+hashing is `O(bytes)` with bounded memory.
+
+## Prospective execution waves
+
+Implementation drafting must preserve this dependency shape:
+
+1. **Wave 1 — Shared gate truth:** reserved conformance, public-root repair,
+   budget regression, independent profile reporting.
+2. **Wave 2 — Local proposal drafts and release readiness:** two proposal
+   drafts, release build/seal proof, publication packet.
+3. **Wave 3 — Owner-gated publication and exact public verification:** no
+   consumer mutation before a stable release identity exists.
+4. **Wave 4 — Six disjoint consumer migrations:** parallel only after exact
+   write-set comparison and per-consumer approval.
+5. **Wave 5 — Global evidence audit:** six receipts, fresh references,
+   rollback archive, retirement manifest.
+6. **Wave 6 — Separately approved retirement:** destructive apply and
+   restoration path.
+
+## Design stop conditions
+
+Stop when:
+
+- normative reserved-file rules cannot be cited;
+- the public checker must broaden beyond the BRAN/public export surface;
+- an exact source/tag/artifact/signature identity cannot be proven;
+- a consumer identity, revision, write set, or prior install cannot be read;
+- parity requires discarding semantic differences;
+- a boundary conflict or oversized-document split lacks an explicit safe
+  resolution and rollback;
+- HGTS or retrieval evidence remains unavailable for a claimed passing gate;
+- any writer overlaps another active writer;
+- compatibility removal is proposed before six passing receipts;
+- publication, consumer mutation, proposal submission, or retirement lacks its
+  exact owner approval; or
+- the Bearing runtime would force divergent artifacts into the rejected
+  auto-slugged plan directory.
+
+## Handoff to implementation drafting
+
+### Role and outcome
+
+Act as the bounded Bearing implementation-drafting agent. Reuse this design and
+`seit.md`; create traceable implementation slices only after the design/SEIT
+checkpoint validates.
+
+### Scope and authority
+
+Write only `implementation.md` in the canonical plan directory. Do not execute,
+publish, mutate consumers, submit proposals, remove compatibility, or hand-edit
+`review.html`. Use only owner-supported route labels and reasoning levels.
+
+### Execute now
+
+Map each prospective SEIT row to one bounded slice with an exact write set,
+dependency wave, model route, verification commands, retained evidence, stop
+condition, owner gate, and rollback. Give each consumer exactly one migration
+slice and reject overlapping writers.
+
+### Verification and evidence
+
+Prove complete bidirectional traceability, valid wave order, six consumer
+slices, supported assignments, and a separate final retirement slice. Bearing,
+not the agent, generates the baseline and final `review.html`.
+
+### Return or stop conditions
+
+Return only `implementation.md` and the Bearing-generated review artifacts at
+the supplied checkpoint. Stop before execution and on any authority expansion,
+unsupported model route, missing traceability, overlapping write set, or
+runtime attempt to continue a divergent duplicate plan.
+
+## 2026-07-23 Slice 2.1 wire-contract clarification
+
+This section provides the exact append-only wire-contract clarification for Slice 2.1 to settle JSON wire shapes, evidence locator/digest bindings, reference classifications, and revision-bound freshness semantics without introducing new requirements, contracts, slices, design IDs, paths, commands, external authority, or consumer-specific semantics.
+
+### 1. Common encoding and evidence binding
+
+- **Encoding and key validation:** Every manifest and receipt is UTF-8 JSON. Duplicate keys within any JSON object are strictly rejected. Behavioral objects use exact documented keys; any unrecognized or unknown behavioral key causes verification failure.
+- **Digests and revisions:** Digests are exact lowercase 64-character hexadecimal SHA-256 strings. Revisions are exact lowercase Git object IDs of 40 or 64 hexadecimal characters.
+- **Evidence locators:** Evidence locators are normalized POSIX paths relative to the supplied evidence directory. Locators cannot be absolute, empty, single dot (`.`), parent traversal (`..`), or contain backslashes (`\`), and must resolve to non-symlink regular files physically contained within that evidence directory.
+- **Evidence digest pairing:** Every evidence locator is paired with its SHA-256 digest. The verifier recomputes all evidence digests in bounded chunks during execution. The verifier never emits raw evidence bodies in receipts or diagnostic output.
+- **Inert commands:** Commands embedded in receipts are inert strings or structured command records. Verifier modes treat commands strictly as read-only evidence and never execute them.
+- **Canonical ordering and JSON hashing:** Deterministic canonical ordering is lexical by consumer, path, and semantic key. Duplicate keys, duplicate locators, or duplicate consumers cause immediate verification failure. Wherever canonical compact JSON is hashed, it is defined uniformly as UTF-8 `json.dumps(value, sort_keys=True, separators=(",", ":"), ensure_ascii=False)` bytes, with arrays already in their required lexical order.
+
+### 2. ReleaseIdentity wire shape (CONTRACT-004)
+
+`ReleaseIdentity` is an exact JSON object containing these top-level keys:
+`tag`, `source_commit`, `lockfile_sha256`, `archives`, `checksums_sha256`, `signature_sha256`, `signer_fingerprint`, `signed_at`, `manifest_sha256`, `asset_urls`.
+
+- `archives` is an exact object keyed by the five approved target triples (`x86_64-unknown-linux-gnu`, `aarch64-unknown-linux-gnu`, `x86_64-apple-darwin`, `aarch64-apple-darwin`, `x86_64-pc-windows-msvc`), with each value being its lowercase 64-hex SHA-256 digest.
+- `asset_urls` is an exact lexically sorted array of immutable direct URL strings for the five target archives plus `SHA256SUMS`, `SHA256SUMS.sig`, and `bran-release-manifest.json` (8 URLs total). URLs using `latest`, query parameters, URL fragments, duplicate entries, or tag mismatches are strictly rejected.
+- Equality of `ReleaseIdentity` requires exact byte/field equality across this entire normalized object; tag-only identity matches are rejected.
+
+### 3. ConsumerGateReceipt wire shape (CONTRACT-010)
+
+`ConsumerGateReceipt` is an exact JSON object with the top-level keys:
+`consumer`, `repository`, `revision`, `release_identity`, `install`, `validation_parity`, `retrieval_parity`, `hook_check`, `reference_audit`, `rollback`, `status`, `blockers`.
+
+- `consumer` is any nonempty stable identifier string. `repository` is the canonical repository identity string. `revision` must equal the CLI revision argument and current clean checkout HEAD.
+- `status` is one of the four-state vocabulary: `passed`, `failed`, `unavailable`, `rolled_back`. Only `passed` permits a successful exit code (0).
+- `blockers` is a lexically sorted array of unique string blocker codes. `blockers` must be empty if and only if `status` is `passed`.
+
+### 4. Nested object wire shapes
+
+- **InstallSnapshot (CONTRACT-005):** Exact top-level keys: `consumer`, `consumer_revision`, `release_identity`, `prior_pin`, `prior_digest`, `staged_path`, `selected_pin`, `selected_digest`, `verification_status`. `staged_path` and `prior_pin` are evidence locators relative to the supplied evidence directory; their bytes must hash to `selected_digest` and `prior_digest` respectively. `selected_pin` is a nonempty inert string identifying the selected pin. `verification_status` is `passed` only when `staged_path` bytes hash to `selected_digest`, `prior_pin` bytes hash to `prior_digest`, the exact `ReleaseIdentity` matches, and prior pin/digest values are retained. This tool verifies a captured snapshot and does not switch the pin.
+- **ParityReceipt (CONTRACT-007):** Exact top-level keys: `consumer`, `corpus_digest`, `native_command`, `legacy_command`, `native_raw`, `legacy_raw`, `normalizer_version`, `semantic_rows`, `validation_status`, `retrieval_status`, `overall_status`. `native_raw` and `legacy_raw` are evidence locator/digest objects. Raw evidence files must be UTF-8 JSON arrays whose normalized entries correspond one-to-one with semantic rows, allowing only the documented field-name, exit-category, and ordering transformations. `semantic_rows` is a lexically sorted list of objects containing `semantic_key`, `native`, and `legacy`. Every `semantic_rows[].native` and `.legacy` is an exact object with always-present keys `locator`, `precedence`, `diagnostic_code`, `conflict`, `unavailable`, plus `outcome` (nullable values are allowed, but the keys cannot be dropped). `normalizer_version` is a nonempty pinned version string. States (`validation_status`, `retrieval_status`, `overall_status`) use the four-state vocabulary (`passed`, `failed`, `unavailable`, `rolled_back`); any non-passing status blocks. The two `ConsumerGateReceipt` parity fields (`validation_parity`, `retrieval_parity`) are independently validated receipts over the same `consumer` and `corpus_digest`, nested under the authoritative `ConsumerGateReceipt` `ReleaseIdentity`; neither raw output may be absent.
+- **Hook check:** Exact JSON object with keys `commands`, `evidence`, `status`. `commands` is an array of inert nonempty string commands, `evidence` is an array of locator/digest objects, and `status` must be `passed`.
+- **Reference audit:** Exact JSON object with keys `consumer`, `revision`, `expected_compatibility`, `matches`, `inventory_digest`, `evidence`, `status`. `expected_compatibility` is a sorted unique list of exact objects with `path` and `kind`; paths are normalized consumer-relative POSIX paths and `kind` uses the existing kind vocabulary (`code`, `skill`, `hook`, `ci`, `configuration`, `historical-documentation`). `matches` is a sorted list of objects containing `path`, `line`, `kind`, `classification`, `match_sha256`. `match_sha256` is the SHA-256 of the exact matched source line bytes read from the clean consumer checkout at `path` and `line`, recomputed by the verifier. `kind` must be one of `code`, `skill`, `hook`, `ci`, `configuration`, `historical-documentation`. `classification` must be one of `native-active`, `compatibility-active`, `historical`, `unexpected-active`, `unclassified`. Passing status permits only `native-active`, `compatibility-active`, and `historical`, requires a matching `compatibility-active` match for every expected object in `expected_compatibility` and no `compatibility-active` match absent from that list, and rejects any `unexpected-active` or `unclassified` entries. This is manifest-driven and has no built-in per-consumer list. `inventory_digest` is SHA-256 of compact UTF-8 JSON encoding (`json.dumps(matches, sort_keys=True, separators=(",", ":"), ensure_ascii=False)` bytes) of the sorted `matches` array.
+- **RollbackReceipt (CONTRACT-006):** Exact top-level keys: `consumer`, `trigger`, `from_digest`, `to_digest`, `restored_paths`, `byte_checks`, `commands`, `status`. Every `restored_paths` item is an exact object with keys `path`, `sha256`, `source`; `source` must be `evidence` or `consumer`. Evidence paths resolve beneath the evidence root; consumer paths resolve beneath the clean consumer checkout; both reject symlinks and path traversal escapes, and their bytes are hashed to `sha256`. `byte_checks` is a sorted list of records with keys `path`, `expected`, `actual`, `status`. `commands` is a sorted list of records with keys `command`, `exit_code`, `status`, `evidence`. Passing requires exact `from_digest` and `to_digest` matching, all byte checks and commands passing with status `passed`, and no missing items.
+
+### 5. RetirementManifest wire shape (CONTRACT-011)
+
+`RetirementManifest` is an exact JSON object with keys:
+`consumers`, `active_reference_audit`, `writes`, `deletions`, `recovery_archive`, `restoration_proof`, `owner_approval_reference`, `apply_commands`, `post_apply_commands`.
+
+- `consumers` is an exact array of six sorted consumer summary objects containing `consumer`, `repository`, `revision`, `release_identity`, `receipt`, `receipt_sha256`, `status` for `Alphazedehq`, `alphazede-sports`, `betbot`, `developers`, `hgts`, and `alphazede-markets`. Each referenced `receipt` is bound to a regular evidence file and independently validates as a passing `ConsumerGateReceipt` with matching revision and release identity.
+- `active_reference_audit`, `recovery_archive`, and `restoration_proof` are evidence locator/digest objects.
+- The file referenced by `active_reference_audit` is strict JSON with exact keys `consumers`, `status`. Its `consumers` array contains the exact six sorted objects with `consumer`, `repository`, `revision`, `release_identity`, `inventory_digest`, `status`, each matching the corresponding independently validated `ConsumerGateReceipt`; top-level and per-consumer status must be `passed`.
+- The file referenced by `restoration_proof` is strict JSON with exact keys `byte_checks`, `commands`, `status`, using the same byte-check and command-record shapes as `RollbackReceipt`, and every item and status must pass.
+- `recovery_archive` references the actual non-symlink regular archive file beneath the evidence directory and its digest is recomputed.
+- `writes` and `deletions` are exact sorted unique lists of normalized repository-relative paths, validated as data structures only.
+- `owner_approval_reference` is a nonempty inert string reference proving the manifest carries an approval tracking string; its presence does not imply verifier grant or confirmation of owner approval.
+- `apply_commands` and `post_apply_commands` are arrays of nonempty inert strings and are never executed by `verify`.
+- Retirement eligibility requires exact identity equality among these six current consumer receipts and the global audit (`active_reference_audit`), matching revision and release identity, live digest recomputation for all referenced evidence files, and passing status across all receipts and audits (no wall-clock threshold). Eligibility does not authorize execution of retirement commands.
+
+### 6. Freshness and read-only verifier semantics
+
+- **Identity-bound freshness:** Freshness is identity-bound rather than wall-clock-based. An audit or receipt is fresh if and only if its recorded revision equals the CLI revision argument and current clean checkout HEAD, its `ReleaseIdentity` equals the selected release identity, and every evidence file digest is recomputed from the supplied evidence directory during the current verifier invocation. Freshness for retirement is proven by exact identity equality among the six current receipts and the global audit plus live digest recomputation, with no wall-clock threshold.
+- **Unavailable telemetry:** Missing or incomplete optional telemetry produces an `unavailable` state and is never normalized into a semantic pass.
+- **Read-only enforcement:** Verifier modes (`install-verify`, `parity`, `reference-audit`, `rollback`, and retirement `verify`) are strictly read-only. They never generate receipts, alter pins, restore files, execute commands, sign artifacts, publish assets, upload packages, or mutate any repository or evidence directory.
+
seit.md
---
+type: seit
+name: bran-okf-final-cutover
+status: complete
+date: 2026-07-23
+applies_to: bran
+plan_spec: ./plan-spec.md
+design: ./design.md
+planning_route: codex gpt-5.6-sol
+planning_reasoning: high
+---
+
+## Purpose
+
+This SEIT plan defines prospective proof for the BRAN final OKF cutover. It does
+not claim that planned commands, consumer repositories, a stable release, or
+retirement evidence exist. Current observations are labeled separately from
+future acceptance.
+
+## Evidence state
+
+### Verified current
+
+- `CMD-BUDGET` fails (exits 1) because the existing checker requires per-unit-test
+  registration against the obsolete fixed ceiling.
+- `CMD-FAST` stops at `CMD-BUDGET` first due to the test budget failure.
+- `CMD-PUBLIC` fails on the doubled path
+  `/home/spectre/alphazede/bran/bran/fixtures/...`.
+- BRAN distinguishes `index.md` and `log.md`, but current portable profile code
+  does not validate their upstream structures.
+
+### Planned
+
+- Test-budget no-ceiling inventory update and budget gate repair (`CMD-BUDGET`).
+- Reserved-document portable conformance.
+- Portable root behavior for `CMD-PUBLIC`.
+- Release build/seal/publication/install verification.
+- Six consumer migrations and parity receipts.
+- Compatibility retirement and both upstream proposal drafts.
+
+### Unavailable
+
+- Retrieval parity evidence.
+- HGTS checkout and current revision.
+- Owner-approved stable public release identity.
+- Owner approval for consumer writes, external proposal submission, or
+  retirement.
+
+## Test strategy
+
+### Pre-lens stance
+
+Use offline deterministic unit, contract, fixture, and procedure tests. Freeze
+all repository/corpus identities before comparison. Retain raw evidence before
+normalization. Use exact digests rather than timestamps as identity.
+
+### Lens additions
+
+- **CDD:** schema, version, profile, command, adapter, manifest, parity, and
+  receipt contract cases.
+- **SecDD:** path traversal, symlink, boundary conflict, signature, checksum,
+  wrong revision, private-data, and unauthorized-side-effect cases.
+- **RDD:** missing repository/runner, timeout, partial build/install, retry,
+  rollback, and restoration-failure cases.
+- **ODD:** exact command/revision/input evidence, first failure, unavailable
+  state, deterministic ordering, and claim-state cases.
+- **OOPDSA:** state transition, value-object validation, boundary precedence,
+  DAG cycle, and write-set overlap cases.
+
+### Evidence retention
+
+Each required row retains:
+
+- command/procedure ID and exact invocation;
+- repository identity and exact revision;
+- relevant config/corpus/artifact digests;
+- stdout/stderr or structured raw output;
+- exit code and first failure;
+- normalized semantic receipt when applicable;
+- before/after mutation inventory for write-capable procedures; and
+- rollback receipt or explicit non-applicability.
+
+Private corpus bodies, credentials, raw authentication state, hidden grader
+truth, and unsanitized provider traces are forbidden evidence.
+
+## Command context
+
+Commands run from the BRAN repository root unless a procedure explicitly
+changes into an owner-approved consumer checkout.
+
+Execution binds these variables to exact values before a release or consumer
+procedure:
+
+```sh
+BRAN_TAG=bran-vX.Y.Z
+BRAN_SOURCE_SHA=<lowercase-40-hex>
+BRAN_DIST=<absolute-empty-dist-directory>
+BRAN_FINGERPRINT=<approved-lowercase-40-or-64-hex>
+BRAN_MANIFEST=<absolute-path-to-bran-release-manifest.json>
+BRAN_ASSET=<absolute-path-to-platform-archive>
+CONSUMER_ROOT=<absolute-owner-approved-checkout>
+CONSUMER_REVISION=<exact-consumer-commit>
+CONSUMER_MANIFEST=<absolute-path-to-consumer-cutover-manifest>
+EVIDENCE_DIR=<absolute-empty-consumer-evidence-directory>
+```
+
+Placeholders are planning bindings, not permission to choose a tag, key,
+checkout, or destination. The implementation slice must record their resolved
+values before any side effect.
+
+## Required Commands
+
+### Existing BRAN commands
+
+- **CMD-OKF-PORTABLE** —
+  `cargo test --manifest-path Cargo.toml -p bran-core p1_conformance`
+- **CMD-PROFILES** —
+  `cargo test --manifest-path Cargo.toml -p bran-core profile::tests::p1_profiles`
+- **CMD-BUDGET** —
+  `python3 tools/ci/test_budget_check.py tools/ci/test-budget.json`
+- **CMD-FAST** — `./tools/ci/check.sh --fast`
+- **CMD-PUBLIC** — `python3 tools/ci/public_boundary_check.py`
+- **CMD-RELEASE-CONTRACT** —
+  `python3 tools/ci/release_contract_check.py`
+- **CMD-RELEASE-PLAN** —
+  `./tools/ci/build-release.sh --plan --tag "$BRAN_TAG" --dist "$BRAN_DIST"`
+- **CMD-RELEASE-BUILD-LINUX-X86** —
+  `./tools/ci/build-release.sh --target x86_64-unknown-linux-gnu --tag "$BRAN_TAG" --dist "$BRAN_DIST"`
+- **CMD-RELEASE-BUILD-LINUX-ARM** —
+  `./tools/ci/build-release.sh --target aarch64-unknown-linux-gnu --tag "$BRAN_TAG" --dist "$BRAN_DIST"`
+- **CMD-RELEASE-BUILD-MAC-X86** —
+  `./tools/ci/build-release.sh --target x86_64-apple-darwin --tag "$BRAN_TAG" --dist "$BRAN_DIST"`
+- **CMD-RELEASE-BUILD-MAC-ARM** —
+  `./tools/ci/build-release.sh --target aarch64-apple-darwin --tag "$BRAN_TAG" --dist "$BRAN_DIST"`
+- **CMD-RELEASE-BUILD-WINDOWS-X86** —
+  `./tools/ci/build-release.sh --target x86_64-pc-windows-msvc --tag "$BRAN_TAG" --dist "$BRAN_DIST"`
+- **CMD-RELEASE-DRY-SEAL** —
+  `./tools/ci/release-check.sh --tag "$BRAN_TAG" --dist "$BRAN_DIST" --dry-run-unsigned`
+- **CMD-RELEASE-SEAL** —
+  `./tools/ci/release-check.sh --tag "$BRAN_TAG" --dist "$BRAN_DIST" --fingerprint "$BRAN_FINGERPRINT"`
+
+### Planned bounded verification commands
+
+These interfaces are prospective. Their owning implementation slices must
+create them before any dependent consumer slice:
+
+- **CMD-EXACT-SHA** —
+  `python3 tools/cutover/verify_release.py --manifest "$BRAN_MANIFEST" --asset "$BRAN_ASSET" --source-sha "$BRAN_SOURCE_SHA" --fingerprint "$BRAN_FINGERPRINT"`
+- **CMD-INSTALL-VERIFY** —
+  `python3 tools/cutover/consumer_gate.py install-verify --consumer "$CONSUMER_ROOT" --revision "$CONSUMER_REVISION" --manifest "$CONSUMER_MANIFEST" --evidence "$EVIDENCE_DIR"`
+- **CMD-CONSUMER-PARITY** —
+  `python3 tools/cutover/consumer_gate.py parity --consumer "$CONSUMER_ROOT" --revision "$CONSUMER_REVISION" --manifest "$CONSUMER_MANIFEST" --evidence "$EVIDENCE_DIR"`
+- **CMD-REFERENCE-AUDIT** —
+  `python3 tools/cutover/consumer_gate.py reference-audit --consumer "$CONSUMER_ROOT" --revision "$CONSUMER_REVISION" --manifest "$CONSUMER_MANIFEST" --evidence "$EVIDENCE_DIR"`
+- **CMD-ROLLBACK** —
+  `python3 tools/cutover/consumer_gate.py rollback --consumer "$CONSUMER_ROOT" --revision "$CONSUMER_REVISION" --manifest "$CONSUMER_MANIFEST" --evidence "$EVIDENCE_DIR"`
+- **CMD-RETIREMENT-PROOF** —
+  `python3 tools/cutover/retirement_gate.py verify --manifest "$RETIREMENT_MANIFEST" --evidence "$EVIDENCE_DIR"`
+- **CMD-ROUTE-TRACE** —
+  `python3 tools/cutover/validate_route.py docs/plans/2026-07-22-bran-okf-final-cutover`
+
+The planned tools are standard-library-only, offline, and read-only unless
+invoked in the explicitly owner-approved install, rollback, or retirement
+mode. Read-only modes reject a changed consumer tree.
+
+### Stable consumer procedure IDs
+
+Each procedure binds the shared commands to one exact consumer manifest and
+checkout. It includes discovery, owner gate, install verification, validation
+and retrieval parity, hook/skill check, active-reference audit, rollback proof,
+and final `ConsumerGateReceipt`.
+
+- **PROC-PARITY-ALPHAZEDEHQ**
+- **PROC-PARITY-ALPHAZEDE-SPORTS**
+- **PROC-PARITY-BETBOT**
+- **PROC-PARITY-DEVELOPERS**
+- **PROC-PARITY-HGTS**
+- **PROC-PARITY-ALPHAZEDE-MARKETS**
+
+Additional procedures:
+
+- **PROC-PUBLICATION** — resolve release variables, run release build/seal
+  commands, stop for approval, publish later, then verify exact public assets.
+- **PROC-PROPOSAL-DRAFTS** — write both local drafts and prove their claim
+  boundaries; no external write.
+- **PROC-RETIREMENT** — evaluate the barrier, prove restoration, stop for
+  approval, apply exact manifest later, and revalidate or restore.
+- **PROC-PLAN-CANONICALIZE** — verify the five artifacts in the canonical
+  directory, ensure review embeds exact sources, and remove the stale
+  auto-slugged alias only after Bearing no longer depends on it.
+
+## Traceability Matrix
+
+| SEIT row ID | Acceptance/Risk ID | Design/Contract ID | Boundary/Test Layer | Positive Case | Negative/Failure Case | Command/Procedure ID | Evidence |
+| --- | --- | --- | --- | --- | --- | --- | --- |
+| SEIT-001 | AC-002 | DES-001, DES-002, DES-003, CONTRACT-001, CONTRACT-002 | portable index conformance | frozen upstream-valid index passes `okf-v0.1` | each cited structural violation yields a stable portable code | CMD-OKF-PORTABLE, CMD-PROFILES | normative locator, fixtures, both profile outcomes |
+| SEIT-002 | AC-002 | DES-001, DES-002, DES-003, CONTRACT-001, CONTRACT-002 | portable log conformance | frozen upstream-valid log passes `okf-v0.1` | each cited structural violation yields a stable portable code | CMD-OKF-PORTABLE, CMD-PROFILES | normative locator, fixtures, ordered diagnostics |
+| SEIT-003 | AC-002, AC-008 | DES-001, DES-003, CONTRACT-001 | profile contract | portable pass/strict fail and portable fail/strict result remain separate | strict-only code changes portable status or selected exit | CMD-PROFILES | four outcome combinations and CLI envelope |
+| SEIT-004 | AC-002 | DES-004, CONTRACT-003 | test-budget gate | named CI journeys, direct CI commands, and owned fixtures are deterministically inventoried; all Rust unit tests run in CMD-FAST | missing/duplicate journey, direct command, or fixture ownership fails CMD-BUDGET before expensive steps | CMD-BUDGET, CMD-FAST | budget inventory diff and first-gate output |
+| SEIT-005 | AC-002 | DES-005, CONTRACT-003 | public-root security | root and relocated checkout find the exact public surface | doubled prefix, caller CWD, traversal, symlink, or broad scope passes | CMD-PUBLIC, CMD-FAST | resolved root, enumerated relative paths, exits |
+| SEIT-006 | AC-002 | DES-001, DES-002, DES-003, DES-004, DES-005, CONTRACT-003 | offline shared gates | shared commands pass without provider or owner-local configuration | a shared command attempts network/provider lookup | CMD-OKF-PORTABLE, CMD-BUDGET, CMD-PUBLIC, CMD-FAST | sanitized environment and receipts |
+| SEIT-007 | AC-003 | DES-006, DES-007, DES-008, CONTRACT-004 | deterministic release build | two same-input builds produce byte-identical target archives | dirty tree, missing lock/target, unknown target, or altered metadata passes | CMD-RELEASE-PLAN, CMD-RELEASE-BUILD-LINUX-X86, CMD-RELEASE-BUILD-LINUX-ARM, CMD-RELEASE-BUILD-MAC-X86, CMD-RELEASE-BUILD-MAC-ARM, CMD-RELEASE-BUILD-WINDOWS-X86 | source, tag, lock, and archive digests |
+| SEIT-008 | AC-003 | DES-006, DES-007, DES-008, DES-009, CONTRACT-004 | release seal and provenance | tag, commit, lock, checksums, signature, manifest, and provenance agree | wrong tag/SHA/fingerprint, floating URL, tampered or extra asset, or symlink passes | CMD-RELEASE-CONTRACT, CMD-RELEASE-DRY-SEAL, CMD-RELEASE-SEAL, CMD-EXACT-SHA | ReleaseIdentity and seal output |
+| SEIT-009 | AC-003 | DES-009, CONTRACT-004 | publication authority | approved exact packet is the only publishable identity | dry-run, recommendation, or stale approval authorizes publication | PROC-PUBLICATION | exact owner decision and immutable public readback |
+| SEIT-010 | AC-003, AC-004 | DES-010, CONTRACT-005 | consumer installation | staged asset verifies before one pin changes | overwrite, digest/member/version mismatch, or latest URL selects | CMD-EXACT-SHA, CMD-INSTALL-VERIFY | InstallSnapshot and pin readback |
+| SEIT-011 | AC-003, AC-004 | DES-011, CONTRACT-006 | consumer rollback | prior pin and bytes restore and focused commands pass | partial restore or failed verification reports success | CMD-ROLLBACK | RollbackReceipt and byte inventory |
+| SEIT-012 | AC-004 | DES-013, DES-014, CONTRACT-007 | semantic parity | identical frozen input produces equivalent validation/retrieval semantics | normalizer hides locator, precedence, conflict, diagnostic, or unavailable state | CMD-CONSUMER-PARITY | raw pair, normalizer version, semantic diff |
+| SEIT-013 | AC-004, AC-006 | DES-012, DES-013, DES-014, DES-019, DES-020, CONTRACT-010 | AlphazedeHQ consumer gate | install, parity, hook/skill, audit, and rollback pass | unexpected legacy reference or fail-open hook drift is ignored | PROC-PARITY-ALPHAZEDEHQ | ConsumerGateReceipt |
+| SEIT-014 | AC-004, AC-005 | DES-012, DES-013, DES-014, DES-015, DES-019, DES-020, CONTRACT-008, CONTRACT-010 | AlphaZede Sports gate | granular allow/deny/inheritance rules and complete gate pass | ambiguous, escaping, unmatched, or weakened boundary policy passes | PROC-PARITY-ALPHAZEDE-SPORTS | rule set, boundary matrix, ConsumerGateReceipt |
+| SEIT-015 | AC-004, AC-005 | DES-012, DES-013, DES-014, DES-016, DES-019, DES-020, CONTRACT-009, CONTRACT-010 | BetBot gate | approved split preserves locators, parity, bounded size, and rollback | global cap rises, content is lost, or rollback differs | PROC-PARITY-BETBOT | OversizedDocumentPlan, retrieval diff, byte rollback |
+| SEIT-016 | AC-004 | DES-012, DES-013, DES-014, DES-019, DES-020, CONTRACT-010 | developers consumer gate | public source, install, parity, audit, and rollback agree | exported source differs or floating release is used | PROC-PARITY-DEVELOPERS | ConsumerGateReceipt and export/source identity |
+| SEIT-017 | AC-004, AC-005 | DES-012, DES-014, DES-017, DES-018, DES-019, DES-020, CONTRACT-010 | HGTS consumer gate | verified checkout identity then complete gate passes | absent or wrong checkout is substituted or inferred passing | PROC-PARITY-HGTS | discovery or typed unavailable receipt |
+| SEIT-018 | AC-004 | DES-012, DES-013, DES-014, DES-019, DES-020, CONTRACT-010 | alphazede-markets gate | install, parity, audit, and rollback pass | repository identity or receipt mismatch is ignored | PROC-PARITY-ALPHAZEDE-MARKETS | ConsumerGateReceipt |
+| SEIT-019 | AC-004, AC-005 | DES-014, DES-017, DES-018, CONTRACT-007, CONTRACT-010 | unavailable parity | missing runner/corpus/capability yields typed unavailable | unavailable is normalized to success or silently skipped | PROC-PARITY-ALPHAZEDEHQ, PROC-PARITY-ALPHAZEDE-SPORTS, PROC-PARITY-BETBOT, PROC-PARITY-DEVELOPERS, PROC-PARITY-HGTS, PROC-PARITY-ALPHAZEDE-MARKETS | raw error, typed row, blocked gate |
+| SEIT-020 | AC-001, AC-004 | DES-019, DES-025, CONTRACT-013 | route DAG and write sets | consumer write sets are disjoint and shared work precedes them | overlap or dependency cycle is accepted | CMD-ROUTE-TRACE | normalized write sets and DAG report |
+| SEIT-021 | AC-006 | DES-020, DES-021, CONTRACT-010 | compatibility retention | legacy surfaces and prior binaries stay recoverable | a consumer slice deletes or disables compatibility | CMD-REFERENCE-AUDIT, PROC-PARITY-ALPHAZEDEHQ, PROC-PARITY-ALPHAZEDE-SPORTS, PROC-PARITY-BETBOT, PROC-PARITY-DEVELOPERS, PROC-PARITY-HGTS, PROC-PARITY-ALPHAZEDE-MARKETS | before/after path and reference inventory |
+| SEIT-022 | AC-004, AC-006 | DES-012, DES-020, CONTRACT-010 | active reference audit | active compatibility and historical references classify deterministically | unexpected active reference is ignored or history triggers deletion | CMD-REFERENCE-AUDIT | raw matches, classification, digest |
+| SEIT-023 | AC-006 | DES-021, CONTRACT-011 | retirement barrier | six passing receipts and fresh reference audit yield eligible | failed, unavailable, stale, or missing evidence yields eligible | CMD-RETIREMENT-PROOF | barrier identities and decision |
+| SEIT-024 | AC-006 | DES-011, DES-022, CONTRACT-006, CONTRACT-011 | retirement restoration | recovery archive restores every proposed removal before approval | missing path, digest mismatch, or uncertain restore passes | CMD-RETIREMENT-PROOF, PROC-RETIREMENT | archive digest and restoration rehearsal |
+| SEIT-025 | AC-006 | DES-022, CONTRACT-011 | retirement apply | separately approved exact manifest applies and gates pass | manifest drift, extra deletion, or post-gate failure lacks restore | PROC-RETIREMENT, CMD-FAST | approval, applied inventory, gate or restore receipt |
+| SEIT-026 | AC-007 | DES-023, CONTRACT-012 | bundle-scope proposal | local draft covers root, coexistence, inclusion, exclusion, symlink, references, and reserved docs | draft invents repository-wide or resource-limit portable rules | PROC-PROPOSAL-DRAFTS | UpstreamProposalDraft and examples |
+| SEIT-027 | AC-007, AC-008 | DES-001, DES-023, CONTRACT-001, CONTRACT-012 | layered-profile proposal | portable floor and additive results remain separate | strict failure is called portable nonconformance | PROC-PROPOSAL-DRAFTS, CMD-PROFILES | proposal and outcome examples |
+| SEIT-028 | AC-007 | DES-009, DES-023, CONTRACT-012 | proposal submission gate | recommendation follows portable proof and stable release | plan, local build, or draft authorizes external write | PROC-PROPOSAL-DRAFTS, PROC-PUBLICATION | current evidence and separate owner decision |
+| SEIT-029 | AC-001, AC-005, AC-008 | DES-025, CONTRACT-003, CONTRACT-007, CONTRACT-010, CONTRACT-013 | claim-state integrity | state labels match current receipts | plan text or prior run is surfaced as current pass | CMD-ROUTE-TRACE | RouteTrace and claim-lint result |
+| SEIT-030 | AC-001, AC-009 | DES-024, DES-025, CONTRACT-013 | canonical artifacts and review | five canonical sources validate and review embeds exact sources | divergent duplicate, missing source, stale review, or prompt dependency remains | CMD-ROUTE-TRACE, PROC-PLAN-CANONICALIZE | artifact digests, links, directory inventory |
+| SEIT-031 | AC-001, AC-004 | DES-019, DES-025, CONTRACT-013 | slice schema and assignments | every slice uses supported assignment and required manifest fields | unsupported route, reasoning, overlap, or missing field passes | CMD-ROUTE-TRACE | parsed assignments and slice manifests |
+| SEIT-032 | AC-009, AC-010 | DES-024, DES-025, CONTRACT-013 | planning stop | route returns for owner selection without execution | Explorer, Expedition, external write, or removal starts | CMD-ROUTE-TRACE, PROC-PLAN-CANONICALIZE | journey stage and unchanged product/consumer inventory |
+
+## Requirement Coverage Matrix
+
+| Requirement | Design/contract | SEIT proof | Command/procedure | Prospective implementation owner | Rollback or N/A |
+| --- | --- | --- | --- | --- | --- |
+| REQ-GATE-001 | DES-001..003, CONTRACT-001..002 | SEIT-001..003 | CMD-OKF-PORTABLE, CMD-PROFILES | shared conformance slice | revert exact core/fixture write set |
+| REQ-GATE-002 | DES-004, CONTRACT-003 | SEIT-004 | CMD-BUDGET, CMD-FAST | shared gate slice | revert registry/test paths together |
+| REQ-GATE-003 | DES-005, CONTRACT-003 | SEIT-005 | CMD-PUBLIC, CMD-FAST | public-root slice | restore prior checker bytes |
+| REQ-GATE-004 | DES-019, CONTRACT-013 | SEIT-020, SEIT-032 | CMD-ROUTE-TRACE | route/integration gate | N/A, read-only validation |
+| REQ-GATE-005 | DES-001..005, CONTRACT-003 | SEIT-006 | shared commands | shared gate slices | revert owning write set |
+| REQ-REL-001 | DES-006..008, CONTRACT-004 | SEIT-007..008 | release build/seal commands | release readiness slice | discard unpromoted dist |
+| REQ-REL-002 | DES-005, DES-008..009 | SEIT-005, SEIT-008..009 | CMD-PUBLIC, PROC-PUBLICATION | release readiness slice | stop before publication |
+| REQ-REL-003 | DES-006..008, CONTRACT-004 | SEIT-008 | CMD-RELEASE-SEAL, CMD-EXACT-SHA | release seal slice | reject identity |
+| REQ-REL-004 | DES-010, CONTRACT-005 | SEIT-010 | CMD-INSTALL-VERIFY | each consumer slice | restore prior pin |
+| REQ-REL-005 | DES-011, CONTRACT-006 | SEIT-011 | CMD-ROLLBACK | each consumer slice | is the rollback proof |
+| REQ-REL-006 | DES-009 | SEIT-009 | PROC-PUBLICATION | publication gate | no side effect before approval |
+| REQ-CONS-001 | DES-012, DES-019, CONTRACT-010 | SEIT-013..018 | six PROC-PARITY-* | six consumer slices | per-consumer |
+| REQ-CONS-002 | DES-019, CONTRACT-013 | SEIT-020 | CMD-ROUTE-TRACE | route validator | N/A |
+| REQ-CONS-003 | DES-013, CONTRACT-007 | SEIT-012 | CMD-CONSUMER-PARITY | parity harness + consumer | read-only corpus |
+| REQ-CONS-004 | DES-013..014, CONTRACT-010 | SEIT-012..019 | six PROC-PARITY-* | each consumer | CMD-ROLLBACK |
+| REQ-CONS-005 | DES-012, DES-020, CONTRACT-010 | SEIT-021..022 | CMD-REFERENCE-AUDIT | each consumer | restore changed references |
+| REQ-CONS-006 | DES-014, DES-021 | SEIT-013..019, SEIT-023 | six procedures, CMD-RETIREMENT-PROOF | gate aggregator | N/A |
+| REQ-CONS-007 | DES-012 | SEIT-010, SEIT-013..018 | six PROC-PARITY-* | owner gate per consumer | no write before approval |
+| REQ-AZS-001 | DES-015, CONTRACT-008 | SEIT-014 | PROC-PARITY-ALPHAZEDE-SPORTS | Sports slice | restore policy/pin |
+| REQ-BETBOT-001 | DES-016, CONTRACT-009 | SEIT-015 | PROC-PARITY-BETBOT | BetBot slice | exact source-byte restore |
+| REQ-PARITY-001 | DES-013, DES-017, CONTRACT-007 | SEIT-012, SEIT-019 | CMD-CONSUMER-PARITY | parity harness | read-only; unavailable blocks |
+| REQ-HGTS-001 | DES-018, CONTRACT-010 | SEIT-017 | PROC-PARITY-HGTS | HGTS slice | no write while absent |
+| REQ-COMPAT-001 | DES-020..021 | SEIT-021, SEIT-023 | CMD-REFERENCE-AUDIT, CMD-RETIREMENT-PROOF | consumers + retirement gate | retained compatibility |
+| REQ-COMPAT-002 | DES-010..011, DES-020 | SEIT-010..011, SEIT-021 | install/rollback commands | each consumer | restore prior pin/fallback |
+| REQ-RETIRE-001 | DES-021..022, CONTRACT-011 | SEIT-023..025 | PROC-RETIREMENT | final separate slice | restoration archive |
+| REQ-RETIRE-002 | DES-022, CONTRACT-011 | SEIT-024..025 | PROC-RETIREMENT | owner-gated retirement | stop before approval |
+| REQ-RETIRE-003 | DES-011, DES-022 | SEIT-024 | CMD-RETIREMENT-PROOF | retirement rehearsal | is the proof |
+| REQ-UPSTREAM-001 | DES-023, CONTRACT-012 | SEIT-026 | PROC-PROPOSAL-DRAFTS | local proposal slice | N/A, local draft |
+| REQ-UPSTREAM-002 | DES-001, DES-023, CONTRACT-012 | SEIT-027 | PROC-PROPOSAL-DRAFTS, CMD-PROFILES | local proposal slice | N/A |
+| REQ-UPSTREAM-003 | DES-009, DES-023 | SEIT-028 | proposal/publication procedures | later owner gate | no external write |
+| REQ-PLAN-001 | DES-024, CONTRACT-013 | SEIT-030 | CMD-ROUTE-TRACE, PROC-PLAN-CANONICALIZE | Bearing planning route | remove stale alias only after validation |
+| REQ-PLAN-002 | DES-025, CONTRACT-013 | SEIT-029..031 | CMD-ROUTE-TRACE | route validator | N/A |
+| REQ-PLAN-003 | CONTRACT-003, CONTRACT-013 | SEIT-001..032 | command registry | SEIT/route owner | N/A |
+| REQ-PLAN-004 | DES-019, OOPDSA DAG | SEIT-020, SEIT-031 | CMD-ROUTE-TRACE | implementation drafting | N/A |
+| REQ-PLAN-005 | DES-024..025 | SEIT-030 | Bearing review generator, CMD-ROUTE-TRACE | Bearing | regenerate, never hand-edit |
+| REQ-PLAN-006 | DES-024 | SEIT-030 | PROC-PLAN-CANONICALIZE | planning closeout | preserve canonical; remove stale alias |
+| REQ-PLAN-007 | DES-025 | SEIT-032 | CMD-ROUTE-TRACE | planning checkpoint | N/A |
+
+## Acceptance traceability
+
+| Acceptance | Required SEIT proof |
+| --- | --- |
+| AC-001 | SEIT-029..031 plus complete requirement matrix |
+| AC-002 | SEIT-001..006 |
+| AC-003 | SEIT-007..011 |
+| AC-004 | SEIT-012..020 |
+| AC-005 | SEIT-014..019 |
+| AC-006 | SEIT-021..025 |
+| AC-007 | SEIT-026..028 |
+| AC-008 | SEIT-003, SEIT-027 |
+| AC-009 | SEIT-030..032 |
+| AC-010 | SEIT-032 |
+
+## Cross-cutting Checks
+
+- **Determinism:** repeat tests with permuted discovery order and compare
+  semantic identities.
+- **Mutation containment:** snapshot every read-only fixture, consumer, and
+  evidence directory before and after.
+- **Path safety:** normalize and root-bind every enumerated or written path;
+  reject symlink aliases for release assets and escaping consumer targets.
+- **Claims:** lint every receipt and review for planned/passed/failed/
+  unavailable/rolled_back accuracy.
+- **Privacy:** scan source, fixtures, logs, receipts, proposal drafts, and
+  release assets for forbidden private material.
+- **Compatibility:** prove legacy surfaces remain callable and recoverable
+  until the final barrier.
+- **Recovery:** byte/configuration/digest uncertainty is a failed rollback.
+- **Concurrency:** compare normalized write sets and dependency DAG before
+  activating parallel consumer lanes.
+
+## Optional and unavailable tools
+
+- Provider or live model evaluation is not required.
+- Network access is not required for shared gates or local release sealing.
+- Public download verification remains unavailable until owner-approved
+  publication.
+- Consumer CI or retrieval runners that are unavailable remain separately
+  typed; fixture success cannot replace them.
+- HGTS work remains discovery-only while its checkout is absent.
+
+## Design-and-SEIT checkpoint
+
+This checkpoint is ready only when:
+
+1. `design.md` and `seit.md` parse from the canonical directory;
+2. all DES, CONTRACT, SEIT, requirement, and acceptance IDs are unique and
+   traceable;
+3. current failures are not presented as passing;
+4. no `implementation.md` or hand-edited `review.html` was created; and
+5. the receipt does not grant publication, consumer mutation, proposal
+   submission, compatibility removal, Explorer, or Expedition authority.
+
+Bearing owns baseline `review.html` generation after this checkpoint. The next
+agent must reuse these exact sources, draft only `implementation.md`, and stop
+again for deterministic review and owner route selection.
+
+## 2026-07-23 Slice 2.1 wire-contract clarification
+
+This section appends the verification procedures and fixture test matrix binding the existing Slice 2.1 command IDs (`CMD-EXACT-SHA`, `CMD-INSTALL-VERIFY`, `CMD-CONSUMER-PARITY`, `CMD-REFERENCE-AUDIT`, `CMD-ROLLBACK`, `CMD-RETIREMENT-PROOF`) to temporary standard-library-only offline fixtures without modifying existing requirements, contracts, slices, paths, or command flags.
+
+### Fixture-based verification suite for wire contracts
+
+Each command ID will be validated against temporary standard-library test fixtures to verify positive wire shapes, all required failure modes, and strict mutation containment.
+
+#### 1. Positive wire shape verification
+
+- **Consumer gate verification (`CMD-INSTALL-VERIFY`, `CMD-CONSUMER-PARITY`, `CMD-REFERENCE-AUDIT`, `CMD-ROLLBACK`):** Will be verified using complete, fully valid `ConsumerGateReceipt` fixtures across generic consumer test cases (including the six consumers `Alphazedehq`, `alphazede-sports`, `betbot`, `developers`, `hgts`, `alphazede-markets`), proving that valid `ReleaseIdentity`, `InstallSnapshot` (with evidence-backed `staged_path` and `prior_pin`), `ParityReceipt` (nested under authoritative `ReleaseIdentity`, with exact `semantic_rows[].native` and `.legacy` keys), `hook_check`, `reference_audit` (with `expected_compatibility`), and `RollbackReceipt` (with exact `restored_paths` items) structures pass with status `passed` and exit code 0.
+- **Six-consumer retirement verification (`CMD-RETIREMENT-PROOF`):** Will be verified using a complete, valid `RetirementManifest` referencing all six passing consumer receipts, valid evidence locator/digest objects for `active_reference_audit` (referencing strict JSON containing matching per-consumer status), `recovery_archive` (referencing a regular non-symlink archive), and `restoration_proof` (referencing strict JSON byte checks and commands), sorted normalized write/deletion path lists, and an `owner_approval_reference`; the fixture must prove successful evaluation without executing apply/post-apply commands and must prove identity-bound freshness.
+
+#### 2. Negative wire shape and failure mode matrix
+
+Verification commands will be executed against temporary fixtures containing single structural or semantic defects to confirm deterministic failure (non-zero exit code, typed blocker/diagnostic emission, and no side effects):
+
+- **Duplicate key failure:** JSON fixture containing duplicate keys within an object (e.g. duplicate top-level keys or duplicate `archives` keys) is rejected.
+- **Unknown behavioral key failure:** Objects containing unrecognized behavioral keys fail verification.
+- **Bad digest failure:** SHA-256 strings containing invalid length, non-hex characters, uppercase hex, or failing bounded recomputation against actual evidence files cause verification failure.
+- **Symlink / path traversal failure:** Evidence locators using absolute paths, empty strings, `.`, `..`, backslashes, or pointing to symlinks or files outside the evidence directory are rejected.
+- **Wrong / dirty revision failure:** Receipt or audit revision failing to match the CLI revision argument or current clean git HEAD causes immediate failure.
+- **InstallSnapshot evidence locator failure:** `InstallSnapshot` where `staged_path` or `prior_pin` evidence locator bytes do not hash to `selected_digest` or `prior_digest` fails verification.
+- **Missing raw parity failure:** `ParityReceipt` missing either `native_raw` or `legacy_raw` evidence locator/digest objects, or where raw evidence is not a UTF-8 JSON array corresponding one-to-one with semantic rows, fails verification.
+- **Missing semantic row key failure:** `ParityReceipt` where any `semantic_rows[].native` or `.legacy` object drops required keys (`locator`, `precedence`, `diagnostic_code`, `conflict`, `unavailable`, `outcome`) fails verification.
+- **Unavailable parity failure:** `ParityReceipt` containing `unavailable` validation/retrieval status blocks consumer completion and exits with failure status.
+- **Reference audit expected compatibility mismatch failure:** `reference_audit` missing a `compatibility-active` match for any object in `expected_compatibility`, or containing a `compatibility-active` match absent from `expected_compatibility`, fails verification.
+- **Unexpected / unclassified reference failure:** `reference_audit` containing `unexpected-active` or `unclassified` classifications fails gate verification.
+- **RollbackReceipt restored paths failure:** `RollbackReceipt` with `restored_paths` item missing exact keys (`path`, `sha256`, `source`), with invalid `source`, escaping path, or mismatching SHA-256 fails verification.
+- **Partial rollback failure:** `RollbackReceipt` with unpassed byte checks, unpassed command execution records, or missing restored paths/digests reports failure.
+- **Stale identity failure:** `ReleaseIdentity` mismatch between consumer gate receipt, install snapshot, and selected release manifest causes failure.
+- **Retirement referenced evidence failure:** `RetirementManifest` where `active_reference_audit` or `restoration_proof` referenced file is not strict JSON with exact required keys, or where `recovery_archive` is a symlink, fails verification.
+- **Missing / five / seven / duplicate consumer failure:** `RetirementManifest` containing fewer than six consumers (e.g. 5), more than six (e.g. 7), missing consumers, or duplicate consumer entries is rejected.
+- **Absent approval reference failure:** `RetirementManifest` with an empty or missing `owner_approval_reference` fails verification.
+
+#### 3. Output determinism and mutation containment
+
+- **Deterministic stdout:** Command stdout will be verified to be byte-for-byte identical across repeated runs on identical fixture inputs, with output sorted lexically by consumer, path, and semantic key, and with compact canonical JSON digests computed via UTF-8 `json.dumps(value, sort_keys=True, separators=(",", ":"), ensure_ascii=False)`.
+- **Before/after directory snapshots:** Pre-run and post-run file system tree and hash snapshots will verify that read-only commands (`install-verify`, `parity`, `reference-audit`, `rollback`, and retirement `verify`) perform zero writes, zero file creations, zero deletions, and zero mutations on the target repository or evidence directory.
+
implementation.md
---
+type: implementation
+name: bran-okf-final-cutover
+status: complete
+date: 2026-07-23
+applies_to: bran
+plan_spec: ./plan-spec.md
+design: ./design.md
+seit: ./seit.md
+planning_route: codex gpt-5.6-sol
+planning_reasoning: high
+---
+
+## Dependencies
+
+- Wave 1: Slice 1.1, then Slice 1.2.
+- Wave 2: Slice 2.1 and Slice 2.2 after Wave 1.
+- Wave 3: Slice 3.1 after Wave 2.
+- Wave 4: Slice 4.1, Slice 4.2, Slice 4.3, Slice 4.4, Slice 4.5, and Slice 4.6 after Wave 3; their writers are disjoint.
+- Wave 5: Slice 5.1 after every Wave 4 consumer reaches a terminal receipt.
+- Wave 6: Slice 6.1 only after Slice 5.1 proves eligibility and the owner separately approves retirement.
+
+## Phase 1 — Shared BRAN gates
+
+### Slice 1.1 — Portable reserved-document conformance
+
+**Goal.** Close the portable reserved `index.md` and `log.md` coverage gap while keeping strict results independent.
+
+**Requirement IDs.** AC-002, AC-008; REQ-GATE-001, REQ-GATE-005.
+
+**Design IDs.** DES-001, DES-002, DES-003, CONTRACT-001, CONTRACT-002.
+
+**SEIT proof rows.** SEIT-001, SEIT-002, SEIT-003.
+
+**Type.** code
+
+**Design lenses.** CDD, SecDD, RDD, ODD, OOPDSA.
+
+**Implementation role.** Crewmate
+
+**Agent model route.** codex gpt-5.6-terra
+
+**Agent reasoning level.** medium
+
+**Ponytail mode.** full
+
+**Review path.** Harness-native read-only reviewer; Surveyor fallback only when unavailable.
+
+### 1.1 execution manifest
+
+**Write set.** Write only `crates/bran-core/src/profile.rs`, `fixtures/conformance/okf-v0.1-index-valid.fixture`, `fixtures/conformance/okf-v0.1-index-invalid.fixture`, `fixtures/conformance/okf-v0.1-log-valid.fixture`, `fixtures/conformance/okf-v0.1-log-invalid.fixture`, `tools/ci/test-budget.json`.
+
+**Command IDs.** CMD-OKF-PORTABLE, CMD-PROFILES.
+
+**Stop condition.** Stop if the normative portable structure cannot be cited, a strict-only rule enters the portable result, or the write set must expand.
+
+**Human decision.** None after the normative source and exact write set are verified; otherwise stop for owner scope direction.
+
+### Slice 1.2 — Public-root repair and fast-gate regression
+
+**Goal.** Remove the doubled-path failure and update `tools/ci/test-budget.json` and `tools/ci/test_budget_check.py` as a deterministic inventory of named CI journeys, direct CI commands, and owned fixtures—not one registry row per Rust unit test. Preserve `CMD-BUDGET` as the first fast-gate check, proving deterministic negative failure on missing/duplicate journeys, direct commands, or fixture ownership, while all Rust unit tests remain mandatory through `CMD-FAST` workspace test commands.
+
+**Requirement IDs.** AC-002; REQ-GATE-002, REQ-GATE-003, REQ-GATE-004, REQ-GATE-005.
+
+**Design IDs.** DES-004, DES-005, CONTRACT-003.
+
+**SEIT proof rows.** SEIT-004, SEIT-005, SEIT-006.
+
+**Type.** code
+
+**Design lenses.** CDD, SecDD, RDD, ODD, OOPDSA.
+
+**Implementation role.** Crewmate
+
+**Agent model route.** codex gpt-5.6-terra
+
+**Agent reasoning level.** medium
+
+**Ponytail mode.** full
+
+**Review path.** Harness-native read-only reviewer; Surveyor fallback only when unavailable.
+
+### 1.2 execution manifest
+
+**Write set.** Write only `tools/ci/public_boundary_check.py`, `tools/ci/test-budget.json`, `tools/ci/test_budget_check.py`, `crates/bran-core/src/migration.rs`, `crates/bran-core/src/packet/mod.rs`, `crates/bran-core/src/policy.rs`, `crates/bran-core/src/profile.rs`, `crates/bran-core/src/scan/mod.rs`, `crates/bran-cli/src/main.rs`.
+
+**Command IDs.** CMD-BUDGET, CMD-PUBLIC, CMD-FAST.
+
+**Stop condition.** Stop if the checker must scan outside the BRAN/public export surface, depends on caller CWD, or the budget check no longer fails first on missing or duplicate inventory entries. Stop if the clippy repair requires semantic behavior change or lint suppression.
+
+**Human decision.** None unless the public export boundary itself must change.
+
+## Phase 2 — Cutover contracts and proposal drafts
+
+### Slice 2.1 — Cutover verification tools
+
+**Goal.** Add the bounded offline verifiers required for exact release, consumer parity, reference, rollback, retirement, and route receipts.
+
+**Requirement IDs.** AC-001, AC-003, AC-004, AC-005, AC-006; REQ-REL-003, REQ-REL-004, REQ-REL-005, REQ-CONS-002, REQ-CONS-003, REQ-CONS-004, REQ-CONS-005, REQ-CONS-006, REQ-PARITY-001, REQ-COMPAT-001, REQ-RETIRE-001, REQ-PLAN-002, REQ-PLAN-003, REQ-PLAN-004.
+
+**Design IDs.** DES-010, DES-011, DES-013, DES-014, DES-017, DES-019, DES-021, DES-025, CONTRACT-005, CONTRACT-006, CONTRACT-007, CONTRACT-010, CONTRACT-011, CONTRACT-013.
+
+**SEIT proof rows.** SEIT-010, SEIT-011, SEIT-012, SEIT-019, SEIT-020, SEIT-021, SEIT-023, SEIT-029, SEIT-031.
+
+**Type.** code
+
+**Design lenses.** CDD, SecDD, RDD, ODD, OOPDSA.
+
+**Implementation role.** Crewmate
+
+**Agent model route.** codex gpt-5.6-terra
+
+**Agent reasoning level.** medium
+
+**Ponytail mode.** full
+
+**Review path.** Harness-native read-only reviewer; Surveyor fallback only when unavailable.
+
+### 2.1 execution manifest
+
+**Write set.** Write only `tools/cutover/verify_release.py`, `tools/cutover/consumer_gate.py`, `tools/cutover/retirement_gate.py`, `tools/cutover/validate_route.py`, `tools/ci/test-budget.json`.
+
+**Command IDs.** CMD-EXACT-SHA, CMD-INSTALL-VERIFY, CMD-CONSUMER-PARITY, CMD-REFERENCE-AUDIT, CMD-ROLLBACK, CMD-RETIREMENT-PROOF, CMD-ROUTE-TRACE.
+
+**Stop condition.** Stop on a dependency, network requirement, hidden consumer rule, write-capable default, semantic-normalization loss, or path outside the exact write set.
+
+**Human decision.** None; every later side-effect mode remains separately gated.
+
+### Slice 2.2 — Upstream OKF proposal drafts
+
+**Goal.** Draft the bundle-scope clarification and layered-profile issue without external submission.
+
+**Requirement IDs.** AC-007, AC-008; REQ-UPSTREAM-001, REQ-UPSTREAM-002, REQ-UPSTREAM-003.
+
+**Design IDs.** DES-001, DES-009, DES-023, CONTRACT-001, CONTRACT-012.
+
+**SEIT proof rows.** SEIT-026, SEIT-027, SEIT-028.
+
+**Type.** documentation
+
+**Design lenses.** CDD, SecDD, RDD, ODD.
+
+**Implementation role.** Crewmate
+
+**Agent model route.** agy agent default
+
+**Agent reasoning level.** medium
+
+**Ponytail mode.** off
+
+**Review path.** Harness-native read-only reviewer; Surveyor fallback only when unavailable.
+
+### 2.2 execution manifest
+
+**Write set.** Write only `docs/integrations/proposals/okf-bundle-scan-scope.md`, `docs/integrations/proposals/okf-layered-profile-separation.md`.
+
+**Command IDs.** PROC-PROPOSAL-DRAFTS, CMD-PROFILES.
+
+**Stop condition.** Stop if either draft claims uncited normative behavior, combines the proposals, or implies submission/publication authority.
+
+**Human decision.** Separate owner approval is required later for each exact external text and destination.
+
+## Phase 3 — Stable release
+
+### Slice 3.1 — Reproducible seal, publication gate, and exact public verification
+
+**Goal.** Build and seal the exact multi-platform release, stop for publication approval, then verify immutable public assets.
+
+**Requirement IDs.** AC-003; REQ-REL-001, REQ-REL-002, REQ-REL-003, REQ-REL-006, REQ-UPSTREAM-003.
+
+**Design IDs.** DES-006, DES-007, DES-008, DES-009, CONTRACT-004.
+
+**SEIT proof rows.** SEIT-007, SEIT-008, SEIT-009.
+
+**Type.** operational
+
+**Design lenses.** CDD, SecDD, RDD, ODD.
+
+**Implementation role.** Crewmate
+
+**Agent model route.** agy agent default
+
+**Agent reasoning level.** medium
+
+**Ponytail mode.** off
+
+**Review path.** Harness-native read-only reviewer; Surveyor fallback only when unavailable.
+
+### 3.1 execution manifest
+
+**Write set.** No writes required in the repository; release archives, seal evidence, and public readback receipts remain outside the source checkout.
+
+**Command IDs.** CMD-RELEASE-PLAN, CMD-RELEASE-BUILD-LINUX-X86, CMD-RELEASE-BUILD-LINUX-ARM, CMD-RELEASE-BUILD-MAC-X86, CMD-RELEASE-BUILD-MAC-ARM, CMD-RELEASE-BUILD-WINDOWS-X86, CMD-RELEASE-CONTRACT, CMD-RELEASE-DRY-SEAL, CMD-RELEASE-SEAL, CMD-EXACT-SHA, PROC-PUBLICATION.
+
+**Stop condition.** Stop on dirty source, missing target, non-reproducible archive, identity/signature/public-boundary mismatch, floating URL, or approval drift.
+
+**Human decision.** Owner approval of the exact tag, source SHA, digest set, fingerprint, destination, and boundary receipt is required before signing, uploading, publishing, or public installation verification.
+
+## Phase 4 — Disjoint consumer migrations
+
+### Slice 4.1 — AlphazedeHQ migration and parity
+
+**Goal.** Install the exact release, switch the BRAN-backed advisory path, prove parity and rollback, and retain every compatibility surface.
+
+**Requirement IDs.** AC-004, AC-005, AC-006; REQ-REL-004, REQ-REL-005, REQ-CONS-001, REQ-CONS-003, REQ-CONS-004, REQ-CONS-005, REQ-CONS-006, REQ-CONS-007, REQ-PARITY-001, REQ-COMPAT-001, REQ-COMPAT-002.
+
+**Design IDs.** DES-010, DES-011, DES-012, DES-013, DES-014, DES-017, DES-019, DES-020, CONTRACT-005, CONTRACT-006, CONTRACT-007, CONTRACT-010, CONTRACT-013.
+
+**SEIT proof rows.** SEIT-010, SEIT-011, SEIT-012, SEIT-013, SEIT-019, SEIT-020, SEIT-021, SEIT-022.
+
+**Type.** consumer
+
+**Design lenses.** CDD, SecDD, RDD, ODD, OOPDSA.
+
+**Implementation role.** Crewmate
+
+**Agent model route.** codex gpt-5.6-terra
+
+**Agent reasoning level.** medium
+
+**Ponytail mode.** full
+
+**Review path.** Harness-native read-only reviewer; Surveyor fallback only when unavailable.
+
+### 4.1 execution manifest
+
+**Write set.** Within the AlphazedeHQ checkout write only `.bran/policy.yaml`, `.bran/evidence/bran-cutover.json`, `.grok/hooks/use-okf.sh`, `.grok/hooks/use-okf.json`, `tools/okf/runtime/bran-release-pin.json`.
+
+**Command IDs.** CMD-EXACT-SHA, CMD-INSTALL-VERIFY, CMD-CONSUMER-PARITY, CMD-REFERENCE-AUDIT, CMD-ROLLBACK, CMD-ROUTE-TRACE, PROC-PARITY-ALPHAZEDEHQ.
+
+**Stop condition.** Stop on repository/revision mismatch, unavailable retrieval, hook contract drift, unexpected active reference, parity failure, or rollback mismatch.
+
+**Human decision.** Owner approval of this checkout, revision, artifact digest, exact write set, commands, and rollback is required before mutation.
+
+### Slice 4.2 — AlphaZede Sports migration and granular boundary parity
+
+**Goal.** Install the exact release and prove the repository's granular public-boundary policy, parity, references, and rollback.
+
+**Requirement IDs.** AC-004, AC-005, AC-006; REQ-REL-004, REQ-REL-005, REQ-CONS-001, REQ-CONS-003, REQ-CONS-004, REQ-CONS-005, REQ-CONS-006, REQ-CONS-007, REQ-AZS-001, REQ-PARITY-001, REQ-COMPAT-001, REQ-COMPAT-002.
+
+**Design IDs.** DES-010, DES-011, DES-012, DES-013, DES-014, DES-015, DES-017, DES-019, DES-020, CONTRACT-005, CONTRACT-006, CONTRACT-007, CONTRACT-008, CONTRACT-010, CONTRACT-013.
+
+**SEIT proof rows.** SEIT-010, SEIT-011, SEIT-012, SEIT-014, SEIT-019, SEIT-020, SEIT-021, SEIT-022.
+
+**Type.** consumer
+
+**Design lenses.** CDD, SecDD, RDD, ODD, OOPDSA.
+
+**Implementation role.** Crewmate
+
+**Agent model route.** codex gpt-5.6-terra
+
+**Agent reasoning level.** medium
+
+**Ponytail mode.** full
+
+**Review path.** Harness-native read-only reviewer; Surveyor fallback only when unavailable.
+
+### 4.2 execution manifest
+
+**Write set.** Within the alphazede-sports checkout write only `.bran/policy.yaml`, `.bran/evidence/bran-cutover.json`, `tools/okf/runtime/bran-release-pin.json`.
+
+**Command IDs.** CMD-EXACT-SHA, CMD-INSTALL-VERIFY, CMD-CONSUMER-PARITY, CMD-REFERENCE-AUDIT, CMD-ROLLBACK, CMD-ROUTE-TRACE, PROC-PARITY-ALPHAZEDE-SPORTS.
+
+**Stop condition.** Stop on repository/revision mismatch, ambiguous boundary precedence, unmatched required path, unavailable retrieval, parity/reference failure, or rollback mismatch.
+
+**Human decision.** Owner approval of this checkout, revision, boundary rules, artifact digest, exact write set, commands, and rollback is required before mutation.
+
+### Slice 4.3 — BetBot migration and oversized-document resolution
+
+**Goal.** Install the exact release and resolve the oversized knowledge document without raising BRAN's global limit, then prove parity and rollback.
+
+**Requirement IDs.** AC-004, AC-005, AC-006; REQ-REL-004, REQ-REL-005, REQ-CONS-001, REQ-CONS-003, REQ-CONS-004, REQ-CONS-005, REQ-CONS-006, REQ-CONS-007, REQ-BETBOT-001, REQ-PARITY-001, REQ-COMPAT-001, REQ-COMPAT-002.
+
+**Design IDs.** DES-010, DES-011, DES-012, DES-013, DES-014, DES-016, DES-017, DES-019, DES-020, CONTRACT-005, CONTRACT-006, CONTRACT-007, CONTRACT-009, CONTRACT-010, CONTRACT-013.
+
+**SEIT proof rows.** SEIT-010, SEIT-011, SEIT-012, SEIT-015, SEIT-019, SEIT-020, SEIT-021, SEIT-022.
+
+**Type.** consumer
+
+**Design lenses.** CDD, SecDD, RDD, ODD, OOPDSA.
+
+**Implementation role.** Crewmate
+
+**Agent model route.** codex gpt-5.6-terra
+
+**Agent reasoning level.** medium
+
+**Ponytail mode.** full
+
+**Review path.** Harness-native read-only reviewer; Surveyor fallback only when unavailable.
+
+### 4.3 execution manifest
+
+**Write set.** Within the BetBot checkout write only `.bran/policy.yaml`, `.bran/evidence/bran-cutover.json`, `.bran/migrations/oversized-document-plan.json`, `docs/okf`, `tools/okf/runtime/bran-release-pin.json`.
+
+**Command IDs.** CMD-EXACT-SHA, CMD-INSTALL-VERIFY, CMD-CONSUMER-PARITY, CMD-REFERENCE-AUDIT, CMD-ROLLBACK, CMD-ROUTE-TRACE, PROC-PARITY-BETBOT.
+
+**Stop condition.** Stop if the exact oversized source is outside `docs/okf`, the semantic split lacks owner approval, locators/relationships change without mapping, retrieval is unavailable, parity fails, or rollback differs.
+
+**Human decision.** Owner approval of the exact source and split paths, checkout revision, artifact digest, write set, commands, and rollback is required before mutation.
+
+### Slice 4.4 — developers public consumer migration and parity
+
+**Goal.** Install the exact public release and prove exported-source identity, parity, references, and rollback.
+
+**Requirement IDs.** AC-004, AC-005, AC-006; REQ-REL-004, REQ-REL-005, REQ-CONS-001, REQ-CONS-003, REQ-CONS-004, REQ-CONS-005, REQ-CONS-006, REQ-CONS-007, REQ-PARITY-001, REQ-COMPAT-001, REQ-COMPAT-002.
+
+**Design IDs.** DES-010, DES-011, DES-012, DES-013, DES-014, DES-017, DES-019, DES-020, CONTRACT-005, CONTRACT-006, CONTRACT-007, CONTRACT-010, CONTRACT-013.
+
+**SEIT proof rows.** SEIT-010, SEIT-011, SEIT-012, SEIT-016, SEIT-019, SEIT-020, SEIT-021, SEIT-022.
+
+**Type.** consumer
+
+**Design lenses.** CDD, SecDD, RDD, ODD, OOPDSA.
+
+**Implementation role.** Crewmate
+
+**Agent model route.** codex gpt-5.6-terra
+
+**Agent reasoning level.** medium
+
+**Ponytail mode.** full
+
+**Review path.** Harness-native read-only reviewer; Surveyor fallback only when unavailable.
+
+### 4.4 execution manifest
+
+**Write set.** Within the developers checkout write only `.bran/policy.yaml`, `.bran/evidence/bran-cutover.json`, `tools/okf/runtime/bran-release-pin.json`.
+
+**Command IDs.** CMD-EXACT-SHA, CMD-INSTALL-VERIFY, CMD-CONSUMER-PARITY, CMD-REFERENCE-AUDIT, CMD-ROLLBACK, CMD-ROUTE-TRACE, PROC-PARITY-DEVELOPERS.
+
+**Stop condition.** Stop on repository/revision mismatch, export/source identity mismatch, floating asset, unavailable retrieval, parity/reference failure, or rollback mismatch.
+
+**Human decision.** Owner approval of this checkout, revision, artifact digest, exact write set, commands, and rollback is required before mutation.
+
+### Slice 4.5 — HGTS discovery, migration, and parity
+
+**Goal.** Verify HGTS identity when available, then install and prove parity and rollback without substituting another checkout.
+
+**Requirement IDs.** AC-004, AC-005, AC-006; REQ-REL-004, REQ-REL-005, REQ-CONS-001, REQ-CONS-003, REQ-CONS-004, REQ-CONS-005, REQ-CONS-006, REQ-CONS-007, REQ-HGTS-001, REQ-PARITY-001, REQ-COMPAT-001, REQ-COMPAT-002.
+
+**Design IDs.** DES-010, DES-011, DES-012, DES-013, DES-014, DES-017, DES-018, DES-019, DES-020, CONTRACT-005, CONTRACT-006, CONTRACT-007, CONTRACT-010, CONTRACT-013.
+
+**SEIT proof rows.** SEIT-010, SEIT-011, SEIT-012, SEIT-017, SEIT-019, SEIT-020, SEIT-021, SEIT-022.
+
+**Type.** consumer
+
+**Design lenses.** CDD, SecDD, RDD, ODD, OOPDSA.
+
+**Implementation role.** Crewmate
+
+**Agent model route.** codex gpt-5.6-terra
+
+**Agent reasoning level.** medium
+
+**Ponytail mode.** full
+
+**Review path.** Harness-native read-only reviewer; Surveyor fallback only when unavailable.
+
+### 4.5 execution manifest
+
+**Write set.** When HGTS is absent, write nothing; after identity and owner approval, within the HGTS checkout write only `.bran/policy.yaml`, `.bran/evidence/bran-cutover.json`, `tools/okf/runtime/bran-release-pin.json`.
+
+**Command IDs.** CMD-EXACT-SHA, CMD-INSTALL-VERIFY, CMD-CONSUMER-PARITY, CMD-REFERENCE-AUDIT, CMD-ROLLBACK, CMD-ROUTE-TRACE, PROC-PARITY-HGTS.
+
+**Stop condition.** Stop with `unavailable` while HGTS is absent, or on identity/revision mismatch, unavailable retrieval, parity/reference failure, or rollback mismatch.
+
+**Human decision.** Owner approval of the verified checkout, revision, artifact digest, exact write set, commands, and rollback is required before any HGTS mutation.
+
+### Slice 4.6 — alphazede-markets migration and parity
+
+**Goal.** Install the exact release and prove policy, validation/retrieval parity, references, and rollback.
+
+**Requirement IDs.** AC-004, AC-005, AC-006; REQ-REL-004, REQ-REL-005, REQ-CONS-001, REQ-CONS-003, REQ-CONS-004, REQ-CONS-005, REQ-CONS-006, REQ-CONS-007, REQ-PARITY-001, REQ-COMPAT-001, REQ-COMPAT-002.
+
+**Design IDs.** DES-010, DES-011, DES-012, DES-013, DES-014, DES-017, DES-019, DES-020, CONTRACT-005, CONTRACT-006, CONTRACT-007, CONTRACT-010, CONTRACT-013.
+
+**SEIT proof rows.** SEIT-010, SEIT-011, SEIT-012, SEIT-018, SEIT-019, SEIT-020, SEIT-021, SEIT-022.
+
+**Type.** consumer
+
+**Design lenses.** CDD, SecDD, RDD, ODD, OOPDSA.
+
+**Implementation role.** Crewmate
+
+**Agent model route.** codex gpt-5.6-terra
+
+**Agent reasoning level.** medium
+
+**Ponytail mode.** full
+
+**Review path.** Harness-native read-only reviewer; Surveyor fallback only when unavailable.
+
+### 4.6 execution manifest
+
+**Write set.** Within the alphazede-markets checkout write only `.bran/policy.yaml`, `.bran/evidence/bran-cutover.json`, `tools/okf/runtime/bran-release-pin.json`.
+
+**Command IDs.** CMD-EXACT-SHA, CMD-INSTALL-VERIFY, CMD-CONSUMER-PARITY, CMD-REFERENCE-AUDIT, CMD-ROLLBACK, CMD-ROUTE-TRACE, PROC-PARITY-ALPHAZEDE-MARKETS.
+
+**Stop condition.** Stop on repository/revision mismatch, unavailable retrieval, policy/parity/reference failure, or rollback mismatch.
+
+**Human decision.** Owner approval of this checkout, revision, artifact digest, exact write set, commands, and rollback is required before mutation.
+
+## Phase 5 — Global evidence barrier
+
+### Slice 5.1 — Retirement eligibility and restoration rehearsal
+
+**Goal.** Aggregate six immutable consumer receipts, audit active references, and prove restoration before retirement can be recommended.
+
+**Requirement IDs.** AC-004, AC-005, AC-006; REQ-CONS-006, REQ-COMPAT-001, REQ-RETIRE-001, REQ-RETIRE-002, REQ-RETIRE-003.
+
+**Design IDs.** DES-011, DES-020, DES-021, DES-022, CONTRACT-006, CONTRACT-010, CONTRACT-011.
+
+**SEIT proof rows.** SEIT-021, SEIT-022, SEIT-023, SEIT-024, SEIT-029.
+
+**Type.** operational
+
+**Design lenses.** CDD, SecDD, RDD, ODD, OOPDSA.
+
+**Implementation role.** Crewmate
+
+**Agent model route.** agy agent default
+
+**Agent reasoning level.** medium
+
+**Ponytail mode.** off
+
+**Review path.** Harness-native read-only reviewer; Surveyor fallback only when unavailable.
+
+### 5.1 execution manifest
+
+**Write set.** No writes required in consumer repositories; the retirement manifest, reference audit, and restoration rehearsal remain owner-reviewable runtime evidence.
+
+**Command IDs.** CMD-REFERENCE-AUDIT, CMD-RETIREMENT-PROOF, PROC-RETIREMENT.
+
+**Stop condition.** Stop on any non-passing, stale, missing, or unavailable consumer receipt, unexpected active reference, recovery archive mismatch, or failed restoration rehearsal.
+
+**Human decision.** No removal is authorized; return the exact retirement packet for a separate owner decision.
+
+## Phase 6 — Separately approved global retirement
+
+### Slice 6.1 — Compatibility retirement transaction
+
+**Goal.** After separate approval, apply the exact global retirement manifest, run integrated gates, and restore on any failure.
+
+**Requirement IDs.** AC-006; REQ-COMPAT-001, REQ-COMPAT-002, REQ-RETIRE-001, REQ-RETIRE-002, REQ-RETIRE-003.
+
+**Design IDs.** DES-011, DES-021, DES-022, CONTRACT-006, CONTRACT-011.
+
+**SEIT proof rows.** SEIT-023, SEIT-024, SEIT-025.
+
+**Type.** destructive
+
+**Design lenses.** CDD, SecDD, RDD, ODD, OOPDSA.
+
+**Implementation role.** Crewmate
+
+**Agent model route.** agy agent default
+
+**Agent reasoning level.** medium
+
+**Ponytail mode.** off
+
+**Review path.** Harness-native read-only reviewer; Surveyor fallback only when unavailable.
+
+### 6.1 execution manifest
+
+**Write set.** Across the owner-approved Alphazede workspace write only `Alphazedehq/.grok/hooks/use-okf.sh`, `Alphazedehq/.grok/hooks/use-okf.json`, `Alphazedehq/skills/use-okf`, `Alphazedehq/tools/okf/okf`, `Alphazedehq/tools/okf/config.yaml`, `alphazede-sports/tools/okf/config.yaml`, `betbot/tools/okf/config.yaml`, `developers/tools/okf/config.yaml`, `hgts/tools/okf/config.yaml`, `alphazede-markets/tools/okf/config.yaml`.
+
+**Command IDs.** CMD-RETIREMENT-PROOF, PROC-RETIREMENT, CMD-FAST.
+
+**Stop condition.** Stop before writes without six passing receipts and exact approval; after writes, stop and restore on manifest drift, extra deletion, active reference, or any integrated-gate failure.
+
+**Human decision.** Separate explicit owner approval of the exact retirement manifest, deletion targets, recovery archive, restoration proof, commands, and evidence is mandatory.
+

Actual implementation and QA

Pending implementation and validation.

diff --git a/docs/plans/2026-07-22-bran-okf-final-cutover/seit.md b/docs/plans/2026-07-22-bran-okf-final-cutover/seit.md new file mode 100644 index 0000000..c32c423 --- /dev/null +++ b/docs/plans/2026-07-22-bran-okf-final-cutover/seit.md @@ -0,0 +1,368 @@ +--- +type: seit +name: bran-okf-final-cutover +status: complete +date: 2026-07-23 +applies_to: bran +plan_spec: ./plan-spec.md +design: ./design.md +planning_route: codex gpt-5.6-sol +planning_reasoning: high +--- + +## Purpose + +This SEIT plan defines prospective proof for the BRAN final OKF cutover. It does +not claim that planned commands, consumer repositories, a stable release, or +retirement evidence exist. Current observations are labeled separately from +future acceptance. + +## Evidence state + +### Verified current + +- `CMD-BUDGET` fails (exits 1) because the existing checker requires per-unit-test + registration against the obsolete fixed ceiling. +- `CMD-FAST` stops at `CMD-BUDGET` first due to the test budget failure. +- `CMD-PUBLIC` fails on the doubled path + `/home/spectre/alphazede/bran/bran/fixtures/...`. +- BRAN distinguishes `index.md` and `log.md`, but current portable profile code + does not validate their upstream structures. + +### Planned + +- Test-budget no-ceiling inventory update and budget gate repair (`CMD-BUDGET`). +- Reserved-document portable conformance. +- Portable root behavior for `CMD-PUBLIC`. +- Release build/seal/publication/install verification. +- Six consumer migrations and parity receipts. +- Compatibility retirement and both upstream proposal drafts. + +### Unavailable + +- Retrieval parity evidence. +- HGTS checkout and current revision. +- Owner-approved stable public release identity. +- Owner approval for consumer writes, external proposal submission, or + retirement. + +## Test strategy + +### Pre-lens stance + +Use offline deterministic unit, contract, fixture, and procedure tests. Freeze +all repository/corpus identities before comparison. Retain raw evidence before +normalization. Use exact digests rather than timestamps as identity. + +### Lens additions + +- **CDD:** schema, version, profile, command, adapter, manifest, parity, and + receipt contract cases. +- **SecDD:** path traversal, symlink, boundary conflict, signature, checksum, + wrong revision, private-data, and unauthorized-side-effect cases. +- **RDD:** missing repository/runner, timeout, partial build/install, retry, + rollback, and restoration-failure cases. +- **ODD:** exact command/revision/input evidence, first failure, unavailable + state, deterministic ordering, and claim-state cases. +- **OOPDSA:** state transition, value-object validation, boundary precedence, + DAG cycle, and write-set overlap cases. + +### Evidence retention + +Each required row retains: + +- command/procedure ID and exact invocation; +- repository identity and exact revision; +- relevant config/corpus/artifact digests; +- stdout/stderr or structured raw output; +- exit code and first failure; +- normalized semantic receipt when applicable; +- before/after mutation inventory for write-capable procedures; and +- rollback receipt or explicit non-applicability. + +Private corpus bodies, credentials, raw authentication state, hidden grader +truth, and unsanitized provider traces are forbidden evidence. + +## Command context + +Commands run from the BRAN repository root unless a procedure explicitly +changes into an owner-approved consumer checkout. + +Execution binds these variables to exact values before a release or consumer +procedure: + +```sh +BRAN_TAG=bran-vX.Y.Z +BRAN_SOURCE_SHA= +BRAN_DIST= +BRAN_FINGERPRINT= +BRAN_MANIFEST= +BRAN_ASSET= +CONSUMER_ROOT= +CONSUMER_REVISION= +CONSUMER_MANIFEST= +EVIDENCE_DIR= +``` + +Placeholders are planning bindings, not permission to choose a tag, key, +checkout, or destination. The implementation slice must record their resolved +values before any side effect. + +## Required Commands + +### Existing BRAN commands + +- **CMD-OKF-PORTABLE** — + `cargo test --manifest-path Cargo.toml -p bran-core p1_conformance` +- **CMD-PROFILES** — + `cargo test --manifest-path Cargo.toml -p bran-core profile::tests::p1_profiles` +- **CMD-BUDGET** — + `python3 tools/ci/test_budget_check.py tools/ci/test-budget.json` +- **CMD-FAST** — `./tools/ci/check.sh --fast` +- **CMD-PUBLIC** — `python3 tools/ci/public_boundary_check.py` +- **CMD-RELEASE-CONTRACT** — + `python3 tools/ci/release_contract_check.py` +- **CMD-RELEASE-PLAN** — + `./tools/ci/build-release.sh --plan --tag "$BRAN_TAG" --dist "$BRAN_DIST"` +- **CMD-RELEASE-BUILD-LINUX-X86** — + `./tools/ci/build-release.sh --target x86_64-unknown-linux-gnu --tag "$BRAN_TAG" --dist "$BRAN_DIST"` +- **CMD-RELEASE-BUILD-LINUX-ARM** — + `./tools/ci/build-release.sh --target aarch64-unknown-linux-gnu --tag "$BRAN_TAG" --dist "$BRAN_DIST"` +- **CMD-RELEASE-BUILD-MAC-X86** — + `./tools/ci/build-release.sh --target x86_64-apple-darwin --tag "$BRAN_TAG" --dist "$BRAN_DIST"` +- **CMD-RELEASE-BUILD-MAC-ARM** — + `./tools/ci/build-release.sh --target aarch64-apple-darwin --tag "$BRAN_TAG" --dist "$BRAN_DIST"` +- **CMD-RELEASE-BUILD-WINDOWS-X86** — + `./tools/ci/build-release.sh --target x86_64-pc-windows-msvc --tag "$BRAN_TAG" --dist "$BRAN_DIST"` +- **CMD-RELEASE-DRY-SEAL** — + `./tools/ci/release-check.sh --tag "$BRAN_TAG" --dist "$BRAN_DIST" --dry-run-unsigned` +- **CMD-RELEASE-SEAL** — + `./tools/ci/release-check.sh --tag "$BRAN_TAG" --dist "$BRAN_DIST" --fingerprint "$BRAN_FINGERPRINT"` + +### Planned bounded verification commands + +These interfaces are prospective. Their owning implementation slices must +create them before any dependent consumer slice: + +- **CMD-EXACT-SHA** — + `python3 tools/cutover/verify_release.py --manifest "$BRAN_MANIFEST" --asset "$BRAN_ASSET" --source-sha "$BRAN_SOURCE_SHA" --fingerprint "$BRAN_FINGERPRINT"` +- **CMD-INSTALL-VERIFY** — + `python3 tools/cutover/consumer_gate.py install-verify --consumer "$CONSUMER_ROOT" --revision "$CONSUMER_REVISION" --manifest "$CONSUMER_MANIFEST" --evidence "$EVIDENCE_DIR"` +- **CMD-CONSUMER-PARITY** — + `python3 tools/cutover/consumer_gate.py parity --consumer "$CONSUMER_ROOT" --revision "$CONSUMER_REVISION" --manifest "$CONSUMER_MANIFEST" --evidence "$EVIDENCE_DIR"` +- **CMD-REFERENCE-AUDIT** — + `python3 tools/cutover/consumer_gate.py reference-audit --consumer "$CONSUMER_ROOT" --revision "$CONSUMER_REVISION" --manifest "$CONSUMER_MANIFEST" --evidence "$EVIDENCE_DIR"` +- **CMD-ROLLBACK** — + `python3 tools/cutover/consumer_gate.py rollback --consumer "$CONSUMER_ROOT" --revision "$CONSUMER_REVISION" --manifest "$CONSUMER_MANIFEST" --evidence "$EVIDENCE_DIR"` +- **CMD-RETIREMENT-PROOF** — + `python3 tools/cutover/retirement_gate.py verify --manifest "$RETIREMENT_MANIFEST" --evidence "$EVIDENCE_DIR"` +- **CMD-ROUTE-TRACE** — + `python3 tools/cutover/validate_route.py docs/plans/2026-07-22-bran-okf-final-cutover` + +The planned tools are standard-library-only, offline, and read-only unless +invoked in the explicitly owner-approved install, rollback, or retirement +mode. Read-only modes reject a changed consumer tree. + +### Stable consumer procedure IDs + +Each procedure binds the shared commands to one exact consumer manifest and +checkout. It includes discovery, owner gate, install verification, validation +and retrieval parity, hook/skill check, active-reference audit, rollback proof, +and final `ConsumerGateReceipt`. + +- **PROC-PARITY-ALPHAZEDEHQ** +- **PROC-PARITY-ALPHAZEDE-SPORTS** +- **PROC-PARITY-BETBOT** +- **PROC-PARITY-DEVELOPERS** +- **PROC-PARITY-HGTS** +- **PROC-PARITY-ALPHAZEDE-MARKETS** + +Additional procedures: + +- **PROC-PUBLICATION** — resolve release variables, run release build/seal + commands, stop for approval, publish later, then verify exact public assets. +- **PROC-PROPOSAL-DRAFTS** — write both local drafts and prove their claim + boundaries; no external write. +- **PROC-RETIREMENT** — evaluate the barrier, prove restoration, stop for + approval, apply exact manifest later, and revalidate or restore. +- **PROC-PLAN-CANONICALIZE** — verify the five artifacts in the canonical + directory, ensure review embeds exact sources, and remove the stale + auto-slugged alias only after Bearing no longer depends on it. + +## Traceability Matrix + +| SEIT row ID | Acceptance/Risk ID | Design/Contract ID | Boundary/Test Layer | Positive Case | Negative/Failure Case | Command/Procedure ID | Evidence | +| --- | --- | --- | --- | --- | --- | --- | --- | +| SEIT-001 | AC-002 | DES-001, DES-002, DES-003, CONTRACT-001, CONTRACT-002 | portable index conformance | frozen upstream-valid index passes `okf-v0.1` | each cited structural violation yields a stable portable code | CMD-OKF-PORTABLE, CMD-PROFILES | normative locator, fixtures, both profile outcomes | +| SEIT-002 | AC-002 | DES-001, DES-002, DES-003, CONTRACT-001, CONTRACT-002 | portable log conformance | frozen upstream-valid log passes `okf-v0.1` | each cited structural violation yields a stable portable code | CMD-OKF-PORTABLE, CMD-PROFILES | normative locator, fixtures, ordered diagnostics | +| SEIT-003 | AC-002, AC-008 | DES-001, DES-003, CONTRACT-001 | profile contract | portable pass/strict fail and portable fail/strict result remain separate | strict-only code changes portable status or selected exit | CMD-PROFILES | four outcome combinations and CLI envelope | +| SEIT-004 | AC-002 | DES-004, CONTRACT-003 | test-budget gate | named CI journeys, direct CI commands, and owned fixtures are deterministically inventoried; all Rust unit tests run in CMD-FAST | missing/duplicate journey, direct command, or fixture ownership fails CMD-BUDGET before expensive steps | CMD-BUDGET, CMD-FAST | budget inventory diff and first-gate output | +| SEIT-005 | AC-002 | DES-005, CONTRACT-003 | public-root security | root and relocated checkout find the exact public surface | doubled prefix, caller CWD, traversal, symlink, or broad scope passes | CMD-PUBLIC, CMD-FAST | resolved root, enumerated relative paths, exits | +| SEIT-006 | AC-002 | DES-001, DES-002, DES-003, DES-004, DES-005, CONTRACT-003 | offline shared gates | shared commands pass without provider or owner-local configuration | a shared command attempts network/provider lookup | CMD-OKF-PORTABLE, CMD-BUDGET, CMD-PUBLIC, CMD-FAST | sanitized environment and receipts | +| SEIT-007 | AC-003 | DES-006, DES-007, DES-008, CONTRACT-004 | deterministic release build | two same-input builds produce byte-identical target archives | dirty tree, missing lock/target, unknown target, or altered metadata passes | CMD-RELEASE-PLAN, CMD-RELEASE-BUILD-LINUX-X86, CMD-RELEASE-BUILD-LINUX-ARM, CMD-RELEASE-BUILD-MAC-X86, CMD-RELEASE-BUILD-MAC-ARM, CMD-RELEASE-BUILD-WINDOWS-X86 | source, tag, lock, and archive digests | +| SEIT-008 | AC-003 | DES-006, DES-007, DES-008, DES-009, CONTRACT-004 | release seal and provenance | tag, commit, lock, checksums, signature, manifest, and provenance agree | wrong tag/SHA/fingerprint, floating URL, tampered or extra asset, or symlink passes | CMD-RELEASE-CONTRACT, CMD-RELEASE-DRY-SEAL, CMD-RELEASE-SEAL, CMD-EXACT-SHA | ReleaseIdentity and seal output | +| SEIT-009 | AC-003 | DES-009, CONTRACT-004 | publication authority | approved exact packet is the only publishable identity | dry-run, recommendation, or stale approval authorizes publication | PROC-PUBLICATION | exact owner decision and immutable public readback | +| SEIT-010 | AC-003, AC-004 | DES-010, CONTRACT-005 | consumer installation | staged asset verifies before one pin changes | overwrite, digest/member/version mismatch, or latest URL selects | CMD-EXACT-SHA, CMD-INSTALL-VERIFY | InstallSnapshot and pin readback | +| SEIT-011 | AC-003, AC-004 | DES-011, CONTRACT-006 | consumer rollback | prior pin and bytes restore and focused commands pass | partial restore or failed verification reports success | CMD-ROLLBACK | RollbackReceipt and byte inventory | +| SEIT-012 | AC-004 | DES-013, DES-014, CONTRACT-007 | semantic parity | identical frozen input produces equivalent validation/retrieval semantics | normalizer hides locator, precedence, conflict, diagnostic, or unavailable state | CMD-CONSUMER-PARITY | raw pair, normalizer version, semantic diff | +| SEIT-013 | AC-004, AC-006 | DES-012, DES-013, DES-014, DES-019, DES-020, CONTRACT-010 | AlphazedeHQ consumer gate | install, parity, hook/skill, audit, and rollback pass | unexpected legacy reference or fail-open hook drift is ignored | PROC-PARITY-ALPHAZEDEHQ | ConsumerGateReceipt | +| SEIT-014 | AC-004, AC-005 | DES-012, DES-013, DES-014, DES-015, DES-019, DES-020, CONTRACT-008, CONTRACT-010 | AlphaZede Sports gate | granular allow/deny/inheritance rules and complete gate pass | ambiguous, escaping, unmatched, or weakened boundary policy passes | PROC-PARITY-ALPHAZEDE-SPORTS | rule set, boundary matrix, ConsumerGateReceipt | +| SEIT-015 | AC-004, AC-005 | DES-012, DES-013, DES-014, DES-016, DES-019, DES-020, CONTRACT-009, CONTRACT-010 | BetBot gate | approved split preserves locators, parity, bounded size, and rollback | global cap rises, content is lost, or rollback differs | PROC-PARITY-BETBOT | OversizedDocumentPlan, retrieval diff, byte rollback | +| SEIT-016 | AC-004 | DES-012, DES-013, DES-014, DES-019, DES-020, CONTRACT-010 | developers consumer gate | public source, install, parity, audit, and rollback agree | exported source differs or floating release is used | PROC-PARITY-DEVELOPERS | ConsumerGateReceipt and export/source identity | +| SEIT-017 | AC-004, AC-005 | DES-012, DES-014, DES-017, DES-018, DES-019, DES-020, CONTRACT-010 | HGTS consumer gate | verified checkout identity then complete gate passes | absent or wrong checkout is substituted or inferred passing | PROC-PARITY-HGTS | discovery or typed unavailable receipt | +| SEIT-018 | AC-004 | DES-012, DES-013, DES-014, DES-019, DES-020, CONTRACT-010 | alphazede-markets gate | install, parity, audit, and rollback pass | repository identity or receipt mismatch is ignored | PROC-PARITY-ALPHAZEDE-MARKETS | ConsumerGateReceipt | +| SEIT-019 | AC-004, AC-005 | DES-014, DES-017, DES-018, CONTRACT-007, CONTRACT-010 | unavailable parity | missing runner/corpus/capability yields typed unavailable | unavailable is normalized to success or silently skipped | PROC-PARITY-ALPHAZEDEHQ, PROC-PARITY-ALPHAZEDE-SPORTS, PROC-PARITY-BETBOT, PROC-PARITY-DEVELOPERS, PROC-PARITY-HGTS, PROC-PARITY-ALPHAZEDE-MARKETS | raw error, typed row, blocked gate | +| SEIT-020 | AC-001, AC-004 | DES-019, DES-025, CONTRACT-013 | route DAG and write sets | consumer write sets are disjoint and shared work precedes them | overlap or dependency cycle is accepted | CMD-ROUTE-TRACE | normalized write sets and DAG report | +| SEIT-021 | AC-006 | DES-020, DES-021, CONTRACT-010 | compatibility retention | legacy surfaces and prior binaries stay recoverable | a consumer slice deletes or disables compatibility | CMD-REFERENCE-AUDIT, PROC-PARITY-ALPHAZEDEHQ, PROC-PARITY-ALPHAZEDE-SPORTS, PROC-PARITY-BETBOT, PROC-PARITY-DEVELOPERS, PROC-PARITY-HGTS, PROC-PARITY-ALPHAZEDE-MARKETS | before/after path and reference inventory | +| SEIT-022 | AC-004, AC-006 | DES-012, DES-020, CONTRACT-010 | active reference audit | active compatibility and historical references classify deterministically | unexpected active reference is ignored or history triggers deletion | CMD-REFERENCE-AUDIT | raw matches, classification, digest | +| SEIT-023 | AC-006 | DES-021, CONTRACT-011 | retirement barrier | six passing receipts and fresh reference audit yield eligible | failed, unavailable, stale, or missing evidence yields eligible | CMD-RETIREMENT-PROOF | barrier identities and decision | +| SEIT-024 | AC-006 | DES-011, DES-022, CONTRACT-006, CONTRACT-011 | retirement restoration | recovery archive restores every proposed removal before approval | missing path, digest mismatch, or uncertain restore passes | CMD-RETIREMENT-PROOF, PROC-RETIREMENT | archive digest and restoration rehearsal | +| SEIT-025 | AC-006 | DES-022, CONTRACT-011 | retirement apply | separately approved exact manifest applies and gates pass | manifest drift, extra deletion, or post-gate failure lacks restore | PROC-RETIREMENT, CMD-FAST | approval, applied inventory, gate or restore receipt | +| SEIT-026 | AC-007 | DES-023, CONTRACT-012 | bundle-scope proposal | local draft covers root, coexistence, inclusion, exclusion, symlink, references, and reserved docs | draft invents repository-wide or resource-limit portable rules | PROC-PROPOSAL-DRAFTS | UpstreamProposalDraft and examples | +| SEIT-027 | AC-007, AC-008 | DES-001, DES-023, CONTRACT-001, CONTRACT-012 | layered-profile proposal | portable floor and additive results remain separate | strict failure is called portable nonconformance | PROC-PROPOSAL-DRAFTS, CMD-PROFILES | proposal and outcome examples | +| SEIT-028 | AC-007 | DES-009, DES-023, CONTRACT-012 | proposal submission gate | recommendation follows portable proof and stable release | plan, local build, or draft authorizes external write | PROC-PROPOSAL-DRAFTS, PROC-PUBLICATION | current evidence and separate owner decision | +| SEIT-029 | AC-001, AC-005, AC-008 | DES-025, CONTRACT-003, CONTRACT-007, CONTRACT-010, CONTRACT-013 | claim-state integrity | state labels match current receipts | plan text or prior run is surfaced as current pass | CMD-ROUTE-TRACE | RouteTrace and claim-lint result | +| SEIT-030 | AC-001, AC-009 | DES-024, DES-025, CONTRACT-013 | canonical artifacts and review | five canonical sources validate and review embeds exact sources | divergent duplicate, missing source, stale review, or prompt dependency remains | CMD-ROUTE-TRACE, PROC-PLAN-CANONICALIZE | artifact digests, links, directory inventory | +| SEIT-031 | AC-001, AC-004 | DES-019, DES-025, CONTRACT-013 | slice schema and assignments | every slice uses supported assignment and required manifest fields | unsupported route, reasoning, overlap, or missing field passes | CMD-ROUTE-TRACE | parsed assignments and slice manifests | +| SEIT-032 | AC-009, AC-010 | DES-024, DES-025, CONTRACT-013 | planning stop | route returns for owner selection without execution | Explorer, Expedition, external write, or removal starts | CMD-ROUTE-TRACE, PROC-PLAN-CANONICALIZE | journey stage and unchanged product/consumer inventory | + +## Requirement Coverage Matrix + +| Requirement | Design/contract | SEIT proof | Command/procedure | Prospective implementation owner | Rollback or N/A | +| --- | --- | --- | --- | --- | --- | +| REQ-GATE-001 | DES-001..003, CONTRACT-001..002 | SEIT-001..003 | CMD-OKF-PORTABLE, CMD-PROFILES | shared conformance slice | revert exact core/fixture write set | +| REQ-GATE-002 | DES-004, CONTRACT-003 | SEIT-004 | CMD-BUDGET, CMD-FAST | shared gate slice | revert registry/test paths together | +| REQ-GATE-003 | DES-005, CONTRACT-003 | SEIT-005 | CMD-PUBLIC, CMD-FAST | public-root slice | restore prior checker bytes | +| REQ-GATE-004 | DES-019, CONTRACT-013 | SEIT-020, SEIT-032 | CMD-ROUTE-TRACE | route/integration gate | N/A, read-only validation | +| REQ-GATE-005 | DES-001..005, CONTRACT-003 | SEIT-006 | shared commands | shared gate slices | revert owning write set | +| REQ-REL-001 | DES-006..008, CONTRACT-004 | SEIT-007..008 | release build/seal commands | release readiness slice | discard unpromoted dist | +| REQ-REL-002 | DES-005, DES-008..009 | SEIT-005, SEIT-008..009 | CMD-PUBLIC, PROC-PUBLICATION | release readiness slice | stop before publication | +| REQ-REL-003 | DES-006..008, CONTRACT-004 | SEIT-008 | CMD-RELEASE-SEAL, CMD-EXACT-SHA | release seal slice | reject identity | +| REQ-REL-004 | DES-010, CONTRACT-005 | SEIT-010 | CMD-INSTALL-VERIFY | each consumer slice | restore prior pin | +| REQ-REL-005 | DES-011, CONTRACT-006 | SEIT-011 | CMD-ROLLBACK | each consumer slice | is the rollback proof | +| REQ-REL-006 | DES-009 | SEIT-009 | PROC-PUBLICATION | publication gate | no side effect before approval | +| REQ-CONS-001 | DES-012, DES-019, CONTRACT-010 | SEIT-013..018 | six PROC-PARITY-* | six consumer slices | per-consumer | +| REQ-CONS-002 | DES-019, CONTRACT-013 | SEIT-020 | CMD-ROUTE-TRACE | route validator | N/A | +| REQ-CONS-003 | DES-013, CONTRACT-007 | SEIT-012 | CMD-CONSUMER-PARITY | parity harness + consumer | read-only corpus | +| REQ-CONS-004 | DES-013..014, CONTRACT-010 | SEIT-012..019 | six PROC-PARITY-* | each consumer | CMD-ROLLBACK | +| REQ-CONS-005 | DES-012, DES-020, CONTRACT-010 | SEIT-021..022 | CMD-REFERENCE-AUDIT | each consumer | restore changed references | +| REQ-CONS-006 | DES-014, DES-021 | SEIT-013..019, SEIT-023 | six procedures, CMD-RETIREMENT-PROOF | gate aggregator | N/A | +| REQ-CONS-007 | DES-012 | SEIT-010, SEIT-013..018 | six PROC-PARITY-* | owner gate per consumer | no write before approval | +| REQ-AZS-001 | DES-015, CONTRACT-008 | SEIT-014 | PROC-PARITY-ALPHAZEDE-SPORTS | Sports slice | restore policy/pin | +| REQ-BETBOT-001 | DES-016, CONTRACT-009 | SEIT-015 | PROC-PARITY-BETBOT | BetBot slice | exact source-byte restore | +| REQ-PARITY-001 | DES-013, DES-017, CONTRACT-007 | SEIT-012, SEIT-019 | CMD-CONSUMER-PARITY | parity harness | read-only; unavailable blocks | +| REQ-HGTS-001 | DES-018, CONTRACT-010 | SEIT-017 | PROC-PARITY-HGTS | HGTS slice | no write while absent | +| REQ-COMPAT-001 | DES-020..021 | SEIT-021, SEIT-023 | CMD-REFERENCE-AUDIT, CMD-RETIREMENT-PROOF | consumers + retirement gate | retained compatibility | +| REQ-COMPAT-002 | DES-010..011, DES-020 | SEIT-010..011, SEIT-021 | install/rollback commands | each consumer | restore prior pin/fallback | +| REQ-RETIRE-001 | DES-021..022, CONTRACT-011 | SEIT-023..025 | PROC-RETIREMENT | final separate slice | restoration archive | +| REQ-RETIRE-002 | DES-022, CONTRACT-011 | SEIT-024..025 | PROC-RETIREMENT | owner-gated retirement | stop before approval | +| REQ-RETIRE-003 | DES-011, DES-022 | SEIT-024 | CMD-RETIREMENT-PROOF | retirement rehearsal | is the proof | +| REQ-UPSTREAM-001 | DES-023, CONTRACT-012 | SEIT-026 | PROC-PROPOSAL-DRAFTS | local proposal slice | N/A, local draft | +| REQ-UPSTREAM-002 | DES-001, DES-023, CONTRACT-012 | SEIT-027 | PROC-PROPOSAL-DRAFTS, CMD-PROFILES | local proposal slice | N/A | +| REQ-UPSTREAM-003 | DES-009, DES-023 | SEIT-028 | proposal/publication procedures | later owner gate | no external write | +| REQ-PLAN-001 | DES-024, CONTRACT-013 | SEIT-030 | CMD-ROUTE-TRACE, PROC-PLAN-CANONICALIZE | Bearing planning route | remove stale alias only after validation | +| REQ-PLAN-002 | DES-025, CONTRACT-013 | SEIT-029..031 | CMD-ROUTE-TRACE | route validator | N/A | +| REQ-PLAN-003 | CONTRACT-003, CONTRACT-013 | SEIT-001..032 | command registry | SEIT/route owner | N/A | +| REQ-PLAN-004 | DES-019, OOPDSA DAG | SEIT-020, SEIT-031 | CMD-ROUTE-TRACE | implementation drafting | N/A | +| REQ-PLAN-005 | DES-024..025 | SEIT-030 | Bearing review generator, CMD-ROUTE-TRACE | Bearing | regenerate, never hand-edit | +| REQ-PLAN-006 | DES-024 | SEIT-030 | PROC-PLAN-CANONICALIZE | planning closeout | preserve canonical; remove stale alias | +| REQ-PLAN-007 | DES-025 | SEIT-032 | CMD-ROUTE-TRACE | planning checkpoint | N/A | + +## Acceptance traceability + +| Acceptance | Required SEIT proof | +| --- | --- | +| AC-001 | SEIT-029..031 plus complete requirement matrix | +| AC-002 | SEIT-001..006 | +| AC-003 | SEIT-007..011 | +| AC-004 | SEIT-012..020 | +| AC-005 | SEIT-014..019 | +| AC-006 | SEIT-021..025 | +| AC-007 | SEIT-026..028 | +| AC-008 | SEIT-003, SEIT-027 | +| AC-009 | SEIT-030..032 | +| AC-010 | SEIT-032 | + +## Cross-cutting Checks + +- **Determinism:** repeat tests with permuted discovery order and compare + semantic identities. +- **Mutation containment:** snapshot every read-only fixture, consumer, and + evidence directory before and after. +- **Path safety:** normalize and root-bind every enumerated or written path; + reject symlink aliases for release assets and escaping consumer targets. +- **Claims:** lint every receipt and review for planned/passed/failed/ + unavailable/rolled_back accuracy. +- **Privacy:** scan source, fixtures, logs, receipts, proposal drafts, and + release assets for forbidden private material. +- **Compatibility:** prove legacy surfaces remain callable and recoverable + until the final barrier. +- **Recovery:** byte/configuration/digest uncertainty is a failed rollback. +- **Concurrency:** compare normalized write sets and dependency DAG before + activating parallel consumer lanes. + +## Optional and unavailable tools + +- Provider or live model evaluation is not required. +- Network access is not required for shared gates or local release sealing. +- Public download verification remains unavailable until owner-approved + publication. +- Consumer CI or retrieval runners that are unavailable remain separately + typed; fixture success cannot replace them. +- HGTS work remains discovery-only while its checkout is absent. + +## Design-and-SEIT checkpoint + +This checkpoint is ready only when: + +1. `design.md` and `seit.md` parse from the canonical directory; +2. all DES, CONTRACT, SEIT, requirement, and acceptance IDs are unique and + traceable; +3. current failures are not presented as passing; +4. no `implementation.md` or hand-edited `review.html` was created; and +5. the receipt does not grant publication, consumer mutation, proposal + submission, compatibility removal, Explorer, or Expedition authority. + +Bearing owns baseline `review.html` generation after this checkpoint. The next +agent must reuse these exact sources, draft only `implementation.md`, and stop +again for deterministic review and owner route selection. + +## 2026-07-23 Slice 2.1 wire-contract clarification + +This section appends the verification procedures and fixture test matrix binding the existing Slice 2.1 command IDs (`CMD-EXACT-SHA`, `CMD-INSTALL-VERIFY`, `CMD-CONSUMER-PARITY`, `CMD-REFERENCE-AUDIT`, `CMD-ROLLBACK`, `CMD-RETIREMENT-PROOF`) to temporary standard-library-only offline fixtures without modifying existing requirements, contracts, slices, paths, or command flags. + +### Fixture-based verification suite for wire contracts + +Each command ID will be validated against temporary standard-library test fixtures to verify positive wire shapes, all required failure modes, and strict mutation containment. + +#### 1. Positive wire shape verification + +- **Consumer gate verification (`CMD-INSTALL-VERIFY`, `CMD-CONSUMER-PARITY`, `CMD-REFERENCE-AUDIT`, `CMD-ROLLBACK`):** Will be verified using complete, fully valid `ConsumerGateReceipt` fixtures across generic consumer test cases (including the six consumers `Alphazedehq`, `alphazede-sports`, `betbot`, `developers`, `hgts`, `alphazede-markets`), proving that valid `ReleaseIdentity`, `InstallSnapshot` (with evidence-backed `staged_path` and `prior_pin`), `ParityReceipt` (nested under authoritative `ReleaseIdentity`, with exact `semantic_rows[].native` and `.legacy` keys), `hook_check`, `reference_audit` (with `expected_compatibility`), and `RollbackReceipt` (with exact `restored_paths` items) structures pass with status `passed` and exit code 0. +- **Six-consumer retirement verification (`CMD-RETIREMENT-PROOF`):** Will be verified using a complete, valid `RetirementManifest` referencing all six passing consumer receipts, valid evidence locator/digest objects for `active_reference_audit` (referencing strict JSON containing matching per-consumer status), `recovery_archive` (referencing a regular non-symlink archive), and `restoration_proof` (referencing strict JSON byte checks and commands), sorted normalized write/deletion path lists, and an `owner_approval_reference`; the fixture must prove successful evaluation without executing apply/post-apply commands and must prove identity-bound freshness. + +#### 2. Negative wire shape and failure mode matrix + +Verification commands will be executed against temporary fixtures containing single structural or semantic defects to confirm deterministic failure (non-zero exit code, typed blocker/diagnostic emission, and no side effects): + +- **Duplicate key failure:** JSON fixture containing duplicate keys within an object (e.g. duplicate top-level keys or duplicate `archives` keys) is rejected. +- **Unknown behavioral key failure:** Objects containing unrecognized behavioral keys fail verification. +- **Bad digest failure:** SHA-256 strings containing invalid length, non-hex characters, uppercase hex, or failing bounded recomputation against actual evidence files cause verification failure. +- **Symlink / path traversal failure:** Evidence locators using absolute paths, empty strings, `.`, `..`, backslashes, or pointing to symlinks or files outside the evidence directory are rejected. +- **Wrong / dirty revision failure:** Receipt or audit revision failing to match the CLI revision argument or current clean git HEAD causes immediate failure. +- **InstallSnapshot evidence locator failure:** `InstallSnapshot` where `staged_path` or `prior_pin` evidence locator bytes do not hash to `selected_digest` or `prior_digest` fails verification. +- **Missing raw parity failure:** `ParityReceipt` missing either `native_raw` or `legacy_raw` evidence locator/digest objects, or where raw evidence is not a UTF-8 JSON array corresponding one-to-one with semantic rows, fails verification. +- **Missing semantic row key failure:** `ParityReceipt` where any `semantic_rows[].native` or `.legacy` object drops required keys (`locator`, `precedence`, `diagnostic_code`, `conflict`, `unavailable`, `outcome`) fails verification. +- **Unavailable parity failure:** `ParityReceipt` containing `unavailable` validation/retrieval status blocks consumer completion and exits with failure status. +- **Reference audit expected compatibility mismatch failure:** `reference_audit` missing a `compatibility-active` match for any object in `expected_compatibility`, or containing a `compatibility-active` match absent from `expected_compatibility`, fails verification. +- **Unexpected / unclassified reference failure:** `reference_audit` containing `unexpected-active` or `unclassified` classifications fails gate verification. +- **RollbackReceipt restored paths failure:** `RollbackReceipt` with `restored_paths` item missing exact keys (`path`, `sha256`, `source`), with invalid `source`, escaping path, or mismatching SHA-256 fails verification. +- **Partial rollback failure:** `RollbackReceipt` with unpassed byte checks, unpassed command execution records, or missing restored paths/digests reports failure. +- **Stale identity failure:** `ReleaseIdentity` mismatch between consumer gate receipt, install snapshot, and selected release manifest causes failure. +- **Retirement referenced evidence failure:** `RetirementManifest` where `active_reference_audit` or `restoration_proof` referenced file is not strict JSON with exact required keys, or where `recovery_archive` is a symlink, fails verification. +- **Missing / five / seven / duplicate consumer failure:** `RetirementManifest` containing fewer than six consumers (e.g. 5), more than six (e.g. 7), missing consumers, or duplicate consumer entries is rejected. +- **Absent approval reference failure:** `RetirementManifest` with an empty or missing `owner_approval_reference` fails verification. + +#### 3. Output determinism and mutation containment + +- **Deterministic stdout:** Command stdout will be verified to be byte-for-byte identical across repeated runs on identical fixture inputs, with output sorted lexically by consumer, path, and semantic key, and with compact canonical JSON digests computed via UTF-8 `json.dumps(value, sort_keys=True, separators=(",", ":"), ensure_ascii=False)`. +- **Before/after directory snapshots:** Pre-run and post-run file system tree and hash snapshots will verify that read-only commands (`install-verify`, `parity`, `reference-audit`, `rollback`, and retirement `verify`) perform zero writes, zero file creations, zero deletions, and zero mutations on the target repository or evidence directory. diff --git a/docs/submissions/bran-build-week/README.md b/docs/submissions/bran-build-week/README.md new file mode 100644 index 0000000..4ca5bfd --- /dev/null +++ b/docs/submissions/bran-build-week/README.md @@ -0,0 +1,237 @@ +--- +type: submission-package +title: BRAN Build Week Private Submission Package +okf_status: draft +status: draft +tags: + - internal + - bran +freshness: "2026-07-24" +resource: https://github.com/alphazede/bran-dev +public_boundary: private +--- + +# BRAN Build Week Private Submission Package + +This private package contains submission copy and measured local evidence. It +is not publication, release, benchmark-upload, or submission authorization. +Nothing here may be copied into BRAN's public source tree without an explicit +public-boundary scrub, claim review, and owner approval. + +Canonical artifacts: + +- [demo-video-outline.md](./demo-video-outline.md) +- [demo-recording-runbook.md](./demo-recording-runbook.md) +- [research-paper.md](./research-paper.md) +- [submission-checklist.md](./submission-checklist.md) +- [customer-setup/README.md](./customer-setup/README.md) +- [controlled Arena evidence](./evidence/arena-matrix-20260720.json) +- [post-review connected smoke evidence](./evidence/connected-smoke-20260720.json) +- [provider-free Obsidian evidence](./evidence/obsidian-core-20260720.json) +- [Understand Anything supply-chain evidence](./evidence/ua-supply-chain-20260720.json) + +## Submission position + +- **Entered category:** Developer Tools. +- **Supporting narrative:** Work & Productivity examples can demonstrate the + same evidence-routing engine without changing the entered category. +- **Core promise:** BRAN gives an agent or developer bounded, + provenance-bearing repository evidence before action. +- **Attribution:** The agent using BRAN performs the review, diagnosis, plan, + explanation, or owner-authorized repair. BRAN supplies evidence and receipts. + +The category references below come from the approved plan's pin of the +[Build Week overview](https://openai.devpost.com/) and +[official rules](https://openai.devpost.com/rules), rechecked on 2026-07-18. +The owner must read back the live rules immediately before submission. + +## Final Devpost copy + +**Title:** BRAN + +**Tagline:** Bounded repository evidence for agents and developers. + +**Public repository:** +[alphazede/developers/bran](https://github.com/alphazede/developers/tree/main/bran) + +**Description:** + +BRAN is a local repository-intelligence engine that helps an agent or developer +find bounded, provenance-rich evidence before acting. Its deterministic Rust +core can scan, query, validate, and build focused context packets without an +LLM or provider account. A connected inner agent can synthesize a grounded +answer when explicitly configured. SQZ response processing, voice, and saved +history remain explicit capabilities; unavailable behavior is never simulated. + +The product surface includes a headless CLI, terminal onboarding, named agent +profiles, requested-versus-effective receipts, release-readiness checks, a +public `use-bran` skill, deterministic Obsidian export, and an isolated Arena +protocol. A connected-task total-token ceiling is unset unless the user +configures `tokens=N`. The independent 65,536-byte connected-answer limit is a +byte-safety bound, not a token ceiling. + +On our controlled 512-file benchmark, all 20 eligible agents found the intended +retry-queue bug and correct account-scoped fix. Each heterogeneous condition +has `n=1`. Plain was descriptively fastest and lowest-token on this easy task; +BRAN Core selected broader evidence, while connected use added provider work +and exposed receipt and grounding failures. These results are a transparent +baseline, not a universal claim that BRAN improves speed, cost, or correctness. + +## Claim policy + +Use this form for any measured statement: + +> On our controlled benchmark (`n=`), the agent using BRAN +> `` while ``. +> `` was ``. + +Required qualifications: + +- Say “on our controlled benchmark,” never “for every repository.” +- State `n=1` for each heterogeneous matrix cell. +- Use provider input plus output for actual tokens. Cached input and reasoning + output are subsets and must not be added again. +- Label Core packet bytes divided by four as an estimate, never provider use. +- Report initialization/indexing separately when measured; otherwise report it + as `unavailable`. +- Retain failed and invalidated runs and explain exclusions. +- Report dollar spend as `unavailable` until provider cost evidence exists. +- Attribute completed work to the agent using BRAN. +- Keep Understand Anything as an unexecuted category reference. + +Prohibited claims include “eliminates hallucinations,” “always faster,” “uses +fewer tokens than every competitor,” “beats Understand Anything,” universal +cost savings, hidden failed runs, or automatic document repair when an agent +performed the repair. + +## Controlled Arena comparison + +Exact evidence scope: + +- BRAN: `33e86f9ef36bf71130013bcbdcb4e3ad37d150d7` +- Arena: `ecc39c83275c0d5930a60a3841c9b9514379c415` +- Corpus: + `cb4fab25ecc7dfa132b65608608afb6fa2245e8f3248a1a7f2a1f3752aa7d6d5` +- Private aggregate SHA-256: + `38317b314c0eb31532590c882571c2c463b35873bc6f8244ad74e4ceefd49a1c` +- Population: 20/20 eligible corrected trials, `n=1` per heterogeneous cell +- Matrix: four plain, four Core, twelve connected +- Outer conditions: Sol Medium/XHigh and Terra Medium/XHigh +- Connected inner conditions: Luna Low/Medium and Spark Medium +- SQZ: off in this comparison + +The full corrected corpus passed `okf-v0.1` before dispatch. Plain saw no +skills; BRAN arms saw only `use-bran`. Every arm used a fresh isolated corpus +copy with neutral `AGENTS.md` and `CLAUDE.md` instructions. + +| Arm | Cells | Median wall time | Median actual tokens | Median tools | Median failed tools | Correct | Material errors | Failed conditions | +|---|---:|---:|---:|---:|---:|---:|---:|---:| +| Plain | 4 | 47.030 s | 72,589 | 5.5 | 2 | 4/4 | 0 | 0 | +| BRAN Core | 4 | 118.060 s | 195,941 | 12 | 4 | 4/4 | 0 | 0 | +| BRAN connected | 12 | 108.975 s | 208,050 | 15.5 | 4 | 12/12 | 4 | 5 | + +The medians summarize heterogeneous one-trial cells and are descriptive only. +Wall duration is the recorded end-to-end outer candidate duration; +initialization and indexing were not separately itemized. Dollar spend is +`unavailable`. + +Plain and connected median direct-path precision and recall were 1.0. Core +packet-locator recall was 1.0 and precision was 0.065217, showing that it found +all required evidence but admitted a broader packet. Connected execution had +nine complete receipts, seven clean results, three grounding failures, four +material reporting/protocol errors, and five failed-condition cells. All final +defect answers still passed the correctness gate. + +The earlier population with corpus digest `f11a1ff6...` failed the repository +OKF precondition because the simulated instruction files lacked required +metadata. Its 21 runs remain preserved but are classified +`invalid_precondition_okf_repository_fail` and contribute no metrics. + +See the [research paper](./research-paper.md) and +[sealed private aggregate](./evidence/arena-matrix-20260720.json) for definitions +and artifact hashes. + +## Post-review connected compatibility smoke + +A separate real CLI smoke exercised BRAN +`36574d01c7c6acad9fb97e09d3aad2c7cf683122` with Arena +`83253293a08380aeddb16874616e90cd21d2a081`. Spark Medium, running inside BRAN +with read/search only, produced the correct bug, fix, and test answer in 15.41 +seconds. BRAN accepted all eight citations as exact packet locators. Provider +telemetry recorded 68,555 input and 5,652 output tokens, or 74,207 total; cached +input and reasoning output are included subsets, not additions. This is one +post-review compatibility smoke (`n=1`), not a matrix row or benchmark win. + +The evidence also preserves a 0.06-second permissions preflight failure before +provider invocation and an earlier provider attempt that failed exact citation +validation before telemetry publication. See the +[scrubbed smoke record](./evidence/connected-smoke-20260720.json). + +## Fixture and provider boundaries + +| Evidence | Classification | Allowed statement | +|---|---|---| +| Corrected provider matrix | `measured_limited` | On our controlled benchmark, every agent found the bug; report all descriptive costs and failures with `n=1`. | +| Post-review connected smoke | `measured_compatibility_n1` | Spark using BRAN produced a grounded answer at the reviewed revisions; do not add it to the frozen matrix. | +| Core packet bytes divided by four | `estimated_fixture_only` | A labeled packet-size estimate; never actual provider tokens. | +| Obsidian core export | `measured_provider_free` | Deterministic export tests passed without an agent or LLM. No GUI/native-plugin claim. | +| Understand Anything | `blocked_category_reference` | Download and supply-chain scan only; no installation, execution, or performance comparison. | +| Dollar spend | `unavailable` | No currency or cost-savings claim. | +| Hosted CI | `unavailable_not_run` | Exact local commits were not pushed, and Arena has no remote; do not infer pass status from local gates. | +| Signed multi-platform release | `unavailable` | Local revisions are not a public release. | + +The Obsidian evidence verifies export behavior, not a competing retrieval +system. The Understand Anything pin remains blocked because its supply-chain +scan found unresolved Critical/High issues; the security policy must not be +bypassed. + +## Customer and judge setup + +Use [customer-setup/README.md](./customer-setup/README.md) for the local CLI/TUI +walkthrough and the public repository's +[`bran/docs/integrations/agent-setup.md`](https://github.com/alphazede/developers/blob/main/bran/docs/integrations/agent-setup.md) +for canonical recipes. Use only an exact owner-authorized release for the final +judge rehearsal. + +## Security and public-boundary notes + +- BRAN Core works without provider authentication or network initialization. +- Credentials remain in the reviewed agent host; BRAN has no credential CLI + flag. +- Receipts distinguish requested from effective model, reasoning, tools, SQZ, + token policy, and retention settings. +- Public source must exclude private corpora, owner paths, auth/state, raw + provider traces, run identifiers, and private submission copy. +- No private Devpost or model-specific copy belongs in the public BRAN tree. +- No sealed multi-platform release, trusted signature, stable internal + promotion, or hosted-CI result is claimed here. + +## Screenshot and asset shot list + +| Shot | Source | State | +|---|---|---| +| Repository hero | [`bran/assets/brand/bran-repository-raven.png`](https://github.com/alphazede/developers/blob/main/bran/assets/brand/bran-repository-raven.png) | Present; avatar candidate only | +| TUI hero | Public `bran/assets/tui/` raven assets | Present; capture exact release | +| Onboarding | Advanced readiness review | Capture after final exact-release QA | +| Headless receipt | Query/packet provenance and failures | Capture exact release; scrub local paths | +| Benchmark card | Controlled table above | Private copy ready; public scrub required | +| Release proof | Checksums, signatures, supported assets | `unavailable` until owner-authorized release | + +Do not create staged or synthetic screenshots. Do not mutate the GitHub avatar +without separate owner authorization. + +## External owner actions + +1. Supply macOS x86_64/arm64 and Windows MSVC build environments, trusted + signing authority, and exact tag/release authorization. +2. Approve a clean no-build judge rehearsal, final screenshots, and timed video + after the exact release exists. +3. Verify the eligible `/feedback` identifier and read the live rules/deadline. +4. Separately authorize repository/video publication, Devpost submission, + stable internal installation or promotion, and any GitHub avatar mutation. +5. Clear a future Understand Anything pin through supply-chain policy before + any category-reference installation or execution. + +See [submission-checklist.md](./submission-checklist.md) for the final launch +sequence. This package generation performed no external submission, +publication, upload, release, deployment, purchase, or avatar mutation. diff --git a/docs/submissions/bran-build-week/customer-setup/README.md b/docs/submissions/bran-build-week/customer-setup/README.md new file mode 100644 index 0000000..1f4be40 --- /dev/null +++ b/docs/submissions/bran-build-week/customer-setup/README.md @@ -0,0 +1,199 @@ +--- +type: customer-setup +title: Customer and judge walkthrough +okf_status: draft +status: draft +tags: + - internal + - bran +freshness: "2026-07-24" +resource: https://github.com/alphazede/bran-dev +public_boundary: private +--- + +# Customer and judge walkthrough + +This is the private rehearsal guide. Use the public canonical +[`bran/docs/integrations/agent-setup.md`](https://github.com/alphazede/developers/blob/main/bran/docs/integrations/agent-setup.md) +for supported recipes. Local tests do not replace an exact signed release or a +clean judge-machine rehearsal. + +## First-run onboarding + +Start the terminal interface: + +```sh +bran tui +``` + +Quick and Advanced flows expose environment checks, optional agent connection, +profile/model/reasoning choices, BRAN mode, SQZ, voice, retention, readiness, +practice run, and repair mode. Review requested and effective settings before +applying them. Offline, read-only operation with zero-conversation retention is +the safe baseline; missing capabilities remain `unavailable`. + +Then run: + +```sh +bran doctor --onboarding +``` + +Check `ready`, `settings_status`, requested/effective capability states, and the +offline-return proof. The diagnostic should record zero provider, auth, and +network calls. + +## Offline BRAN Core + +Deterministic Core needs no agent or provider account: + +```sh +bran packet "" +bran query "" +``` + +Preserve locators and provenance. Any bytes-divided-by-four token field is an +estimate, not provider usage. + +## Install the agent skill + +Copy the public `skill/use-bran` directory into the external agent host's skill +directory. If that host uses a nonstandard path, set `BRAN_SKILL_PATH` to the +copied `SKILL.md` only for doctor discovery. BRAN reports discovery; it does not +modify global agent configuration. + +Credentials stay in the reviewed host credential store or documented +environment input. BRAN accepts no credential CLI flag and must not echo secret +material. + +## Optional connected agent + +Enable Connected Agent in the TUI, configure the reviewed host adapter, and +inspect profiles and readiness: + +```sh +bran agents list +bran doctor --agent +``` + +Agent doctor validates local CLI and skill discovery, workspace policy, SQZ +capability, a deterministic packet round trip, and host attestation. It does not +contact a provider merely to probe capability. Local setup may pass while +connected execution remains `unavailable`; the command must not claim overall +readiness without effective host attestation. + +A connected-task total-token ceiling is unset unless the user explicitly +configures `tokens=N`. When set, it remains requested until the host attests +enforcement. Leaving it unset does not block connected execution and does not +claim token enforcement. The separate 65,536-byte connected-answer bound is an +independent byte-safety limit. + +Reasoning accepts `off|minimal|low|medium|high|xhigh`; task tools are limited to +`read,search`: + +```sh +bran -p --trust-current-root --agent --reasoning medium --tools read,search "review this change" +bran -p --trust-current-root --agent --reasoning low --no-session "find the owning specification" +``` + +Read the complete receipt. Requested and effective profile, model, reasoning, +tools, SQZ, session, and token-policy fields are distinct. Unattested effective +values stay `unavailable`. `--no-session` requests no conversation session; +bounded result artifacts remain governed by their own retention rules. + +Retrieve an explicitly retained result before its TTL expires: + +```sh +bran get +``` + +## Controlled Arena evidence + +The completed comparison is exact to BRAN +`33e86f9ef36bf71130013bcbdcb4e3ad37d150d7`, Arena +`ecc39c83275c0d5930a60a3841c9b9514379c415`, and corrected 512-file corpus +`cb4fab25ecc7dfa132b65608608afb6fa2245e8f3248a1a7f2a1f3752aa7d6d5`. +The full corpus passed `okf-v0.1` before dispatch. + +Each heterogeneous cell has `n=1`: four plain, four BRAN Core, and twelve BRAN +connected cells. Outer agents were Sol Medium/XHigh and Terra Medium/XHigh; +connected inner agents were Luna Low/Medium and Spark Medium. Every agent found +the missing-`account_id` retry-key defect and correct fix. SQZ was off in every +cell, so this matrix does not evaluate SQZ. + +| Arm | Cells | Median wall time | Median actual tokens | Median tools | Median failed tools | Correct | +|---|---:|---:|---:|---:|---:|---:| +| Plain | 4 | 47.030 s | 72,589 | 5.5 | 2 | 4/4 | +| BRAN Core | 4 | 118.060 s | 195,941 | 12 | 4 | 4/4 | +| BRAN connected | 12 | 108.975 s | 208,050 | 15.5 | 4 | 12/12 | + +On our controlled benchmark, plain was descriptively fastest and lowest-token +on this easy task. Core recovered all target evidence but selected a broader +packet. Connected execution added provider work and recorded four material +reporting/protocol errors, five failed-condition cells, and three grounding +failures. These are heterogeneous single-cell descriptions, not universal +performance claims. + +Actual provider totals are input plus output. Cached input and reasoning output +are subsets and are not added again; connected totals add outer and inner +provider totals once. Core packet bytes divided by four remain estimates and +are excluded from actual totals. Dollar spend is `unavailable`. + +The recorded end-to-end wall time includes the candidate execution path, but +initialization and indexing are not separately itemized and are therefore +`unavailable`. The earlier `f11a1ff6...` corpus runs failed the repository OKF +precondition and are preserved but excluded. + +See [arena-matrix-20260720.json](../evidence/arena-matrix-20260720.json) and the +[research paper](../research-paper.md). + +## Post-review connected smoke + +One real CLI compatibility smoke exercised BRAN +`36574d01c7c6acad9fb97e09d3aad2c7cf683122` with Arena +`83253293a08380aeddb16874616e90cd21d2a081`: + +```sh +bran -p --trust-current-root --agent spark-medium --reasoning medium --tools read,search --no-session "Investigate why events from different accounts sometimes collapse in the retry queue. Explain the bug, the fix, and how to test it." +``` + +Spark using BRAN produced the correct answer, and BRAN validated eight exact +packet citations. The run took 15.41 seconds and recorded 74,207 actual +provider tokens. It used no token ceiling; the independent answer limit was +65,536 bytes. Treat this as `n=1` compatibility evidence, not a new matrix row +or a performance claim. The scrubbed record also preserves the preflight and +citation-validation failures that preceded the successful run. See +[connected-smoke-20260720.json](../evidence/connected-smoke-20260720.json). + +## Obsidian export + +BRAN Core's provider-free Obsidian export test passed deterministic frontmatter, +wikilink, graph-edge, reparse, property-preservation, and unsafe-link rejection +checks. No provider or agent was used. No Obsidian GUI or native plugin was +tested, and Obsidian is an export surface rather than a benchmark competitor. +See [obsidian-core-20260720.json](../evidence/obsidian-core-20260720.json). + +## Voice and saved history + +Voice and saved-history behavior must reflect actual installation and policy. +If unavailable, leave them off and display `unavailable`; do not simulate them. + +## Return to offline mode + +Disable Connected Agent in the TUI or verify the boundary directly: + +```sh +bran -p --agent --offline --no-session "offline return proof" +bran packet "" +``` + +The first command returns a typed incomplete offline receipt rather than a +generated answer. The following packet remains deterministic and must not +initialize provider, auth, or network paths. + +## Judge path + +Use only an exact owner-authorized release. Rehearse onboarding, Core retrieval, +optional connected execution, receipt reading, result retrieval, and offline +return on a clean machine. Show every `unavailable` field plainly. Do not claim +signed multi-platform availability, hosted CI, provider spend, GUI evidence, or +publication until the corresponding owner-controlled evidence exists. diff --git a/docs/submissions/bran-build-week/demo-recording-runbook.md b/docs/submissions/bran-build-week/demo-recording-runbook.md new file mode 100644 index 0000000..43e3f92 --- /dev/null +++ b/docs/submissions/bran-build-week/demo-recording-runbook.md @@ -0,0 +1,124 @@ +--- +type: submission-artifact +title: BRAN Immediate Demo Recording Runbook +okf_status: draft +status: draft +tags: + - internal + - bran +freshness: "2026-07-24" +resource: https://github.com/alphazede/bran-dev +public_boundary: private +--- + +# BRAN Immediate Demo Recording Runbook + +This is the shortest honest product demo. It does not show or claim a model +comparison. Record locally only after the clean rehearsal; publishing or +uploading requires separate owner authorization. + +## Before recording + +- Use post-native-review BRAN revision + `36574d01c7c6acad9fb97e09d3aad2c7cf683122` for the local rehearsal. For the + final judge video, replace it only with the exact owner-authorized tag and + verify its manifest, checksum, trusted signature, and platform archive. +- Install the authorized exact tag with: + + ```sh + cargo install --git https://github.com/alphazede/developers --tag bran-vX.Y.Z --locked bran-cli + ``` + +- Use a public-safe 512-file sample that passes the full OKF repository check. + Do not reuse private provider traces or expose a local owner path. +- Resize the terminal and scrub repository roots, auth material, run IDs, and + private corpus content from every frame. +- Have the public repository and raven hero ready: + [alphazede/developers/bran](https://github.com/alphazede/developers/tree/main/bran) + and + [`bran-repository-raven.png`](https://github.com/alphazede/developers/blob/main/bran/assets/brand/bran-repository-raven.png). + +## 2:30 recording + +### 0:00-0:20 — problem + +Narrate: “Large workspaces make agents spend context on discovery before they +can solve the task. BRAN is a local Rust evidence router that works without a +model and gives an agent a bounded, attributed context packet.” + +### 0:20-0:45 — TUI + +Run `bran tui`. Show Quick, Advanced, environment checks, optional agent +connection, readiness review, and the practice path. Do not enable or imply +connected synthesis, SQZ, voice, retained history, or repair behavior unless +the exact release labels it configured and the rehearsal proves it. + +### 0:45-1:20 — query + +Run: + +```text +bran query "Locate the misleading-symptom retry bug source and its visible validation evidence." +``` + +Point to the returned paths, `why_selected`, provenance, candidate bytes, +selected bytes, avoided bytes, and any explicit `unavailable` telemetry. + +### 1:20-1:55 — packet + +Run the same request through: + +```text +bran packet "Locate the misleading-symptom retry bug source and its visible validation evidence." +``` + +Narrate: “The packet is what a configured agent reads. BRAN finds and accounts +for evidence; the agent using BRAN performs the diagnosis, explanation, or +owner-authorized repair.” + +### 1:55-2:15 — exact-release local evidence + +Show only the deterministic card reproduced against the exact recording +revision. Label byte-derived token values as estimates, provider tokens as +actual only when provider telemetry exists, and absent telemetry as +`unavailable`. Do not show the controlled model-comparison table in the video. + +### 2:15-2:30 — close + +Narrate: “BRAN Core is model-agnostic and offline. Connected agents, SQZ, +Obsidian export, voice, and retained history are explicit configuration +choices.” Show the exact tag, checksums, public repository, and install command. + +## Recording acceptance + +- Total duration is below three minutes and includes audio. +- The timed video contains no plain/Core/connected comparison, universal win, + competitor claim, or automatic-repair claim. +- Every shown behavior and number was reproduced against the exact recording + revision; estimates and unavailable fields are labeled. +- No personal path, auth/state, private corpus, raw provider trace, fabricated + screenshot, unavailable feature, or private model/Devpost copy appears. +- BRAN’s final local full gate is green with 20 tests. Arena’s final local full + gate is green at revision `83253293a08380aeddb16874616e90cd21d2a081` + with 374 pytest tests in 57.49 seconds, Ruff, strict Mypy over 50 files, and + Bandit exit 0 with warnings only. These are local results; hosted CI was not + run because the exact local commits were not pushed and Arena has no remote. +- The owner approves the final screenshots, recording, upload, repository + publication, and Devpost submission. This runbook grants none of those + external actions. + +## Research reference outside the video + +The completed comparison remains private in the +[research paper](./research-paper.md) and +[sealed evidence](./evidence/arena-matrix-20260720.json). It evaluated BRAN +`33e86f9ef36bf71130013bcbdcb4e3ad37d150d7` and Arena +`ecc39c83275c0d5930a60a3841c9b9514379c415`; do not relabel it as evidence for +the later reviewed revisions used by the recording rehearsal. + +The separate [connected smoke](./evidence/connected-smoke-20260720.json) +records `n=1` post-review compatibility at BRAN +`36574d01c7c6acad9fb97e09d3aad2c7cf683122` and Arena +`83253293a08380aeddb16874616e90cd21d2a081`. Spark using BRAN produced the +correct grounded answer, but this smoke is neither a matrix row nor a demo +comparison claim. diff --git a/docs/submissions/bran-build-week/demo-video-outline.md b/docs/submissions/bran-build-week/demo-video-outline.md new file mode 100644 index 0000000..33e9e84 --- /dev/null +++ b/docs/submissions/bran-build-week/demo-video-outline.md @@ -0,0 +1,116 @@ +--- +type: submission-artifact +title: BRAN Build Week Demo Video Outline +okf_status: draft +status: draft +tags: + - internal + - bran +freshness: "2026-07-24" +resource: https://github.com/alphazede/bran-dev +public_boundary: private +--- + +# BRAN Build Week Demo Video Outline + +Private HQ submission artifact. The timed demo shows BRAN product behavior and +contains no model comparison. Comparative research remains in the evidence +appendix and research paper. + +## Target: 2:45 + +Record from an exact owner-authorized release with audio and stop before 3:00. +Use only behavior reproduced during the clean judge rehearsal. + +| Time | Visual | Narration and proof | +|---|---|---| +| `0:00-0:15` | A large repository with conflicting evidence | Explain that agents spend context on discovery before solving a task. | +| `0:15-0:35` | Public repository and raven hero | Introduce BRAN as a local Rust evidence router. State the build-period extension and required build-tool/model attribution in private submission copy only. | +| `0:35-1:05` | `bran tui` Quick and Advanced flows | Show environment checks, optional agent connection, profile/model/reasoning, BRAN mode, SQZ, voice, retention, readiness review, practice run, and repair mode. Unconfigured features must visibly remain unavailable or off. | +| `1:05-1:35` | Offline `bran query` and `bran packet` on the public-safe sample | Show the correct evidence paths, `why_selected`, provenance, candidate/selected bytes, warnings, and stable machine-readable fields. Do not call the packet an LLM answer. | +| `1:35-1:55` | Optional connected receipt or offline boundary | If rehearsed, show that a configured agent reads the packet and authors the response. Otherwise show the typed offline/unavailable result. Never imply BRAN silently repairs files. | +| `1:55-2:20` | Reproducible Core evidence card | Show only deterministic, exact-release measurements and label estimates and unavailable telemetry. Do not show the plain/Core/connected comparison. | +| `2:20-2:35` | Offline architecture and public/private boundary | Explain that Core works without an LLM; connected synthesis, SQZ, Obsidian export, voice, and history are explicit choices. | +| `2:35-2:45` | Exact tag, checksums, install command, public repository | Close with a measured local claim and invite judges to reproduce it without rebuilding. | + +## Judge walkthrough + +1. Verify the public repository, dual license, exact tag, release manifest, + checksums, trusted signature, and supported platform archive. +2. Install the exact tag: + + ```sh + cargo install --git https://github.com/alphazede/developers --tag bran-vX.Y.Z --locked bran-cli + ``` + +3. Run `bran tui`, choose Quick, inspect Advanced, and read back every requested + versus effective or unavailable setting. +4. On the bundled public-safe sample, run: + + ```sh + bran query "Locate the misleading-symptom retry bug source and its visible validation evidence." + bran packet "Locate the misleading-symptom retry bug source and its visible validation evidence." + ``` + +5. Point to selected sources, provenance, bytes, warnings, and unavailable + fields. Attribute any diagnosis or proposal to the configured agent using + BRAN. +6. Demonstrate explicit-authority repair and its receipt only if the final + rehearsal proves that exact path; otherwise omit it. +7. Confirm offline return behavior, then remove the sample installation using + the public documentation. + +## Evidence appendix — not part of the timed demo + +The completed controlled comparison is exact to BRAN +`33e86f9ef36bf71130013bcbdcb4e3ad37d150d7`, Arena +`ecc39c83275c0d5930a60a3841c9b9514379c415`, and corrected 512-file corpus +`cb4fab25ecc7dfa132b65608608afb6fa2245e8f3248a1a7f2a1f3752aa7d6d5`. +It is not evidence about the later reviewed code. + +| Arm | Cells | Median wall time | Median actual tokens | Correct | Material errors | Failed conditions | +|---|---:|---:|---:|---:|---:|---:| +| Plain | 4 | 47.030 s | 72,589 | 4/4 | 0 | 0 | +| BRAN Core | 4 | 118.060 s | 195,941 | 4/4 | 0 | 0 | +| BRAN connected | 12 | 108.975 s | 208,050 | 12/12 | 4 | 5 | + +Each heterogeneous cell has `n=1`; medians are descriptive. On our controlled +benchmark, every eligible agent found the intended bug and account-scoped fix, +but plain was descriptively fastest and lowest-token on this easy task. See the +[research paper](./research-paper.md) and +[private aggregate](./evidence/arena-matrix-20260720.json). Dollar spend and +separately itemized initialization/indexing time are `unavailable`. + +Post-native-review integrated revisions are BRAN +`36574d01c7c6acad9fb97e09d3aad2c7cf683122` and Arena +`83253293a08380aeddb16874616e90cd21d2a081`. Their final local full gates +passed: BRAN completed its 20-test inventory within the 25-test cap; Arena +completed 374 pytest tests in 57.49 seconds, Ruff, strict Mypy over 50 files, +and Bandit with warnings only and exit 0. Hosted CI was not run because the +exact local commits were not pushed and Arena has no remote. A signed release +also remains `unavailable`. + +A separate post-review connected smoke at those revisions passed in 15.41 +seconds: Spark using BRAN produced the correct bug/fix/test answer with 74,207 +actual provider tokens and eight exact packet citations accepted by BRAN. It is +`n=1` compatibility evidence, not a matrix row or material for the timed demo. +The [scrubbed record](./evidence/connected-smoke-20260720.json) preserves the +preceding preflight and citation-validation failures. + +Understand Anything was downloaded and scanned only. It was not installed or +executed because the pinned supply-chain record contains unresolved +Critical/High findings. Obsidian evidence covers deterministic provider-free +export, not a competing retrieval system or native plugin. + +## Recording assets and gates + +- Public repository: + [alphazede/developers/bran](https://github.com/alphazede/developers/tree/main/bran) +- Repository hero: + [`bran/assets/brand/bran-repository-raven.png`](https://github.com/alphazede/developers/blob/main/bran/assets/brand/bran-repository-raven.png) +- TUI raven sources: public `bran/assets/tui/` +- Capture only real exact-release TUI, onboarding, headless receipt, checksum, + signature, and manifest screenshots; scrub personal paths and private data. +- The owner must authorize the exact tag/release, final recording, screenshots, + upload, repository publication, and Devpost submission. No avatar change is + implied by the present raven asset. diff --git a/docs/submissions/bran-build-week/evidence/arena-matrix-20260720.json b/docs/submissions/bran-build-week/evidence/arena-matrix-20260720.json new file mode 100644 index 0000000..d2915c0 --- /dev/null +++ b/docs/submissions/bran-build-week/evidence/arena-matrix-20260720.json @@ -0,0 +1,165 @@ +{ + "schema_version": 1, + "evidence_id": "arena-matrix-20260720", + "visibility": "private_submission_evidence", + "source_generated_at_utc": "2026-07-20T14:24:42Z", + "aggregate_classification": "controlled_arena_n1_descriptive", + "claim_scope": "on this controlled 512-file Arena corpus at the exact revisions above", + "revisions": { + "arena": "ecc39c83275c0d5930a60a3841c9b9514379c415", + "bran": "33e86f9ef36bf71130013bcbdcb4e3ad37d150d7", + "corpus_sha256": "cb4fab25ecc7dfa132b65608608afb6fa2245e8f3248a1a7f2a1f3752aa7d6d5" + }, + "source_artifacts": { + "aggregate": { + "filename": "final-matrix-aggregate-okf2.json", + "sha256": "de3059b27e516a6894ff7a11850fc2d79bb76c491ac78ac7ae1d6cb00cdc5508" + }, + "comparison": { + "filename": "final-matrix-comparison-okf2.md", + "sha256": "cc90396c82b56ee5c944a22d60b33f39ab5bb4ff9e024b27132c93b87d78d2be" + }, + "invalid_ledger": { + "filename": "invalidated-f11a-corpus-runs.json", + "sha256": "763b75c0240e796ef1ffea171452ed325284ff4f525479af605c98d205553ab6" + } + }, + "preconditions": { + "full_okf_v0_1_repository_check": "passed", + "provider_free_self_test": "self-test-okf-cb4fab25-001:exit_0" + }, + "population": { + "eligible_corrected_trials": 20, + "expected_trials": 20, + "sample_count_per_cell": 1, + "invalidated_prior_corpus_trials_included": 0, + "sample_size_label": "n=1 per heterogeneous condition" + }, + "provenance_classes": { + "measured": { + "fields": [ + "wall_duration_median_ms", + "tool_calls_median", + "failed_tool_calls_median", + "numeric_source_precision_median", + "numeric_source_recall_median", + "cell outcome counts" + ], + "scope": "descriptive summaries from corrected single-cell trials" + }, + "actual": { + "field": "actual_comparison_tokens_median", + "basis": "Provider telemetry from outer JSONL and, for connected arms, inner adapter telemetry. Cached input and reasoning output are subsets and are never added twice." + }, + "estimated": { + "field": "core_packet_tokens", + "basis": "BRAN Core packet token figures are bytes-divided-by-four estimates and are retained only in per-trial summaries; they are not used as model-token totals.", + "included_in_actual_token_totals": false + }, + "unavailable": { + "field": "dollar_spend", + "value": "unavailable" + }, + "invalid": { + "corpus_sha256": "f11a1ff6ebbd0e798766782d6f7d5689534030a1d12246559266c4a4a6517ffa", + "classification": "invalid_precondition_okf_repository_fail", + "included_in_metrics": false, + "excluded_from_final_comparison": true + } + }, + "descriptive_by_arm": [ + { + "arm": "connected", + "heterogeneous_single_cells": 12, + "n_per_cell": 1, + "wall_duration_median_ms": 108975, + "actual_comparison_tokens_median": 208050, + "tool_calls_median": 15.5, + "failed_tool_calls_median": 4, + "numeric_source_precision_median": 1, + "numeric_source_recall_median": 1, + "target_correct_cells": 12, + "final_answer_correct_cells": 12, + "material_error_cells": 4, + "failed_condition_cells": 5, + "connected_receipt_complete_cells": 9, + "clean_connected_result_cells": 7, + "grounding_failed_cells": 3 + }, + { + "arm": "core", + "heterogeneous_single_cells": 4, + "n_per_cell": 1, + "wall_duration_median_ms": 118060, + "actual_comparison_tokens_median": 195941, + "tool_calls_median": 12, + "failed_tool_calls_median": 4, + "numeric_source_precision_median": 0.06521739130434782, + "numeric_source_recall_median": 1, + "target_correct_cells": 4, + "final_answer_correct_cells": 4, + "material_error_cells": 0, + "failed_condition_cells": 0, + "connected_receipt_complete_cells": 0, + "clean_connected_result_cells": 0, + "grounding_failed_cells": 0 + }, + { + "arm": "plain", + "heterogeneous_single_cells": 4, + "n_per_cell": 1, + "wall_duration_median_ms": 47030, + "actual_comparison_tokens_median": 72589, + "tool_calls_median": 5.5, + "failed_tool_calls_median": 2, + "numeric_source_precision_median": 1, + "numeric_source_recall_median": 1, + "target_correct_cells": 4, + "final_answer_correct_cells": 4, + "material_error_cells": 0, + "failed_condition_cells": 0, + "connected_receipt_complete_cells": 0, + "clean_connected_result_cells": 0, + "grounding_failed_cells": 0 + } + ], + "evidence_labels": { + "sample_size": "n=1 per heterogeneous condition", + "medians": "descriptive summaries across heterogeneous single cells, not statistical claims", + "source_precision": "Plain and connected precision is direct target evidence-path precision. Core precision is BRAN packet locator precision. Opaque connected citation IDs are not converted into path precision." + }, + "invalidated_prior_evidence": { + "recorded_at_utc": "2026-07-20T14:03:44Z", + "corpus_sha256": "f11a1ff6ebbd0e798766782d6f7d5689534030a1d12246559266c4a4a6517ffa", + "classification": "invalid_precondition_okf_repository_fail", + "excluded_from_final_comparison": true, + "precondition": { + "check_profile": "okf-v0.1", + "status": "failed", + "failures": [ + { + "path": "AGENTS.md", + "field": "type", + "problem": "missing" + }, + { + "path": "CLAUDE.md", + "field": "type", + "problem": "missing" + } + ] + }, + "handling": { + "raw_evidence_preserved": true, + "existing_trial_summary_seals_preserved": true, + "sealed_summaries_mutated": false, + "provider_results_eligible_as_final": false + }, + "run_count": 21, + "notes": [ + "This ledger supersedes final-use eligibility, not the historical raw evidence.", + "All listed runs used the invalid frozen corpus and must not contribute to final benchmark claims or aggregate metrics.", + "A corrected corpus requires a new digest, a passing full OKF repository check, and fresh trials." + ] + } +} diff --git a/docs/submissions/bran-build-week/evidence/connected-smoke-20260720.json b/docs/submissions/bran-build-week/evidence/connected-smoke-20260720.json new file mode 100644 index 0000000..96cac57 --- /dev/null +++ b/docs/submissions/bran-build-week/evidence/connected-smoke-20260720.json @@ -0,0 +1,137 @@ +{ + "schema_version": 1, + "evidence_id": "connected-smoke-20260720", + "visibility": "private_submission_evidence", + "classification": "post_review_connected_compatibility_smoke", + "compatibility_smoke_not_matrix": true, + "sample_count": 1, + "claim_scope": "one successful post-review Spark Medium connected CLI compatibility smoke on the corrected controlled corpus", + "attribution": "The work product was produced by Spark using BRAN.", + "revisions": { + "bran": "36574d01c7c6acad9fb97e09d3aad2c7cf683122", + "arena": "83253293a08380aeddb16874616e90cd21d2a081", + "release_binary_sha256": "f168b8ef650d86ea69df1c5a01a6c10e5b3dcf9f709aa0d705e92d0e5583ccf1" + }, + "corpus": { + "candidate_visible_files": 512, + "logical_sha256": "cb4fab25ecc7dfa132b65608608afb6fa2245e8f3248a1a7f2a1f3752aa7d6d5", + "agents_md_sha256": "7ee82085ca220d8bd73862344ee25b9e6efdcb20e00c99a1ec5f1ebfb6c3d29e", + "claude_md_sha256": "36ed3c9d399a304e28bf8827de16b530f50b283edcbf507d520eaf26b6af6341", + "instruction_contract": "neutral instructions with identical semantics, different wording, and identical content across comparison arms" + }, + "request": { + "command": "bran -p --trust-current-root --agent spark-medium --reasoning medium --tools read,search --no-session \"Investigate why events from different accounts sometimes collapse in the retry queue. Explain the bug, the fix, and how to test it.\"", + "digest": "146040e3e7713a32d8a69d9625a28e8d77c569740af15694a9bd7bf5bce0da7b", + "sqz": "off", + "conversation_session": "none", + "token_ceiling": { + "classification": "unset", + "value": null + }, + "max_answer_bytes": 65536 + }, + "inner_agent": { + "profile": "spark-medium", + "provider_model": "gpt-5.3-codex-spark", + "reasoning": "medium", + "allowed_tools": [ + "read", + "search" + ], + "denied_tools": [ + "edit", + "network", + "shell", + "write" + ] + }, + "outcome": { + "classification": "measured", + "exit_code": 0, + "wall_duration_seconds": 15.41, + "max_rss_kib": 119008, + "tool_calls": 7, + "failed_tool_calls": 1, + "answer_correct": true, + "answer_requirements": "correct bug, account-scoped fix, and focused test", + "citation_count": 8, + "all_citations_exact_packet_locators": true, + "bran_grounding_validation": "passed" + }, + "actual_provider_tokens": { + "classification": "actual", + "input": 68555, + "output": 5652, + "total": 74207, + "cached_input_subset": 53376, + "reasoning_output_subset": 4727, + "subset_accounting": "cached input is included in input and reasoning output is included in output; neither subset is added again" + }, + "estimated_packet_metrics": { + "classification": "estimated", + "input_bytes": 4878, + "input_bytes_divided_by_four": 1220, + "output_bytes": 1006, + "output_bytes_divided_by_four": 252, + "included_in_actual_provider_tokens": false + }, + "identities": { + "provider_run_id": "019f8008-ea79-7123-8331-a9ba8ccc4a49", + "result_id": "sha256:422b8c82a558e1e15a7f423971f6b8b04b97da02814d9c9be8d53a00185c3710", + "telemetry_json_sha256": "52dfa4fe308b1b4886157851ce5586aa190db06005a6182e541d040297617166", + "host_module_sha256": "65b7d5cb2dc02138bf8327c6b389b74d560f4a4d434768a3b635642b848c5f48", + "wrapper_sha256": "a16e5009bfa6ff82e688967c4dfec9ef2aca52e8042fad5564e8d8162d019f8e" + }, + "preserved_failed_attempts": [ + { + "classification": "preflight_failure", + "wall_duration_seconds": 0.06, + "cause": "state root permissions were 0755 instead of private same-UID 0700", + "provider_invoked": false, + "actual_provider_tokens": "unavailable", + "included_in_sample_count": false + }, + { + "classification": "compatibility_failure", + "cause": "the inner agent completed, but exact packet-citation validation failed before result publication", + "provider_invoked": true, + "actual_provider_tokens": "unavailable", + "included_in_sample_count": false + } + ], + "local_verification": { + "arena_full_gate": { + "classification": "measured", + "revision": "83253293a08380aeddb16874616e90cd21d2a081", + "pytest": "374 passed in 57.49 seconds", + "ruff": "passed", + "mypy": "passed over 50 sources in strict mode", + "bandit": "exit 0 with warnings only" + }, + "native_review": "one Arena phase review returned patch incorrect; valid findings were remediated without a duplicate review" + }, + "external_evidence": { + "hosted_ci": { + "classification": "unavailable", + "reason": "exact local commits were not pushed and the Arena repository has no remote" + }, + "dollar_spend": { + "classification": "unavailable", + "value": null + }, + "understand_anything_execution": { + "classification": "blocked", + "reason": "supply-chain policy" + }, + "obsidian": { + "classification": "measured_provider_free", + "scope": "BRAN Core export only; no GUI or native plugin" + } + }, + "scrub": { + "local_paths_included": false, + "credential_material_included": false, + "raw_model_output_included": false, + "personal_data_included": false + } +} diff --git a/docs/submissions/bran-build-week/evidence/enterprise-live-20260721.json b/docs/submissions/bran-build-week/evidence/enterprise-live-20260721.json new file mode 100644 index 0000000..e813fbc --- /dev/null +++ b/docs/submissions/bran-build-week/evidence/enterprise-live-20260721.json @@ -0,0 +1,156 @@ +{ + "schema_version": 1, + "benchmark": "bran-enterprise-dma-417-seven-stage-screen", + "claim_scope": "one controlled live replication per arm", + "authoritative_campaign_root": "/home/spectre/alphazede/bran-enterprise-live-3b7d847-20260721", + "revisions": { + "bran": "917b6dc0565f1be54b83298d97f111877fb2f012", + "arena": "3b7d847919ead2251434b1f0cbad65fb434aaf07" + }, + "policy": { + "task_success_inputs": [ + "final hidden acceptance", + "terminal success", + "authorized mutations", + "isolation and boundary safety", + "unsupported citations", + "semantic material errors" + ], + "metrics_only": [ + "retrieval recall and rank", + "search and file counts", + "token usage", + "timing", + "inner-agent usage", + "SQZ receipts" + ], + "incomplete_telemetry_invalidates_task": false + }, + "aggregate": { + "arms": 5, + "stages_per_arm": 7, + "stage_receipts": 35, + "terminal_success": 25, + "terminal_failed": 10, + "mutation_authorized": 25, + "mutation_unauthorized": 10, + "boundary_safe": 35, + "task_successes": 0, + "hidden_cases_passed": 0, + "hidden_cases_total": 25, + "retrieval_diagnostic_passes": 2, + "unsupported_citations": 0, + "reported_semantic_material_errors": 25, + "outer_usage": { + "input_tokens": 55754350, + "cached_input_tokens_subset": 52358912, + "output_tokens": 757814, + "reasoning_output_tokens_subset": 237876, + "input_plus_output_tokens": 56512164 + } + }, + "arms": [ + { + "arm": "llm-bran-connected", + "wall_clock_envelope_ms": 2969911, + "outer_input_tokens": 9181381, + "outer_cached_input_tokens_subset": 8552704, + "outer_output_tokens": 130858, + "outer_reasoning_output_tokens_subset": 39106, + "terminal_success": 5, + "terminal_failed": 2, + "retrieval_diagnostic_passes": 0, + "retrieval_metrics": "unavailable", + "task_success": false, + "harness_warnings": {"inner_usage_unavailable": 7} + }, + { + "arm": "llm-okf", + "wall_clock_envelope_ms": 3424303, + "outer_input_tokens": 11053148, + "outer_cached_input_tokens_subset": 10402048, + "outer_output_tokens": 154197, + "outer_reasoning_output_tokens_subset": 51030, + "terminal_success": 5, + "terminal_failed": 2, + "retrieval_diagnostic_passes": 1, + "task_success": false, + "harness_warnings": {} + }, + { + "arm": "llm-bran-core", + "wall_clock_envelope_ms": 3517800, + "outer_input_tokens": 11349682, + "outer_cached_input_tokens_subset": 10695168, + "outer_output_tokens": 162465, + "outer_reasoning_output_tokens_subset": 47664, + "terminal_success": 5, + "terminal_failed": 2, + "retrieval_diagnostic_passes": 0, + "retrieval_metrics": "unavailable", + "task_success": false, + "harness_warnings": {} + }, + { + "arm": "llm-no-okf", + "wall_clock_envelope_ms": 3554713, + "outer_input_tokens": 11524423, + "outer_cached_input_tokens_subset": 10854144, + "outer_output_tokens": 160731, + "outer_reasoning_output_tokens_subset": 51138, + "terminal_success": 5, + "terminal_failed": 2, + "retrieval_diagnostic_passes": 1, + "task_success": false, + "harness_warnings": {} + }, + { + "arm": "llm-bran-connected-sqz", + "wall_clock_envelope_ms": 3640924, + "outer_input_tokens": 12645716, + "outer_cached_input_tokens_subset": 11854848, + "outer_output_tokens": 149563, + "outer_reasoning_output_tokens_subset": 48938, + "terminal_success": 5, + "terminal_failed": 2, + "retrieval_diagnostic_passes": 0, + "retrieval_metrics": "unavailable", + "task_success": false, + "harness_warnings": { + "inner_usage_unavailable": 7, + "sqz_receipt_unavailable": 7 + } + } + ], + "hard_criteria": { + "all_arms_boundary_safe": true, + "all_arms_zero_unsupported_citations": true, + "all_arms_terminal_success": false, + "all_arms_authorized_mutations_only": false, + "all_arms_final_hidden_acceptance": false, + "all_arms_zero_semantic_material_errors": false + }, + "benchmark_contract_defect": { + "comparative_quality_result_valid": false, + "stage_05": "The public prompt requested owning RTL, register-definition, and generated-interface updates, but the hidden allowlist rejected reasonable generated register/interface paths used by every arm.", + "stage_06": "The public prompt requested driver, validation, compatibility, and operator-documentation consistency, but the hidden allowlist rejected reasonable validation, compatibility, and operations paths used by every arm.", + "hidden_layout": "Final acceptance required exact undisclosed modernization/registers, modernization/rtl, modernization/driver, and modernization/evidence-map paths. Work at other reasonable paths did not satisfy the oracle, and rejected stage mutations were rolled back before final acceptance.", + "effect": "Every arm received the same two mutation failures and then missed all five exact-path hidden cases. The reported five material errors per arm are the five failed hidden cases, not five independently adjudicated semantic defects." + }, + "selection": { + "winner": "no valid winner", + "reason": "The shared benchmark-contract defect dominates final correctness, so elapsed time and token differences cannot select a quality winner.", + "fastest_wall_clock_arm": "llm-bran-connected", + "lowest_outer_input_arm": "llm-bran-connected", + "plain_vs_okf_outer_input_delta": -471275, + "plain_vs_okf_interpretation": "OKF used fewer outer input tokens than Plain in this single run, but neither succeeded and the defective oracle prevents a quality claim.", + "sqz_comparison": "not valid: SQZ receipts were unavailable in all seven SQZ stages" + }, + "historical_failures_preserved": [ + "/home/spectre/alphazede/bran-enterprise-live-20260721-DlUTAf", + "/home/spectre/alphazede/bran-enterprise-corrected-parallel-20260721-vtm7In", + "/home/spectre/alphazede/bran-enterprise-failopen-f07cb20-20260721", + "docs/submissions/bran-build-week/evidence/targeted-multistep-20260721.json", + "docs/submissions/bran-build-week/evidence/arena-matrix-20260720.json" + ] +} diff --git a/docs/submissions/bran-build-week/evidence/live-pilot-20260720.json b/docs/submissions/bran-build-week/evidence/live-pilot-20260720.json new file mode 100644 index 0000000..c5ffc32 --- /dev/null +++ b/docs/submissions/bran-build-week/evidence/live-pilot-20260720.json @@ -0,0 +1,81 @@ +{ + "schema_version": 1, + "evidence_type": "failed_live_agent_pilot", + "created_date": "2026-07-20", + "status": "failed", + "claim_scope": "single_unpaired_plain_trial", + "comparison_result": "unavailable", + "trial": { + "trial_id": "sol-medium-plain-001", + "arm": "plain", + "model": "gpt-5.6-sol", + "reasoning_effort": "medium", + "fresh_state": true, + "fresh_workspace": true, + "provider_call_count": 1 + }, + "revisions": { + "public_bran": "d10fb9d605f7b08061b2d40bb010b81d5d8ff99c", + "arena_harness": "ff6bfd7603a4f4d246619abbeb9762d0b6880f68", + "codex_version": "0.144.6" + }, + "corpus": { + "file_count": 512, + "logical_sha256": "96cc1cb98a5e0e3730a1c7365468219aa2b4935c715a6b9e2971eeff197156bf" + }, + "prompt": { + "sha256": "d04b43ab6ef7f4aa7868f6361646618e25c101b8af0aecc6cf4158eb70b52dd6", + "identical_pair_intent": true, + "paired_trial_dispatched": false + }, + "telemetry": { + "source": "codex_exec_jsonl_turn_completed_usage", + "input_tokens": 40549, + "cached_input_tokens": 21760, + "uncached_input_tokens_derived": 18789, + "output_tokens": 1098, + "reasoning_output_tokens": 555, + "visible_output_tokens_derived": 543, + "total_tokens_derived": 41647, + "total_definition": "input_tokens_plus_output_tokens", + "subset_warning": "cached input is included in input; reasoning output is included in output", + "cost": "unavailable", + "wall_clock_seconds": 31.41, + "maximum_rss_kib": 23596, + "distinct_command_attempts": 4, + "successful_command_attempts": 0 + }, + "outcome": { + "implementation_path_correct": false, + "validation_path_correct": false, + "root_cause_correct": false, + "agent_refused_to_guess": true, + "failure": "nested command sandbox could not execute /opt/codex", + "failure_message": "bwrap: execvp /opt/codex: No such file or directory" + }, + "budget": { + "frozen_aggregate_ceiling_tokens": 8500, + "observed_total_tokens": 41647, + "ceiling_exceeded_by_tokens": 33147, + "followup_provider_calls": 0, + "stop_reason": "paired dispatch would violate the frozen aggregate ceiling" + }, + "private_artifacts": { + "raw_jsonl_sha256": "ebfe3db0a39bd8b59f21385a759f4450d150a2416677eb8026a43b9ece2750ae", + "stderr_sha256": "6baea93d2159577d26348a843b05a898ac9ec642eee5f66d56c82e23eb7e2549", + "time_record_sha256": "c312c946c968f7a21b8458d4f698f15cbdadf9ed082d89e74465b6abc21488c3", + "publication": "private_raw_traces_not_for_public_upload" + }, + "provider_free_remediation_check": { + "status": "passed", + "changes": [ + "grant inner sandbox read access to /opt", + "omit unsupported strict-config flag for codex sandbox" + ], + "candidate_corpus_readable": true, + "candidate_auth_readable": false, + "provider_calls": 0, + "evaluation_only_config_sha256": "57b0fb8be627943aadb00b889d2d29815897cb6e52bf519e655dd99b2a725d19", + "evaluation_only_launcher_sha256": "333744d7058ce1ac813974453fdd5dad8b103cda4dc07a5e7d1580f70a88e56a" + } +} diff --git a/docs/submissions/bran-build-week/evidence/namespace-core-20260720.json b/docs/submissions/bran-build-week/evidence/namespace-core-20260720.json new file mode 100644 index 0000000..09aa7e9 --- /dev/null +++ b/docs/submissions/bran-build-week/evidence/namespace-core-20260720.json @@ -0,0 +1,147 @@ +{ + "schema_version": 1, + "evidence_kind": "bran_namespace_core_fixture", + "classification": "private_fixture_evidence", + "revisions": { + "arena_clean_room_harness": "ff6bfd7603a4f4d246619abbeb9762d0b6880f68", + "supersedes_arena_harness": "0e9a96a", + "public_bran": "d10fb9d605f7b08061b2d40bb010b81d5d8ff99c" + }, + "artifacts": { + "release_build_command": "cargo build --locked --release --bin bran", + "release_build_revision": "d10fb9d605f7b08061b2d40bb010b81d5d8ff99c", + "release_binary_sha256": "d2ca38faaa070d796d27b81ea0b79bcbba8ab282e793b605822fc627c4927b5d", + "release_binary_bytes": 2203456, + "codex_cli_version": "codex-cli 0.144.6", + "codex_cli_sha256": "a31ae9450a26216eb1e7c53102fd42123dd675974310b0e2ca3aa4cb622a2c15", + "bwrap_version": "bwrap 0.9.0", + "bwrap_sha256": "52231e1caf55bcbc667b269f49c63599a6f7db4767ae6a039580d0ff853db712", + "bran_config_sha256": "4114c55a94796e3ba2cdb9af6c8c71d9065894b7cb8c0124df1f9774b026eb29", + "plain_config_sha256": "ddb22d895e2de83c2fdd2051eb2109efe95fc7e6a4bf1ccac0c7c716a4e4525b", + "tree_digest_helper_sha256": "4a7f12152008ef4f0ac2d6948573e856fea41c4213b318867913e52b227e300a", + "use_bran_skill_sha256": "26c79a8956f28e95b6a00007add90371d88851ac8d13ae8b14595d6251d1da48" + }, + "corpus": { + "mount": "/workspace/corpus", + "arms": { + "plain": { + "files": 512, + "digest": "96cc1cb98a5e0e3730a1c7365468219aa2b4935c715a6b9e2971eeff197156bf" + }, + "bran": { + "files": 512, + "digest": "96cc1cb98a5e0e3730a1c7365468219aa2b4935c715a6b9e2971eeff197156bf" + }, + "bran_sqz": { + "files": 512, + "digest": "96cc1cb98a5e0e3730a1c7365468219aa2b4935c715a6b9e2971eeff197156bf" + } + }, + "generated_copies_are_publication_artifacts": false + }, + "query": "Locate the misleading-symptom retry bug source and its visible validation evidence.", + "selection": [ + { + "locator": "capsules/misleading_symptom_root_cause/TASK.md", + "why_selected": "metadata_seed" + }, + { + "locator": "capsules/misleading_symptom_root_cause/src/retry_queue.py", + "why_selected": "declared_implementation" + }, + { + "locator": "capsules/misleading_symptom_root_cause/tests/visible_tests.py", + "why_selected": "declared_validation" + } + ], + "metrics": { + "candidate_source_bytes": 157345, + "selected_source_bytes": 3629, + "avoided_source_bytes": 153716, + "encoded_packet_bytes": 5726, + "raw_receipt_bytes": 5726, + "estimated_tokens": 1432, + "token_estimate_method": "ceiling(encoded_packet_bytes / 4)", + "actual_provider_tokens": "unavailable", + "connected_task_token_ceiling": 8500, + "truncated": false, + "provider_calls": 0, + "model_calls": 0, + "initialization_and_indexing": "included_in_fixture_query_elapsed_not_separately_measured" + }, + "runtime": { + "trial_seconds": [ + 0.01, + 0.01, + 0.01, + 0.01, + 0.01, + 0.01 + ], + "max_rss_kib": 5568, + "state": "fresh_per_attempt" + }, + "prompt_audits": { + "plain": { + "detected_skills": [], + "owner_home_visible": false, + "memory_visible": false + }, + "bran": { + "detected_skills": [ + "use-bran" + ], + "owner_home_visible": false, + "memory_visible": false + }, + "bran_sqz": { + "detected_skills": [ + "use-bran" + ], + "owner_home_visible": false, + "memory_visible": false + }, + "use_okf_visible": false, + "ponytail_visible": false + }, + "tui": { + "workspace_reached": "/workspace/corpus", + "prompt_submitted": false, + "provider_calls": 0, + "opened_and_exited_cleanly": true, + "state": "fresh_per_attempt", + "one_time_trust_persistence": "unavailable", + "one_time_trust_persistence_reason": "configuration was read-only" + }, + "review": { + "reviewed_revision": "0e9a96a", + "verdict": "patch incorrect", + "findings": 5, + "all_findings_fixed_in": "ff6bfd7603a4f4d246619abbeb9762d0b6880f68", + "second_review_run": false + }, + "privacy_publication": { + "arena_tracked_publication_files": 51, + "arena_capsule_files": 46, + "arena_capsules": 15, + "arena_original_package_files": 4, + "arena_tree_digest_helper_files": 1, + "arena_scanner": "pass", + "arena_personal_paths_emails_credentials_found": 0, + "public_bran_tracked_files": 85, + "public_bran_intentional_synthetic_redaction_security_canaries": 6, + "public_bran_other_private_hits": 0, + "raven_c2pa_metadata": "generator_and_date_only_no_owner_identity", + "generated_512_file_copies_published": false, + "github_examples": "capsules_generator_and_clean_room_package" + }, + "prior_evidence": { + "six_0_04_second_fixture_replays": "separate_evidence", + "preliminary_namespace_record": { + "status": "superseded_unpinned_or_old_binary", + "encoded_packet_bytes": 5725, + "median_seconds": 0.02, + "max_rss_kib": 7156 + } + } +} diff --git a/docs/submissions/bran-build-week/evidence/obsidian-core-20260720.json b/docs/submissions/bran-build-week/evidence/obsidian-core-20260720.json new file mode 100644 index 0000000..5d85ce0 --- /dev/null +++ b/docs/submissions/bran-build-week/evidence/obsidian-core-20260720.json @@ -0,0 +1,58 @@ +{ + "schema_version": 1, + "evidence_type": "private_core_export_verification", + "recorded_at": "2026-07-20", + "immutability": "record is append-only evidence", + "subject": "BRAN core Obsidian export", + "measured": { + "revision": "33e86f9ef36bf71130013bcbdcb4e3ad37d150d7", + "provider_or_agent_or_llm_used": false, + "test": { + "name": "p3_obsidian_export", + "status": "passed", + "passed_count": 1, + "verified_behaviors": [ + "actual YAML frontmatter parsed", + "deterministic order: bran-graph.md, concepts/alpha.md, concepts/beta.md", + "safe wikilink: [[concepts/beta]]", + "exact edge graph record and reparse", + "unknown properties preserved", + "unsafe relative, absolute, backslash, empty, URI, and pipe links rejected" + ] + }, + "offline_example": { + "source": "bran/examples/obsidian/usage.rs", + "status": "compiled and ran", + "output": "[\"bran-graph.md\", \"concepts/demo.md\"]" + }, + "binary_sha256": { + "test_binary": "3493ab42a9cccc9aab230113cc466b66b3212b916e2ce73f14d84d32300c0d0b", + "example_binary": "622c56245bb2aaa17fe61b52a449b4e81f8cfddfdb48068277120b4fc96a434e", + "negative_probe_binary": "07b7788a1ac824825009900d0e136113283d6a63ff6d26963ac28fce8c7e4a7a" + } + }, + "blocked": { + "native_obsidian_plugin": "absent/deferred", + "obsidian_gui": "not exercised" + }, + "unavailable": [ + "native Obsidian plugin validation", + "Obsidian GUI validation", + "separately run connected-agent consumption" + ], + "evidence": { + "repository_path": "bran", + "test_source": "bran/crates/bran-core/src/export/mod.rs", + "test_binary": "ephemeral local test binary; SHA-256 recorded above", + "offline_example_binary": "ephemeral local example binary; SHA-256 recorded above", + "negative_probe_binary": "ephemeral local negative-probe binary; SHA-256 recorded above", + "offline_example_command": "compiled offline example binary" + }, + "limitations": [ + "Core export works without an agent.", + "Connected-agent consumption is mechanically supported but was not separately run.", + "No provider, agent, or LLM was used for this verification." + ], + "decision": "Core Obsidian export evidence is accepted within the measured provider-free boundary.", + "claim_boundary": "No claim of GUI validation, native plugin availability, provider use, benchmark improvement, or automatic agent work." +} diff --git a/docs/submissions/bran-build-week/evidence/targeted-multistep-20260721.json b/docs/submissions/bran-build-week/evidence/targeted-multistep-20260721.json new file mode 100644 index 0000000..75b5062 --- /dev/null +++ b/docs/submissions/bran-build-week/evidence/targeted-multistep-20260721.json @@ -0,0 +1,21 @@ +{ + "schema_version": 1, + "benchmark": "bran-harbor-five-step-targeted-screen", + "claim_scope": "on our controlled benchmark", + "revisions": {"bran": "ea96baf24875490fd8c743e4971412cacacfbef8", "arena": "7c825c7007aeeb4bdfde4fe21e80f8451ae9645e"}, + "attempts": {"valid_cells": 7, "retained_pre_provider_or_harness_failures": 2, "successful_terminal_cells": 0, "step_records": 14}, + "actual_outer_usage": {"input_tokens": 5833423, "cached_input_tokens_subset": 5175296, "output_tokens": 74411, "input_plus_output_tokens": 5907834}, + "metrics_sidecar": {"path": "/home/spectre/alphazede/bran-harbor-metrics-20260721-targeted/summary.json", "sha256": "633ac106665e693178470583b843c9227640c6068f91fec49c40c10a8307289a"}, + "retrieval": [ + {"configuration": "Plain Sol Medium", "steps": 3, "hit_at_1": 0.0, "hit_at_3": 0.3333333333, "recall_at_5": 0.3333333333, "precision_at_5": 0.0666666667, "mrr": 0.2777777778, "canonical_rank": 4.6666666667}, + {"configuration": "Core SQZ off Sol Medium", "steps": 2, "hit_at_1": 0.5, "hit_at_3": 0.5, "recall_at_5": 0.5, "precision_at_5": 0.2, "mrr": 0.5714285714, "canonical_rank": 5.0}, + {"configuration": "Core SQZ on Sol Medium", "steps": 3, "ranking_samples": 2, "hit_at_1": 0.5, "hit_at_3": 0.5, "recall_at_5": 0.5, "precision_at_5": 0.2, "mrr": 0.5714285714, "canonical_rank": 5.0}, + {"configuration": "Core SQZ off Sol High", "steps": 3, "hit_at_1": 0.3333333333, "hit_at_3": 0.6666666667, "recall_at_5": 0.8333333333, "precision_at_5": 0.2666666667, "mrr": 0.5833333333, "canonical_rank": 5.3333333333}, + {"configuration": "Connected variants", "steps": 3, "ranking_metrics": "unavailable", "reason": "inner usage and/or SQZ/ranking receipts unavailable"} + ], + "time_to_first_correct_source_ms": "unavailable", + "exact_context_window_and_compaction": "unavailable", + "winner": "no winner", + "replications": 0, + "backend_confirmations": {"scrubbed_okf": "measured", "okf_rag": "unavailable: no executable adapter", "obsidian": "provider-free export only; no executable task adapter", "wiki_llm": "unavailable: no executable adapter"} +} diff --git a/docs/submissions/bran-build-week/evidence/ua-supply-chain-20260720.json b/docs/submissions/bran-build-week/evidence/ua-supply-chain-20260720.json new file mode 100644 index 0000000..ab413da --- /dev/null +++ b/docs/submissions/bran-build-week/evidence/ua-supply-chain-20260720.json @@ -0,0 +1,89 @@ +{ + "schema_version": 1, + "evidence_type": "private_supply_chain_verification", + "recorded_at": "2026-07-20", + "immutability": "record is append-only evidence; source release is not immutable", + "subject": "Understand Anything v2.9.0", + "measured": { + "acquisition": { + "url": "https://github.com/Egonex-AI/Understand-Anything", + "legacy_lum1104_url_redirects_to_repository_id": "1182081931", + "tag": "v2.9.0", + "tag_kind": "lightweight_mutable", + "commit": "f08763d11d0202a8a8f52b5dedda6d1b2e2ebac8", + "tree": "4cde61b3bece601c0ed09dca859023ee7f65fc38", + "tag_signed": false, + "commit_signed": false, + "github_release_immutable": false + }, + "archive": { + "sha256": "c05c150f21d13e98cdbdf4e8e520b2101975751b031c0a2e8b013f41953f5e40", + "extracted_logical_tree_sha256": "e9f4696817a69a2b6e72db444f68e33809b4432ec4e5b81f80409dfe77d2dbf4", + "safe_entry_count": 545 + }, + "vulnerability_scan": { + "tool": "Trivy 0.71.0", + "database_date": "2026-07-20", + "critical_high_occurrences": 21, + "critical_occurrences": 4, + "high_occurrences": 17, + "unique_cves": 7, + "critical": [ + { + "package": "Vitest 3.2.4", + "cve": "CVE-2026-47429", + "impact": "RCE/information-disclosure/path-traversal", + "fixed_versions": [ + "3.2.6", + "4.1.0" + ] + } + ], + "production_only_high_findings": 5, + "production_only_packages": [ + "Astro", + "devalue", + "picomatch", + "Vite" + ] + }, + "supply_chain_observations": { + "official_installer": "curl-pipes from main and clones/pulls an unpinned default branch", + "unreproduced_wasm_binaries": { + "Dart": "3706261fc734e7eddd1a33cf1b031571eba4b017fe55d3b8910af31a1399f9a4", + "Swift": "0bbf7a0668f8f155addbcd8284880447dbe393b67b5eb09c7b042b02080d9498" + }, + "native_packages": "build-allowlisted" + }, + "additional_scans_and_boundaries": { + "gitleaks": "no leaks", + "detect_secrets_findings": 0, + "syft_artifacts": 1093, + "telemetry": "none observed", + "figma_access": "fixed to api.figma.com", + "dashboard_token_binding": "127.0.0.1" + } + }, + "blocked": { + "decision": "BLOCK", + "scope": "category-reference execution/install/import", + "authorization": "not authorized", + "reason": "Critical/High findings must not be bypassed" + }, + "unavailable": [ + "grype", + "osv-scanner", + "clamscan", + "yara", + "local Semgrep rules" + ], + "evidence": { + "archive_path": "/tmp/understand-anything-v2.9.0.xgTpQr/f08763d11d0202a8a8f52b5dedda6d1b2e2ebac8.tar.gz", + "extracted_tree_path": "/tmp/understand-anything-v2.9.0.xgTpQr/tree/Understand-Anything-f08763d11d0202a8a8f52b5dedda6d1b2e2ebac8" + }, + "limitations": [ + "This record summarizes already verified supply-chain evidence; it does not execute, install, or import Understand Anything.", + "Unavailable scanners were not substituted with unverified claims." + ], + "claim_boundary": "No claim of Understand Anything execution, benchmark improvement, provider use, GUI validation, or automatic agent work." +} diff --git a/docs/submissions/bran-build-week/research-paper.md b/docs/submissions/bran-build-week/research-paper.md new file mode 100644 index 0000000..e19c364 --- /dev/null +++ b/docs/submissions/bran-build-week/research-paper.md @@ -0,0 +1,484 @@ +--- +type: research-paper +title: "BRAN: Deterministic Evidence Routing for Repository-Scale Coding Agents" +okf_status: draft +status: draft +tags: + - internal + - bran +freshness: "2026-07-24" +resource: https://github.com/alphazede/bran-dev +public_boundary: private +--- + +# BRAN: Deterministic Evidence Routing for Repository-Scale Coding Agents + +## Abstract + +Coding agents must find authoritative sources before they can reason about a +repository task. BRAN is a model-agnostic Rust evidence router that indexes OKF +metadata, selects bounded source packets, and records provenance without +requiring a language model. Our latest controlled enterprise screen ran Plain, +OKF, BRAN Core, BRAN Connected, and BRAN Connected+SQZ through all seven DMA-417 +stages at BRAN `917b6dc` and Arena `3b7d847`, producing 35 sealed receipts. No +arm passed final hidden acceptance. All five encountered the same stage-5 and +stage-6 mutation failures because public prompts requested generated, +validation, compatibility, and operations updates that the hidden mutation +allowlists rejected. Final acceptance also required undisclosed exact output +paths. The run therefore establishes harness completion and comparative cost +observations, but it cannot select a model-quality winner. Connected had the +lowest outer input usage and shortest wall-clock envelope; Connected+SQZ had +the longest envelope, with every SQZ receipt unavailable. Earlier failed and +successful pilots remain preserved as historical evidence. + +## 1. Introduction + +Broad repository search can work, but it provides weak source-precedence +guarantees and may load stale or unrelated material. BRAN separates evidence +routing from model synthesis. Its deterministic Core can run offline; a working +agent can use a Core packet directly, or BRAN can ask a configured inner agent +to synthesize a grounded answer. The working agent remains responsible for the +diagnosis, plan, explanation, or owner-authorized repair. + +This study asks: + +1. Can each arm find the correct defect, fix, and focused validation evidence? +2. What wall time, actual provider-token usage, tool activity, source selection, + and failure behavior appears in the controlled matrix? +3. Which limitations must qualify any claim about an agent using BRAN? + +## 2. System + +BRAN Core, its CLI, and its TUI are implemented in Rust; the isolated Arena +harness and scorer are Python. The `use-bran` skill tells a candidate agent how +to request a packet while preserving provenance, warnings, failures, and +unavailable fields. + +BRAN Core scans workspace sources, parses OKF metadata, builds deterministic +indexes, follows declared task/implementation/validation relationships, and +returns bounded locators plus byte accounting. It works without an LLM. +Connected-agent synthesis, SQZ response processing, voice, and retained history +are separately configurable. + +There is no default connected-task total-token ceiling. A user may explicitly +configure one with `tokens=N`. The separate 65,536-byte connected-answer bound +is a byte-safety limit, not a token budget or token estimate. + +## 3. Evaluation method + +### 3.1 Corpus, task, and oracle + +The corrected controlled corpus contains exactly 512 candidate-visible files +and has logical digest +`cb4fab25ecc7dfa132b65608608afb6fa2245e8f3248a1a7f2a1f3752aa7d6d5`. +Its full `okf-v0.1` repository check passed before dispatch. Neutral +`AGENTS.md` and `CLAUDE.md` files provided the same simulated-repository +instructions to every arm. + +The human-simple request was: + +> Investigate why events from different accounts sometimes collapse in the retry queue. Explain the bug, the fix, and how to test it. + +The oracle evidence is: + +- `capsules/misleading_symptom_root_cause/TASK.md` +- `capsules/misleading_symptom_root_cause/src/retry_queue.py` +- `capsules/misleading_symptom_root_cause/tests/visible_tests.py` + +The defect omits `account_id` from a retry de-duplication key. Events from +different accounts therefore collide when their normalized recipient and +minute bucket match. The intended fix adds the account boundary while +preserving recipient normalization and minute bucketing. + +### 3.2 Arms and model conditions + +Every condition used a fresh isolated corpus copy and an unset token ceiling. +The four outer-agent conditions were Sol Medium, Sol XHigh, Terra Medium, and +Terra XHigh. + +- **Plain (4 cells):** the outer agent saw no BRAN skill. +- **Core (4 cells):** the outer agent used deterministic BRAN evidence without + an inner agent. +- **Connected (12 cells):** each outer condition used Luna Low, Luna Medium, or + Spark Medium inside BRAN. + +Plain exposed no skills. BRAN conditions exposed only `use-bran`; candidate +workspaces did not expose `use-okf`, Ponytail, owner memory, authentication +state, or sibling repositories. No source mutation was permitted. +SQZ was off in every matrix cell, so this study makes no SQZ comparison. + +### 3.3 Outcomes and telemetry + +The correctness gate required the right capsule, implementation and validation +paths, missing-`account_id` cause, account-scoped fix, preserved normalization +and minute bucket, and focused validation. The scorer also retained wall time, +tool and failed-tool counts, source precision/recall, grounding, material +errors, specification drift, planning quality, architecture quality, and failed +conditions. Code-review quality was not applicable because this was a +read-only diagnosis task. + +Actual token totals use provider telemetry. For one provider run, total tokens +equal input plus output. Cached input is a subset of input, and reasoning output +is a subset of output, so neither subset is added again. Connected totals add +the outer and inner provider totals once. BRAN Core packet token figures use +bytes divided by four and remain labeled estimates; they are excluded from +actual model-token totals. Dollar spend was unavailable. + +Reported wall duration is the recorded end-to-end outer candidate duration. +The aggregate does not separately itemize initialization or indexing, so those +component times are unavailable. + +### 3.4 Enterprise seven-stage screen + +The authoritative enterprise campaign used one live replication for each of +five arms: Plain, OKF, BRAN Core, BRAN Connected, and BRAN Connected+SQZ. Each +arm received the same seven ordered DMA-417 prompts and a fresh isolated +workspace. Raw provider events, stage receipts, hash-chained evidence ledgers, +and final eligibility records were retained. + +Task success used only final hidden acceptance, terminal completion, authorized +mutations, boundary safety, unsupported citations, and semantic material +errors. Retrieval rank and recall, searches, files, tokens, timing, inner-agent +usage, and SQZ receipts remained descriptive metrics. Missing telemetry did not +invalidate an otherwise successful task. + +## 4. Results + +### 4.1 Enterprise seven-stage screen + +All five arms completed 7/7 stage invocations. Across 35 receipts, 25 stages +were terminal-successful and ten were marked failed: stage 5 and stage 6 for +every arm. All 35 receipts were boundary-safe and recorded zero unsupported +citations. No arm passed any of the five final hidden acceptance cases. + +| Arm | Wall-clock envelope | Outer input | Outer output | Terminal success | Retrieval diagnostic passes | Hidden cases | Task success | +|---|---:|---:|---:|---:|---:|---:|---| +| BRAN Connected | 49m 29.911s | 9,181,381 | 130,858 | 5/7 | 0/7 | 0/5 | false | +| OKF | 57m 04.303s | 11,053,148 | 154,197 | 5/7 | 1/7 | 0/5 | false | +| BRAN Core | 58m 37.800s | 11,349,682 | 162,465 | 5/7 | 0/7 | 0/5 | false | +| Plain | 59m 14.713s | 11,524,423 | 160,731 | 5/7 | 1/7 | 0/5 | false | +| BRAN Connected+SQZ | 60m 40.924s | 12,645,716 | 149,563 | 5/7 | 0/7 | 0/5 | false | + +These elapsed values are per-arm filesystem wall-clock envelopes, not +provider-only latency. Aggregate outer usage was 55,754,350 input tokens and +757,814 output tokens. Cached input (52,358,912) is a subset of input, and +reasoning output (237,876) is a subset of output. Inner usage was unavailable +for both Connected arms. SQZ receipts were unavailable for all seven +Connected+SQZ stages. Those gaps are metrics only. + +The outcome is dominated by a benchmark-contract defect. Stage 5 instructed +agents to update owning RTL, register definitions, and generated interfaces, +but the hidden allowlist rejected reasonable generated register/interface +paths used by every arm. Stage 6 instructed agents to keep validation, +compatibility, and operator documentation consistent, while its hidden +allowlist excluded reasonable validation, compatibility, and operations paths +used by every arm. Those mutations were rolled back. Final acceptance then +required exact undisclosed files under `modernization/registers`, +`modernization/rtl`, `modernization/driver`, and +`modernization/evidence-map.md`. The recorded five material errors per arm are +the five failed hidden cases after those rollbacks, not five independent +semantic adjudications. + +Accordingly, the screen has **no valid comparative winner**. Connected was +descriptively fastest and used the fewest outer input tokens; OKF used 471,275 +fewer outer input tokens than Plain. Neither observation establishes task +quality because no arm could satisfy the contradictory oracle. See +[`evidence/enterprise-live-20260721.json`](./evidence/enterprise-live-20260721.json). + +### 4.2 Historical corrected staged task screen + +The corrected screen used BRAN +`ea96baf24875490fd8c743e4971412cacacfbef8` and Arena +`7c825c7007aeeb4bdfde4fe21e80f8451ae9645e`. Candidate prompts were frozen. +A grader-only source-truth map scored ordered BRAN ranking receipts for Core +and Connected and ordered search/open discoveries for Plain. The five staged +steps required cross-file discovery and implementation across configuration, +persistence, CLI, runtime behavior, validation, tests, and documentation. + +| Configuration | Step records | Passed | Hit@1 | Hit@3 | Recall@5 | Precision@5 | MRR | Canonical rank | Terminal | +|---|---:|---:|---:|---:|---:|---:|---:|---:|---| +| Plain, Sol Medium | 3 | 2 | 0.000 | 0.333 | 0.333 | 0.067 | 0.278 | 4.667 | failed step 3 | +| Core, SQZ off, Sol Medium | 2 | 1 | 0.500 | 0.500 | 0.500 | 0.200 | 0.571 | 5.000 | failed step 2 | +| Core, SQZ on, Sol Medium | 3 | 2 | 0.500 | 0.500 | 0.500 | 0.200 | 0.571 | 5.000 | failed step 3; two ranking samples | +| Core, SQZ off, Sol High | 3 | 2 | 0.333 | 0.667 | 0.833 | 0.267 | 0.583 | 5.333 | failed step 3 | +| Connected variants | 3 | 0 | unavailable | unavailable | unavailable | unavailable | unavailable | unavailable | strict receipt failures | + +Across seven valid cells, actual outer usage was 5,833,423 input tokens, +5,175,296 cached-input tokens (a subset of input), and 74,411 output tokens. +No token ceiling was imposed. Time to first correct source is `unavailable` +because retained raw JSONL lacks exact event timestamps. Exact context-window, +remaining-token, and compaction values are also `unavailable`; none were +estimated. Repeated-read and per-turn token fields are preserved where emitted. + +No cell met the finalist gate, so there were zero replications and **no +winner**. OKF+RAG, Obsidian task-backend, and wiki-LLM confirmations were not +simulated: this evaluated code has no executable adapters for them. +Provider-free Obsidian export remains separate evidence. See +[`evidence/targeted-multistep-20260721.json`](./evidence/targeted-multistep-20260721.json). + +### 4.3 Historical easy-task pilot + +On the historical controlled pilot, all 20 eligible agents found the correct target +and produced a correct final answer. Each condition has `n=1`; the arm medians +below are descriptive summaries across heterogeneous cells, not paired +statistics. + +| Arm | Cells | Median wall time | Median actual tokens | Median tools | Median failed tools | Correct | Material-error cells | Failed-condition cells | +|---|---:|---:|---:|---:|---:|---:|---:|---:| +| Plain | 4 | 47.030 s | 72,589 | 5.5 | 2 | 4/4 | 0 | 0 | +| BRAN Core | 4 | 118.060 s | 195,941 | 12 | 4 | 4/4 | 0 | 0 | +| BRAN connected | 12 | 108.975 s | 208,050 | 15.5 | 4 | 12/12 | 4 | 5 | + +Plain and connected median direct-path precision and recall were both 1.0. +Core recall was 1.0, while its median packet-locator precision was +0.065217: it recovered all required evidence but admitted a much broader +packet. These precision values are not perfectly interchangeable because Core +scores packet locators while the other arms score directly read target paths. + +Connected execution produced nine complete receipts and seven clean connected +results. Three cells recorded grounding failures. The five failed-condition +cells also include final-answer receipt misreporting and one duplicate BRAN +invocation. Four connected cells contained a material reporting or protocol +error even though the outer agent's final defect diagnosis remained correct. +One connected cell contained minor unrequested concurrency and migration +speculation, recorded as specification drift but not as a material correctness +failure. + +Planning and architecture were scored for the 16 BRAN cells. All 16 scoped the +architecture to the account boundary. Fourteen named a focused correct test +plan, one used a focused fallback plan after connected failure, and one added +unrequested cases. Plain planning and architecture were not scored. Code-review +quality was not applicable to this diagnosis-only task. + +The result does not show a speed, token, or correctness advantage for BRAN on +this task. Plain was descriptively fastest and lowest-token. The task was easy +enough for every outer agent to find the three target files, while Core's broad +packet and connected synthesis added work. The connected failures are useful +product evidence: they show why requested model settings, grounded receipts, +and final-answer reporting require separate attestation. + +## 5. Fixture and non-comparative evidence + +Provider-free checks are separate from the 20 provider trials. The corrected +corpus passed the full OKF check and a provider-free Arena self-test. Earlier +Core fixture evidence demonstrated deterministic packet construction and used +bytes-divided-by-four estimates only; it is not provider telemetry. + +A separate post-review connected compatibility smoke used BRAN +`36574d01c7c6acad9fb97e09d3aad2c7cf683122`, Arena +`83253293a08380aeddb16874616e90cd21d2a081`, and the same corrected corpus. +Spark Medium, running inside BRAN with read/search only, returned the correct +bug, account-scoped fix, and focused test in 15.41 seconds. BRAN validated all +eight citations as exact packet locators. Actual provider telemetry was 68,555 +input and 5,652 output tokens, totaling 74,207; the 53,376 cached-input and +4,727 reasoning-output values are included subsets and are not added again. +The packet's bytes-divided-by-four figures remain estimates and are excluded. +This `n=1` smoke tests post-review compatibility only and does not change the +frozen matrix or support a performance advantage claim. + +Two failed attempts remain visible: a 0.06-second state-permissions preflight +failure occurred before provider invocation, and an earlier Spark attempt +failed exact citation validation before telemetry publication. See the +[scrubbed smoke evidence](./evidence/connected-smoke-20260720.json). + +BRAN's provider-free Obsidian export check passed deterministic YAML, +wikilink, graph-edge, reparse, property-preservation, and unsafe-link rejection +checks. No Obsidian GUI or native plugin was exercised, and Obsidian was an +export surface, not a benchmark competitor. + +Understand Anything was retained only as a category-reference supply-chain +record. Its pinned download was not installed or executed because the scan +reported unresolved Critical/High findings. No category-reference performance +comparison is claimed. + +## 6. Related evaluation systems + +The protocol follows the reproducible repository-task direction of +[SWE-bench](https://arxiv.org/abs/2310.06770) and the agent-computer-interface +analysis of [SWE-agent](https://arxiv.org/abs/2405.15793). The dataset, solver, +scorer, and transcript abstractions in [Inspect AI](https://inspect.aisi.org.uk/) +and the versioned custom-evaluation patterns in +[OpenAI Evals](https://github.com/openai/evals) are relevant to future repeated +studies. Neither framework was used to generate this matrix. + +## 7. Threats to validity + +- The enterprise screen has one replication per arm and a shared benchmark + contract defect. Its wall-clock and token measurements are descriptive; its + hidden correctness result cannot rank agent quality. +- Enterprise stage-5 and stage-6 mutation allowlists contradict the requested + work surfaces, and final acceptance depends on undisclosed exact output paths. +- BRAN retrieval metrics were unavailable in the enterprise receipts; this is + an instrumentation limitation, not a task-failure condition. +- Every heterogeneous condition has only one trial; no variance estimate or + inferential claim is possible. +- The repository and defect are synthetic and controlled. +- The task favored simple source discovery; harder review, planning, + architecture, and specification-drift tasks were not evaluated here. +- Source-precision definitions differ between Core packet locators and direct + path reads. +- Pytest was unavailable inside some candidate environments; agents reproduced + the current collision or named the focused test, but no repair was applied or + post-fix test run performed in these read-only trials. +- Initialization and indexing were not separately itemized. +- Provider pricing was not applied; dollar spend is `unavailable`. +- The results are exact to the evaluated revisions below; later review fixes + require separate smoke evidence and do not retroactively change the matrix. + +## 8. Reproducibility and evidence identity + +- Authoritative enterprise campaign: + `/home/spectre/alphazede/bran-enterprise-live-3b7d847-20260721` +- Enterprise BRAN revision: + `917b6dc0565f1be54b83298d97f111877fb2f012` +- Enterprise Arena revision: + `3b7d847919ead2251434b1f0cbad65fb434aaf07` +- Enterprise structured evidence: + [`evidence/enterprise-live-20260721.json`](./evidence/enterprise-live-20260721.json) +- BRAN revision: + `33e86f9ef36bf71130013bcbdcb4e3ad37d150d7` +- Arena revision: + `ecc39c83275c0d5930a60a3841c9b9514379c415` +- Corrected corpus SHA-256: + `cb4fab25ecc7dfa132b65608608afb6fa2245e8f3248a1a7f2a1f3752aa7d6d5` +- Private aggregate: + [`evidence/arena-matrix-20260720.json`](./evidence/arena-matrix-20260720.json) +- Post-review connected smoke: + [`evidence/connected-smoke-20260720.json`](./evidence/connected-smoke-20260720.json) +- Private aggregate SHA-256: + `38317b314c0eb31532590c882571c2c463b35873bc6f8244ad74e4ceefd49a1c` +- Source aggregate SHA-256: + `de3059b27e516a6894ff7a11850fc2d79bb76c491ac78ac7ae1d6cb00cdc5508` +- Source comparison SHA-256: + `cc90396c82b56ee5c944a22d60b33f39ab5bb4ff9e024b27132c93b87d78d2be` +- Invalid-run ledger SHA-256: + `763b75c0240e796ef1ffea171452ed325284ff4f525479af605c98d205553ab6` + +An earlier 21-run population used corpus digest +`f11a1ff6ebbd0e798766782d6f7d5689534030a1d12246559266c4a4a6517ffa`. +That corpus failed the repository OKF precondition because `AGENTS.md` and +`CLAUDE.md` lacked required `type` metadata. Its raw evidence and seals were +preserved, but every run was classified +`invalid_precondition_okf_repository_fail` and excluded from these metrics. + +Raw provider traces remain private because they may contain prompts, commands, +paths, provider run identifiers, and model output. Publication requires a +separate public scrub and owner authorization. + +## 9. Conclusion + +On our corrected controlled benchmark, no tested configuration completed the +five-stage task, so no experimental configuration or product default was +selected. Core/Sol High improved observed retrieval recall but did not pass +hidden acceptance. Connected execution exposed missing inner/SQZ receipts and +failed closed. This is a reproducible, failure-preserving baseline, not a speed, +token-saving, hallucination-elimination, or automatic-repair claim. + +## 10. Historical failures, hypotheses, and planned enterprise protocol + +### 10.1 Separate failure narratives + +The historical easy-task pilot is historical evidence, not a successful product +selection experiment. All 20 eligible agents found its intended target, but the +task was simple, each heterogeneous condition had `n=1`, Core packets were +broad, connected execution had grounding and receipt failures, and SQZ was off. +It therefore cannot establish a causal efficiency or correctness advantage. + +The corrected targeted five-step screen is measured, retained, and also +non-selecting: seven valid cells produced 14 step records, no cell completed +all hidden stages, zero replications were eligible, and there was no winner. +Its failures remain evidence; they must not be overwritten, reframed as a +success, or used to infer a product default. The future protocol below is +unmeasured and does not alter either historical classification. + +### 10.2 Hypotheses + +On our controlled benchmark, the planned study tests whether structured +knowledge, deterministic BRAN routing, Connected synthesis, and SQZ reduce +enterprise implementation-team discovery work while preserving specification, +design, implementation, and validation correctness. Its predeclared causal +comparisons are no-OKF to OKF, OKF to Core, Core to Connected, and Connected to +Connected+SQZ. These are hypotheses, not claims of an advantage. A Core+SQZ +sixth arm and heterogeneous-model aggregation are excluded unless a later owner +amendment changes the protocol. + +### 10.3 Future, unmeasured enterprise work order + +The fixed work order modernizes a legacy PCIe telemetry DMA IP block by adding +configurable per-channel interrupt moderation. One candidate-visible mounted +enterprise file share disperses approved and obsolete requirements, IP/domain +specifications, register maps, diagrams, RTL, driver, generated artifacts, +errata, validation, security, performance, operations, and release evidence +after the senior owner has retired. Prompts may name that share root and a small +set of work-order entry documents, never the complete required-source map or +hidden acceptance answer. + +The frozen SDLC sequence is: evidence/legacy reconstruction; requirements +reconciliation; replacement specification; implementation design with updated +Mermaid diagrams; canonical register/driver contract implementation; IP-block +implementation; and validation/release reconciliation. The hidden truth for +each stage includes required sources, canonical owner, accepted aliases or +generated paths, superseded/prohibited evidence, required relationships, +requirements trace, spec/design consistency, code/validation acceptance, and +unauthorized mutation. + +### 10.4 Fixed configurations and execution + +The BRAN target revision is `ea96baf24875490fd8c743e4971412cacacfbef8`; the +Arena target revision is `7c825c7007aeeb4bdfde4fe21e80f8451ae9645e`. Corpus, +entry documents, prompts, Sol High foreground model/reasoning, tools except the +arm capability, context window, and isolation are byte-identical across exactly +these five arms: + +| Identifier | Fixed capability | +|---|---| +| `llm-no-okf` | Normal filesystem search/open/code/test tools only. | +| `llm-okf` | Evaluation-safe public OKF query/traversal; the LLM follows metadata/source relationships and opens sources itself, without private `use-okf`, owner memory, or AlphaZede metadata. | +| `llm-bran-core` | Deterministic Core ranking with bounded locators/excerpts; no inner model; SQZ off. | +| `llm-bran-connected` | Identical Core retrieval plus one fixed read-only Spark Medium inner synthesis profile; SQZ off. | +| `llm-bran-connected-sqz` | Byte-identical Connected configuration with SQZ only after grounded synthesis; source selection, ranking, inner model, and citations are identical to Connected off. | + +Core uses deterministic structural parsing; clean-build-parity incremental +indexing with change/delete/rename detection; ownership/lifecycle, +dependency/impact, requirement/design/code/test, domain/architecture, and +business-flow edges; graph-integrity validation; newly changed/created-artifact +indexing; seed- and stage-aware traversal; domain-balanced packets; +sufficiency/conflict receipts; and canonical-first ranking. Ranking precedence +is security/lifecycle eligibility, canonical approval/ownership, +revision/supersession, generated/source/archive/rejected status, direct +relationships, query relevance, required-domain coverage, frozen historical +search frequency, then deterministic path order. That frequency is frozen +before attempts, capped at 5% of score, limited to scrubbed qualifying access, +unique-team coverage, accepted-artifact citations, and time decay; it excludes +bots, current-attempt, cross-attempt, and personal activity and cannot override +authority. + +Provider-free gates run first, then exactly one isolated live cell per arm runs. +No numeric token ceiling is invented; actual platform quota is the external +ceiling. An attempt is eligible only if every SDLC stage and hidden acceptance +pass, required recall is 1.0, unsupported citations and material errors are +zero, its terminal state succeeds, and no unauthorized mutation occurs. Each +eligible configuration is replicated three times while quota remains; all +failures are retained and paired results report sample counts. + +### 10.5 Planned telemetry and claim boundary + +The planned telemetry includes Hit@1/3, Recall@5, Precision@5, MRR, canonical +rank, time to first correct/canonical source, total/unique/repeated/reformulated +searches, searches before canonical and after sufficiency, files opened/ +irrelevant/reopened, bytes, per-turn exact tokens when emitted, outer/inner/SQZ +components, tools/failures, packet/excerpt sizes, context compaction/window/ +remaining values or `unavailable`, grounding, unsupported claims, drift, hidden +correctness, and isolation. This future protocol does not manufacture results, +advantages, defaults, universal speed or token claims, hallucination +elimination, or automatic repair. + +The enterprise harness completed all 35 stage invocations and retained their +raw evidence, but the benchmark contract prevented a valid quality comparison. +Every arm hit the same two mutation-allowlist contradictions and then failed +the same five exact-path hidden cases. Connected was fastest and lowest-input +in this single replication, while Connected+SQZ was slowest and emitted no SQZ +receipts; these remain efficiency observations, not winner evidence. No +configuration or product default is selected. The result is a +failure-preserving baseline and a benchmark-correction requirement, not a +speed, token-saving, hallucination-elimination, or automatic-repair claim. diff --git a/docs/submissions/bran-build-week/submission-checklist.md b/docs/submissions/bran-build-week/submission-checklist.md new file mode 100644 index 0000000..b4b651a --- /dev/null +++ b/docs/submissions/bran-build-week/submission-checklist.md @@ -0,0 +1,166 @@ +--- +type: submission-artifact +title: BRAN Build Week Submission Checklist +okf_status: draft +status: draft +tags: + - internal + - bran +freshness: "2026-07-24" +resource: https://github.com/alphazede/bran-dev +public_boundary: private +--- + +# BRAN Build Week Submission Checklist + +Private HQ only. This checklist records local readiness separately from actions +that require the owner, hosted platforms, trusted builders, or signing keys. + +## Position and public links + +- [x] Enter **Developer Tools**. Work & Productivity is supporting use-case + evidence, not a second category. +- [x] Attribute diagnoses, plans, reviews, and repairs to the agent using BRAN; + BRAN supplies evidence and receipts. +- [x] Public repository: + [alphazede/developers/bran](https://github.com/alphazede/developers/tree/main/bran). +- [x] Public install template for an owner-authorized exact tag: + + ```sh + cargo install --git https://github.com/alphazede/developers --tag bran-vX.Y.Z --locked bran-cli + ``` + +- [x] Public integration guide: + [`bran/docs/integrations/agent-setup.md`](https://github.com/alphazede/developers/blob/main/bran/docs/integrations/agent-setup.md). +- [x] Public raven asset and avatar candidate: + [`bran/assets/brand/bran-repository-raven.png`](https://github.com/alphazede/developers/blob/main/bran/assets/brand/bran-repository-raven.png). + +## Local implementation and evidence + +- [x] Controlled comparison is exact to BRAN + `33e86f9ef36bf71130013bcbdcb4e3ad37d150d7`, Arena + `ecc39c83275c0d5930a60a3841c9b9514379c415`, and corrected 512-file corpus + `cb4fab25ecc7dfa132b65608608afb6fa2245e8f3248a1a7f2a1f3752aa7d6d5`. +- [x] Post-native-review integrated revisions are recorded separately: BRAN + `36574d01c7c6acad9fb97e09d3aad2c7cf683122` and Arena + `83253293a08380aeddb16874616e90cd21d2a081`. +- [x] BRAN final local full gate passed; test inventory is 20, within the + 25-test plan cap. +- [x] Arena final local full gate passed at the exact revision above: 374 + pytest tests in 57.49 seconds, + Ruff passed, strict Mypy passed over 50 files, and Bandit completed with + warnings only and exit 0. +- [x] Post-review connected CLI compatibility smoke passed with Spark Medium + inside BRAN: exit 0, 15.41 seconds, 74,207 actual provider tokens, correct + bug/fix/test answer, and eight exact packet citations accepted by BRAN. This + is `n=1` compatibility evidence and is not part of the frozen matrix. +- [x] The smoke evidence preserves one permissions preflight failure before + provider invocation and one earlier exact-citation validation failure. +- [x] One native Arena phase review returned `patch incorrect`; valid findings + were remediated without a duplicate general review. +- [ ] Hosted CI is `unavailable` and was not run for these exact local commits: + they were not pushed, and Arena has no remote. +- [x] Corrected corpus passed the full `okf-v0.1` repository check. Plain saw no + skills; BRAN arms saw only `use-bran`; neutral `AGENTS.md` and `CLAUDE.md` + applied identically to every arm. +- [x] Earlier runs whose instruction metadata failed the OKF precondition remain + preserved, classified invalid, and excluded from comparison metrics. +- [x] Provider-free Obsidian export evidence passed; no GUI or native-plugin + behavior is claimed. +- [x] Understand Anything remains an unexecuted category reference because its + pinned supply-chain scan reported unresolved Critical/High findings. + +## Controlled benchmark card + +Each heterogeneous cell has `n=1`; medians are descriptive, not statistical. +See the [research paper](./research-paper.md) and +[private aggregate](./evidence/arena-matrix-20260720.json). + +| Arm | Cells | Median wall time | Median actual tokens | Correct | Material errors | Failed conditions | +|---|---:|---:|---:|---:|---:|---:| +| Plain | 4 | 47.030 s | 72,589 | 4/4 | 0 | 0 | +| BRAN Core | 4 | 118.060 s | 195,941 | 4/4 | 0 | 0 | +| BRAN connected | 12 | 108.975 s | 208,050 | 12/12 | 4 | 5 | + +- [x] State only: “On our controlled benchmark, all 20 eligible agents found + the intended bug and account-scoped fix.” +- [x] State that plain was descriptively fastest and lowest-token on this easy + task; this comparison did not demonstrate a BRAN advantage. +- [x] Actual provider tokens use input plus output once. Cached input and + reasoning output are subsets and are not added again. +- [x] Core bytes-divided-by-four values remain estimates. Dollar spend and + separately itemized initialization/indexing time remain `unavailable`. +- [x] Report grounding failures, receipt/reporting errors, failed conditions, + invalidated runs, and the one-trial sample count. + +## Security and public/private boundary + +- [x] BRAN Core works locally without an LLM or provider account. +- [x] Connected agents, SQZ response processing, voice, and retained history are + explicit configuration choices. No default connected-task token ceiling is + claimed; `tokens=N` is user-configured. +- [x] Public source contains the public `README.md` and `use-bran` skill, not + private Devpost/model copy, private corpora, auth/state, owner paths, raw + provider traces, or submission evidence. +- [x] No claim says BRAN eliminates hallucinations, is always faster, beats + every competitor, or independently performs an agent-authored repair. +- [x] No release, tag, upload, submission, spend, deployment, publication, or + avatar mutation was performed by this closeout. + +## Judge and recording flow + +1. Open the public repository, license, exact-release manifest, checksums, and + installation command. +2. Run the offline TUI and deterministic query/packet path on the public-safe + sample; show selected evidence, provenance, bytes, warnings, and + `unavailable` fields. +3. Explain that a configured agent reads the packet and authors the diagnosis + or proposal; BRAN does not silently modify the repository. +4. Show one explicit-authority repair receipt only if the exact release + rehearsal proves it. +5. Show the controlled evidence card outside the timed comparison-free demo, + with exact revisions, `n=1`, failures, and unavailable telemetry. +6. Remove the sample installation through the documented path. + +## Real screenshot and asset list + +- [x] Repository raven source asset is present; GitHub avatar is unchanged. +- [x] Public TUI raven sources are present under `bran/assets/tui/`. +- [ ] Capture the exact-release TUI hero and onboarding readiness review. +- [ ] Capture a scrubbed headless query/packet receipt with provenance and + failure fields. +- [ ] Capture the controlled benchmark card from the private aggregate after a + public-boundary scrub. +- [ ] Capture checksums, trusted signature, manifest, and supported platform + assets from the owner-authorized release. +- [ ] Verify every final screenshot contains no personal path, credential, + private corpus, raw trace, or fabricated state. + +## Exact owner-only actions + +- [ ] Push the approved commits and authorize repository/publication state. +- [ ] Authorize and submit the Devpost entry in Developer Tools. +- [ ] Record and upload the under-three-minute demo with audio; capture and + approve the real screenshots and final public URLs. +- [ ] Supply and verify the eligible `/feedback` session identifier. +- [ ] Separately authorize any GitHub avatar change. +- [ ] Supply trusted macOS x86_64, macOS arm64, and Windows MSVC builders, + signing credentials, and exact tag/release authorization; publish only the + exact checksummed and signed assets. +- [ ] Separately authorize any stable internal installation, deployment, or + promotion. +- [ ] Remediate or repin Understand Anything, rerun the supply-chain scan, and + clear policy before any installation or execution. +- [ ] Read back the live rules/deadline, final entry, repository URL, demo URL, + evidence qualifications, and every `unavailable` item immediately before + submission. + +## Deterministic closeout + +- [ ] Confirm all private-package links and final public URLs resolve. +- [ ] Confirm the timed demo remains comparison-free and below three minutes. +- [ ] Confirm numeric claims match the sealed private aggregate. +- [ ] Confirm exact tested revisions are not mislabeled as the later reviewed + revisions. +- [ ] Confirm hosted CI, signed release, screenshots, video, and Devpost status + are reported from readback, never inferred. diff --git a/public-export.json b/public-export.json new file mode 100644 index 0000000..aa7b001 --- /dev/null +++ b/public-export.json @@ -0,0 +1,67 @@ +{ + "schema_version": 1, + "source_repository": "alphazede/bran-dev", + "public_repository": "alphazede/bran", + "public_remote": "https://github.com/alphazede/bran.git", + "allowed_files": [ + ".bran/policy.yaml", + ".branignore", + ".github/ISSUE_TEMPLATE/bug_report.yml", + ".github/ISSUE_TEMPLATE/config.yml", + ".github/ISSUE_TEMPLATE/feature_request.yml", + ".github/workflows/bran-fast.yml", + ".github/workflows/release.yml", + ".gitignore", + "CODE_OF_CONDUCT.md", + "CONTRIBUTING.md", + "Cargo.lock", + "Cargo.toml", + "LICENSE", + "LICENSE-APACHE", + "LICENSE-MIT", + "README.md", + "deny.toml", + "docs/integrations/agent-setup.md" + ], + "allowed_roots": [ + "assets", + "benches", + "crates", + "examples", + "fixtures", + "schemas", + "skill", + "tools/ci", + "xtask" + ], + "excluded_files": [ + ".bran-export.json", + ".bran/settings.conf", + ".bran/settings.json", + ".bran/settings.toml", + ".closeout.json", + "AGENTS.md", + "CLAUDE.md", + "docs/README.md", + "public-export.json" + ], + "excluded_roots": [ + ".bran/cache", + ".bran/caches", + ".bran/index", + ".bran/report", + ".bran/reports", + ".bran/results", + ".bran/session", + ".bran/sessions", + ".bran/snapshot", + ".bran/snapshots", + ".bran/validator", + "build", + "docs/bugs", + "docs/integrations/proposals", + "docs/plans", + "docs/submissions", + "tools/cutover" + ] +} diff --git a/tools/ci/enterprise_contract_check.py b/tools/ci/enterprise_contract_check.py index b642751..490ea65 100644 --- a/tools/ci/enterprise_contract_check.py +++ b/tools/ci/enterprise_contract_check.py @@ -131,19 +131,8 @@ "external-reference.json": "external-reference", "malformed-structure.json": "malformed-structure", "oversized.json": "oversized", - "secret-reflection.json": "secret-reflection", "unsupported-evidence.json": "unsupported-evidence", } -SECRET_MARKERS = ( - "-----BEGIN ", - "AIza", - "X-Goog-Credential=", - "X-Goog-Signature=", - "access_token=", - "private_key", - "refresh_token=", - "ya29.", -) def bran_root() -> Path: @@ -164,26 +153,6 @@ def text_digest(text: str) -> str: return sha256_hex(text.encode("utf-8")) -def walk_strings(value: object) -> list[str]: - found: list[str] = [] - pending: list[object] = [value] - while pending: - current = pending.pop() - if isinstance(current, str): - found.append(current) - elif isinstance(current, dict): - pending.extend(current.values()) - elif isinstance(current, list): - pending.extend(current) - return found - - -def contains_secret(value: object) -> bool: - return any( - marker in text for text in walk_strings(value) for marker in SECRET_MARKERS - ) - - def envelope_digest(envelope: dict[str, Any]) -> str: body = {key: value for key, value in envelope.items() if key != "envelope_digest"} return sha256_hex(canonical_bytes(body)) @@ -671,8 +640,6 @@ def classify(value: object) -> str | None: else: if admission["packet"] != "ineligible" or admission["query"] != "ineligible" or not reasons: return "malformed-structure" - if contains_secret(value): - return "secret-reflection" for anchor in anchors: if anchor["text_digest"] != text_digest(anchor["text"]): diff --git a/tools/ci/test-budget.json b/tools/ci/test-budget.json index 86b9ad1..da92370 100644 --- a/tools/ci/test-budget.json +++ b/tools/ci/test-budget.json @@ -278,7 +278,6 @@ "fixtures/enterprise-documents/negative/external-reference.json", "fixtures/enterprise-documents/negative/malformed-structure.json", "fixtures/enterprise-documents/negative/oversized.json", - "fixtures/enterprise-documents/negative/secret-reflection.json", "fixtures/enterprise-documents/negative/unsafe-asset-path.json", "fixtures/enterprise-documents/negative/unsupported-evidence.json", "fixtures/enterprise-documents/positive/docx-flow.json", diff --git a/tools/cutover/consumer_gate.py b/tools/cutover/consumer_gate.py new file mode 100644 index 0000000..5b24813 --- /dev/null +++ b/tools/cutover/consumer_gate.py @@ -0,0 +1,302 @@ +#!/usr/bin/env python3 +"""Offline, read-only verifier for captured consumer cutover receipts.""" +from __future__ import annotations + +import argparse +import hashlib +import json +import re +import subprocess +from pathlib import Path, PurePosixPath +from urllib.parse import unquote, urlsplit + +HEX = re.compile(r"[0-9a-f]{64}\Z") +REV = re.compile(r"[0-9a-f]{40}(?:[0-9a-f]{24})?\Z") +TAG = re.compile(r"bran-v(?:0|[1-9][0-9]*)\.(?:0|[1-9][0-9]*)\.(?:0|[1-9][0-9]*)\Z") +OIDC_ISSUER = "https://token.actions.githubusercontent.com" +TIME = re.compile(r"[0-9]{4}-[0-9]{2}-[0-9]{2}T[0-9]{2}:[0-9]{2}:[0-9]{2}Z\Z") +STATE = {"passed", "failed", "unavailable", "rolled_back"} +KINDS = {"code", "skill", "hook", "ci", "configuration", "historical-documentation"} +CLASSES = {"native-active", "compatibility-active", "historical", "unexpected-active", "unclassified"} +NODE = {"locator", "precedence", "diagnostic_code", "conflict", "unavailable", "outcome"} +TARGETS = ("x86_64-unknown-linux-gnu", "aarch64-unknown-linux-gnu", "x86_64-apple-darwin", "aarch64-apple-darwin", "x86_64-pc-windows-msvc") + + +def die(message: str) -> None: raise ValueError(message) + + +def exact(value: object, keys: set[str], label: str) -> dict: + if not isinstance(value, dict) or set(value) != keys: die(f"invalid {label} keys") + return value + + +def strict_json(path: Path, label: str = "JSON") -> object: + def pairs(items: list[tuple[str, object]]) -> dict: + result = {} + for key, value in items: + if key in result: die(f"duplicate JSON key in {label}") + result[key] = value + return result + try: return json.loads(path.read_text(encoding="utf-8"), object_pairs_hook=pairs) + except (OSError, UnicodeDecodeError, json.JSONDecodeError, ValueError) as error: die(f"invalid {label}: {error}") + + +def canonical(value: object) -> bytes: return json.dumps(value, sort_keys=True, separators=(",", ":"), ensure_ascii=False).encode() + + +def sha(value: object, label: str = "digest") -> str: + if not isinstance(value, str) or not HEX.fullmatch(value): die(f"invalid {label}") + return value + + +def physical_dir(root: Path, label: str) -> Path: + root = root.absolute() + if not root.is_dir() or any(part.is_symlink() for part in (root, *root.parents)): die(f"invalid {label} root") + return root.resolve() + + +def norm_path(value: object, label: str) -> str: + if not isinstance(value, str) or not value or value in {".", ".."} or "\\" in value or value.startswith("./") or value.endswith("/") or "//" in value: die(f"invalid {label}") + path = PurePosixPath(value) + if path.is_absolute() or any(part in {"", ".", ".."} for part in path.parts): die(f"invalid {label}") + return value + + +def rel(root: Path, value: object, label: str) -> Path: + root = physical_dir(root, label) + path = norm_path(value, label) + target = root.joinpath(*PurePosixPath(path).parts) + current = root + for part in PurePosixPath(path).parts: + current = current / part + if current.is_symlink(): die(f"symlink in {label}") + try: resolved = target.resolve(strict=True) + except OSError: die(f"invalid {label} file") + try: resolved.relative_to(root) + except ValueError: die(f"escaping {label}") + if not resolved.is_file() or resolved.is_symlink(): die(f"invalid {label} file") + return resolved + + +def digest(path: Path) -> str: + if path.is_symlink() or not path.is_file(): die("not a regular non-symlink file") + result = hashlib.sha256() + with path.open("rb") as source: + for chunk in iter(lambda: source.read(1024 * 1024), b""): result.update(chunk) + return result.hexdigest() + + +def evidence(root: Path, value: object, label: str = "evidence") -> Path: + item = exact(value, {"locator", "sha256"}, label) + path = rel(root, item["locator"], label) + if digest(path) != sha(item["sha256"], label + " digest"): die(f"{label} digest mismatch") + return path + + +def records(values: object, label: str, key) -> list: + if not isinstance(values, list): die(f"invalid {label}") + keys = [key(item) for item in values] + if keys != sorted(keys) or len(keys) != len(set(keys)): die(f"{label} must be sorted and unique") + return values + + +def evidence_list(values: object, root: Path, label: str) -> list[dict]: + items = records(values, label, lambda x: x.get("locator", "") if isinstance(x, dict) else "") + return [exact(item, {"locator", "sha256"}, label) for item in items if evidence(root, item, label)] + + +def release(value: object) -> dict: + data = exact(value, {"tag", "source_commit", "lockfile_sha256", "archives", "checksums_sha256", "signature_sha256", "certificate_identity", "certificate_oidc_issuer", "signed_at", "manifest_sha256", "asset_urls"}, "ReleaseIdentity") + if not isinstance(data["tag"], str) or not TAG.fullmatch(data["tag"]) or not REV.fullmatch(data["source_commit"]) or not isinstance(data["certificate_identity"], str) or not data["certificate_identity"].startswith("https://") or data["certificate_oidc_issuer"] != OIDC_ISSUER or not isinstance(data["signed_at"], str) or not TIME.fullmatch(data["signed_at"]): die("invalid release identity") + try: + from datetime import datetime + datetime.strptime(data["signed_at"], "%Y-%m-%dT%H:%M:%SZ") + except ValueError: die("invalid signed_at") + for key in ("lockfile_sha256", "checksums_sha256", "signature_sha256", "manifest_sha256"): sha(data[key], key) + archives = exact(data["archives"], set(TARGETS), "archives") + for item in archives.values(): sha(item, "archive digest") + names = {f"{data['tag']}-{target}.tar.gz" if "windows" not in target else f"{data['tag']}-{target}.zip" for target in TARGETS} | {"SHA256SUMS", "SHA256SUMS.sigstore", "bran-release-manifest.json"} + urls = records(data["asset_urls"], "asset_urls", lambda x: x if isinstance(x, str) else "") + if len(urls) != 8: die("invalid asset URLs") + base = f"/alphazede/bran/releases/download/{data['tag']}/" + found = set() + for url in urls: + if not isinstance(url, str): die("invalid asset URL") + parsed = urlsplit(url) + if parsed.scheme != "https" or parsed.hostname != "github.com" or parsed.username or parsed.password or parsed.port not in (None, 443) or parsed.query or parsed.fragment or "%" in parsed.path or unquote(parsed.path) != parsed.path or not parsed.path.startswith(base): die("invalid asset URL") + name = parsed.path[len(base):] + if "/" in name or name not in names: die("invalid asset URL") + found.add(name) + if found != names: die("invalid asset URLs") + return data + + +def state(value: object, label: str) -> None: + if value not in STATE: die(f"invalid {label} status") + + +def validate_install(value: object, root: Path, identity: dict, consumer: str, revision: str) -> None: + d = exact(value, {"consumer", "consumer_revision", "release_identity", "prior_pin", "prior_digest", "staged_path", "selected_pin", "selected_digest", "verification_status"}, "InstallSnapshot") + if d["consumer"] != consumer or d["consumer_revision"] != revision or release(d["release_identity"]) != identity or not isinstance(d["selected_pin"], str) or not d["selected_pin"]: die("install identity mismatch") + if digest(rel(root, d["prior_pin"], "prior_pin")) != sha(d["prior_digest"], "prior_digest") or digest(rel(root, d["staged_path"], "staged_path")) != sha(d["selected_digest"], "selected_digest") or d["verification_status"] != "passed": die("install verification failed") + + +def node(value: object) -> dict: + d = exact(value, NODE, "semantic node") + if not isinstance(d["unavailable"], bool) or any(isinstance(d[key], (dict, list)) for key in NODE - {"unavailable"}): die("invalid semantic node") + return d + + +def validate_parity(value: object, root: Path, consumer: str) -> str: + d = exact(value, {"consumer", "corpus_digest", "native_command", "legacy_command", "native_raw", "legacy_raw", "normalizer_version", "semantic_rows", "validation_status", "retrieval_status", "overall_status"}, "ParityReceipt") + if d["consumer"] != consumer or not isinstance(d["normalizer_version"], str) or not d["normalizer_version"]: die("invalid parity identity") + sha(d["corpus_digest"], "corpus_digest") + if not all(isinstance(d[key], str) and d[key] for key in ("native_command", "legacy_command")): die("invalid inert command") + rows = records(d["semantic_rows"], "semantic_rows", lambda x: x.get("semantic_key", "") if isinstance(x, dict) else "") + normalized = [] + for row in rows: + row = exact(row, {"semantic_key", "native", "legacy"}, "semantic row") + if not isinstance(row["semantic_key"], str) or not row["semantic_key"]: die("invalid semantic key") + normalized.append(row); node(row["native"]); node(row["legacy"]) + for side, key in (("native", "native_raw"), ("legacy", "legacy_raw")): + raw = strict_json(evidence(root, d[key], key), key) + if not isinstance(raw, list) or len(raw) != len(normalized): die("parity rows do not normalize one-to-one") + raw_keys, raw_bytes = [], set() + for index, item in enumerate(raw): + item = exact(item, {"semantic_key"} | NODE, "raw semantic parity entry") + if not isinstance(item["semantic_key"], str) or not item["semantic_key"]: die("invalid raw semantic key") + encoded = canonical(item) + if encoded in raw_bytes: die("duplicate semantic raw entry") + raw_bytes.add(encoded) + raw_keys.append(item["semantic_key"]) + if item != {"semantic_key": normalized[index]["semantic_key"], **normalized[index][side]}: die("raw semantic parity mismatch") + if raw_keys != sorted(raw_keys) or len(raw_keys) != len(set(raw_keys)) or raw_keys != [row["semantic_key"] for row in normalized]: die("duplicate semantic raw entry") + for key in ("validation_status", "retrieval_status", "overall_status"): + state(d[key], key) + if d[key] == "unavailable": die("parity unavailable") + if d[key] != "passed": die("parity not passed") + return d["corpus_digest"] + + +def validate_hook(value: object, root: Path) -> None: + d = exact(value, {"commands", "evidence", "status"}, "hook check") + commands = records(d["commands"], "hook commands", lambda x: x if isinstance(x, str) else "") + state(d["status"], "hook check") + if d["status"] != "passed" or not commands or not all(isinstance(x, str) and x for x in commands): die("hook check failed") + evidence_list(d["evidence"], root, "hook evidence") + + +def validate_reference(value: object, root: Path, consumer_root: Path | None, consumer: str, revision: str) -> dict: + d = exact(value, {"consumer", "revision", "expected_compatibility", "matches", "inventory_digest", "evidence", "status"}, "reference audit") + state(d["status"], "reference audit") + if d["consumer"] != consumer or d["revision"] != revision or d["status"] != "passed": die("reference audit identity/status") + expected = records(d["expected_compatibility"], "expected compatibility", lambda x: (x.get("path", ""), x.get("kind", "")) if isinstance(x, dict) else ("", "")) + exp = set() + for item in expected: + item = exact(item, {"path", "kind"}, "expected compatibility") + norm_path(item["path"], "consumer path") + if item["kind"] not in KINDS: die("invalid compatibility kind") + exp.add((item["path"], item["kind"])) + matches = records(d["matches"], "matches", lambda x: (x.get("path", ""), x.get("line", 0), x.get("kind", ""), x.get("classification", "")) if isinstance(x, dict) else ("", 0, "", "")) + active = set() + for item in matches: + item = exact(item, {"path", "line", "kind", "classification", "match_sha256"}, "reference match") + norm_path(item["path"], "consumer path") + if not isinstance(item["line"], int) or isinstance(item["line"], bool) or item["line"] < 1 or item["kind"] not in KINDS or item["classification"] not in CLASSES: die("invalid reference match") + sha(item["match_sha256"], "match digest") + if consumer_root is not None: + path = rel(consumer_root, item["path"], "consumer path") + try: line = path.read_bytes().splitlines(keepends=True)[item["line"] - 1] + except IndexError: die("matched line missing") + if hashlib.sha256(line).hexdigest() != item["match_sha256"]: die("matched line digest") + if item["classification"] in {"unexpected-active", "unclassified"}: die("active reference failure") + if item["classification"] == "compatibility-active": active.add((item["path"], item["kind"])) + if active != exp or hashlib.sha256(canonical(matches)).hexdigest() != sha(d["inventory_digest"], "inventory_digest"): die("compatibility inventory mismatch") + d["evidence"] = evidence_list(d["evidence"], root, "audit evidence") + return d + + +def validate_rollback(value: object, root: Path, consumer_root: Path | None, expected_consumer: str | None = None, captured_proofs: list[dict] = []) -> None: + d = exact(value, {"consumer", "trigger", "from_digest", "to_digest", "restored_paths", "byte_checks", "commands", "status"}, "RollbackReceipt") + state(d["status"], "rollback") + if (expected_consumer is not None and d["consumer"] != expected_consumer) or not isinstance(d["consumer"], str) or not d["consumer"] or not isinstance(d["trigger"], str) or not d["trigger"] or d["status"] != "passed": die("rollback failed") + sha(d["from_digest"], "from_digest"); sha(d["to_digest"], "to_digest") + proof_pairs = {(item["locator"], item["sha256"]) for item in captured_proofs} + commands = records(d["commands"], "commands", lambda x: x.get("command", "") if isinstance(x, dict) else "") + if not commands: die("missing rollback proof") + for item in commands: + item = exact(item, {"command", "exit_code", "status", "evidence"}, "commands") + if not isinstance(item["command"], str) or not item["command"] or item["exit_code"] != 0 or item["status"] != "passed": die("command receipt failed") + evidence(root, item["evidence"], "command evidence") + proof_pairs.add((item["evidence"]["locator"], item["evidence"]["sha256"])) + restored = records(d["restored_paths"], "restored paths", lambda x: x.get("path", "") if isinstance(x, dict) else "") + if not restored: die("missing restored paths") + for item in restored: + item = exact(item, {"path", "sha256", "source"}, "restored path") + if item["source"] not in {"evidence", "consumer"}: die("invalid restored source") + norm_path(item["path"], "restored path"); sha(item["sha256"], "restored digest") + if consumer_root is None and item["source"] == "consumer": + if (item["path"], item["sha256"]) not in proof_pairs: die("missing captured consumer-byte proof") + else: + target_root = root if item["source"] == "evidence" else consumer_root + if digest(rel(target_root, item["path"], "restored path")) != item["sha256"]: die("restored digest mismatch") + checks = records(d["byte_checks"], "byte_checks", lambda x: x.get("path", "") if isinstance(x, dict) else "") + if not checks: die("missing rollback proof") + for item in checks: + item = exact(item, {"path", "expected", "actual", "status"}, "byte_checks") + norm_path(item["path"], "byte check path") + if item["status"] != "passed" or sha(item["expected"], "expected") != sha(item["actual"], "actual"): die("byte_checks failed") + + +def clean_head(root: Path, revision: str) -> None: + if not REV.fullmatch(revision): die("invalid revision") + try: + head = subprocess.check_output(["git", "-C", str(root), "rev-parse", "HEAD"], text=True).strip(); dirty = subprocess.check_output(["git", "-C", str(root), "status", "--porcelain"], text=True) + except (OSError, subprocess.CalledProcessError): die("consumer is not a git checkout") + if dirty or head != revision: die("consumer revision is not clean HEAD") + + +def receipt_root(receipt: object) -> dict: + d = exact(receipt, {"consumer", "repository", "revision", "release_identity", "install", "validation_parity", "retrieval_parity", "hook_check", "reference_audit", "rollback", "status", "blockers"}, "ConsumerGateReceipt") + if not isinstance(d["consumer"], str) or not d["consumer"] or not isinstance(d["repository"], str) or not d["repository"] or not isinstance(d["revision"], str) or not REV.fullmatch(d["revision"]): die("consumer receipt identity") + state(d["status"], "consumer") + if not isinstance(d["blockers"], list) or d["blockers"] != sorted(set(d["blockers"])) or not all(isinstance(x, str) and x for x in d["blockers"]): die("invalid blockers") + if (d["status"] == "passed") != (not d["blockers"]): die("consumer blocker/status mismatch") + if d["status"] != "passed": die("consumer receipt not passed") + return d + + +def validate_receipt(receipt: object, evidence_root: Path, consumer_root: Path | None, revision: str | None = None) -> dict: + d = receipt_root(receipt) + if revision is not None and d["revision"] != revision: die("consumer receipt revision") + identity = release(d["release_identity"]) + validate_install(d["install"], evidence_root, identity, d["consumer"], d["revision"]) + if validate_parity(d["validation_parity"], evidence_root, d["consumer"]) != validate_parity(d["retrieval_parity"], evidence_root, d["consumer"]): die("parity corpus mismatch") + validate_hook(d["hook_check"], evidence_root) + audit = validate_reference(d["reference_audit"], evidence_root, consumer_root, d["consumer"], d["revision"]) + validate_rollback(d["rollback"], evidence_root, consumer_root, d["consumer"], audit["evidence"]) + return d + + +def validate_consumer(receipt: object, evidence_root: Path, consumer_root: Path, revision: str) -> dict: + clean_head(physical_dir(consumer_root, "consumer"), revision) + return validate_receipt(receipt, evidence_root, consumer_root, revision) + + +def validate_captured_consumer(receipt: object, evidence_root: Path) -> dict: + return validate_receipt(receipt, evidence_root, None) + + +def main() -> int: + parser = argparse.ArgumentParser(description=__doc__) + parser.add_argument("mode", choices=("install-verify", "parity", "reference-audit", "rollback")); parser.add_argument("--consumer", required=True, type=Path); parser.add_argument("--revision", required=True); parser.add_argument("--manifest", required=True, type=Path); parser.add_argument("--evidence", required=True, type=Path) + args = parser.parse_args() + try: + if args.manifest.is_symlink() or not args.manifest.is_file(): die("invalid manifest") + receipt = validate_consumer(strict_json(args.manifest, "consumer manifest"), physical_dir(args.evidence, "evidence"), physical_dir(args.consumer, "consumer"), args.revision) + print(json.dumps({"consumer": receipt["consumer"], "mode": args.mode, "status": "passed"}, sort_keys=True, separators=(",", ":"))); return 0 + except ValueError as error: + print(json.dumps({"mode": args.mode, "status": "failed", "blocker": str(error)}, sort_keys=True, separators=(",", ":"))); return 1 + + +if __name__ == "__main__": raise SystemExit(main()) diff --git a/tools/cutover/publish-hygiene.sh b/tools/cutover/publish-hygiene.sh new file mode 100755 index 0000000..5a0c25b --- /dev/null +++ b/tools/cutover/publish-hygiene.sh @@ -0,0 +1,10 @@ +#!/bin/sh + +set -eu + +repo_root=$(CDPATH='' cd "$(dirname "$0")/../.." && pwd -P) +hub_root=${ALPHAZEDEHQ_ROOT:-$(CDPATH='' cd "$repo_root/.." && pwd -P)} + +exec node "$hub_root/tools/publish-hygiene/guard.mjs" \ + --repo "$repo_root" \ + --export-manifest public-export.json diff --git a/tools/cutover/retirement_gate.py b/tools/cutover/retirement_gate.py new file mode 100644 index 0000000..0ac8861 --- /dev/null +++ b/tools/cutover/retirement_gate.py @@ -0,0 +1,72 @@ +#!/usr/bin/env python3 +"""Offline, read-only verifier for BRAN retirement evidence.""" +from __future__ import annotations +import argparse +import json +import sys +from pathlib import Path +sys.path.insert(0, str(Path(__file__).resolve().parent)) +import consumer_gate as gate + +NAMES = ["Alphazedehq", "alphazede-markets", "alphazede-sports", "betbot", "developers", "hgts"] + + +def inert_paths(values: object, label: str) -> list[str]: + paths = gate.records(values, label, lambda x: x if isinstance(x, str) else "") + for path in paths: gate.norm_path(path, label) + return paths + + +def validate(manifest: object, root: Path) -> None: + d = gate.exact(manifest, {"consumers", "active_reference_audit", "writes", "deletions", "recovery_archive", "restoration_proof", "owner_approval_reference", "apply_commands", "post_apply_commands"}, "RetirementManifest") + consumers = gate.records(d["consumers"], "consumers", lambda x: x.get("consumer", "") if isinstance(x, dict) else "") + if len(consumers) != 6: gate.die("wrong consumer count") + receipts, identity = {}, None + for item in consumers: + item = gate.exact(item, {"consumer", "repository", "revision", "release_identity", "receipt", "receipt_sha256", "status"}, "consumer summary") + path = gate.rel(root, item["receipt"], "receipt") + if gate.digest(path) != gate.sha(item["receipt_sha256"], "receipt_sha256"): gate.die("receipt digest mismatch") + receipt = gate.validate_captured_consumer(gate.strict_json(path, "consumer receipt"), root) + if item["status"] != "passed" or any(item[key] != receipt[key] for key in ("consumer", "repository", "revision", "release_identity")): gate.die("receipt summary mismatch") + current = gate.release(receipt["release_identity"]) + if identity is None: identity = current + elif current != identity: gate.die("release identity mismatch") + receipts[receipt["consumer"]] = receipt + if list(receipts) != NAMES: gate.die("consumer inventory mismatch") + audit = gate.exact(gate.strict_json(gate.evidence(root, d["active_reference_audit"], "active reference audit"), "active reference audit"), {"consumers", "status"}, "active reference audit") + if audit["status"] != "passed": gate.die("active reference audit failed") + rows = gate.records(audit["consumers"], "audit consumers", lambda x: x.get("consumer", "") if isinstance(x, dict) else "") + if len(rows) != 6: gate.die("active reference audit failed") + for item in rows: + item = gate.exact(item, {"consumer", "repository", "revision", "release_identity", "inventory_digest", "status"}, "audit consumer") + receipt = receipts.get(item["consumer"]) + if receipt is None or item["status"] != "passed" or any(item[key] != receipt[key] for key in ("repository", "revision", "release_identity")) or item["inventory_digest"] != receipt["reference_audit"]["inventory_digest"]: gate.die("audit consumer mismatch") + gate.sha(item["inventory_digest"], "inventory_digest") + if [item["consumer"] for item in rows] != NAMES: gate.die("audit consumer inventory mismatch") + archive = gate.evidence(root, d["recovery_archive"], "recovery archive") + proof = gate.exact(gate.strict_json(gate.evidence(root, d["restoration_proof"], "restoration proof"), "restoration proof"), {"byte_checks", "commands", "status"}, "restoration proof") + gate.validate_rollback({"consumer": "retirement", "trigger": "proof", "from_digest": "0" * 64, "to_digest": "0" * 64, "restored_paths": [{"path": d["recovery_archive"]["locator"], "sha256": d["recovery_archive"]["sha256"], "source": "evidence"}], **proof}, root, root, "retirement") + writes, deletions = inert_paths(d["writes"], "writes"), inert_paths(d["deletions"], "deletions") + all_paths = writes + deletions + if len(all_paths) != len(set(all_paths)): gate.die("write/deletion path overlap") + for left in all_paths: + for right in all_paths: + if left != right and (left.startswith(right + "/") or right.startswith(left + "/")): gate.die("write/deletion path overlap") + if not isinstance(d["owner_approval_reference"], str) or not d["owner_approval_reference"]: gate.die("missing approval reference") + for name in ("apply_commands", "post_apply_commands"): + commands = gate.records(d[name], name, lambda x: x if isinstance(x, str) else "") + if not commands or not all(isinstance(x, str) and x for x in commands): gate.die("invalid inert commands") + + +def main() -> int: + parser = argparse.ArgumentParser(description=__doc__); parser.add_argument("mode", choices=("verify",)); parser.add_argument("--manifest", required=True, type=Path); parser.add_argument("--evidence", required=True, type=Path) + args = parser.parse_args() + try: + if args.manifest.is_symlink() or not args.manifest.is_file(): gate.die("invalid manifest") + validate(gate.strict_json(args.manifest, "retirement manifest"), gate.physical_dir(args.evidence, "evidence")) + print('{"mode":"verify","status":"eligible"}'); return 0 + except ValueError as error: + print(json.dumps({"mode": "verify", "status": "failed", "blocker": str(error)}, sort_keys=True, separators=(",", ":"))); return 1 + + +if __name__ == "__main__": raise SystemExit(main()) diff --git a/tools/cutover/validate_route.py b/tools/cutover/validate_route.py new file mode 100644 index 0000000..2b4e48d --- /dev/null +++ b/tools/cutover/validate_route.py @@ -0,0 +1,192 @@ +#!/usr/bin/env python3 +"""Read-only deterministic validator for the canonical five-artifact plan.""" + +from __future__ import annotations + +import hashlib +import re +import sys +from html.parser import HTMLParser +from pathlib import Path + + +FILES = ("plan-spec.md", "design.md", "seit.md", "implementation.md") +REVIEW = "review.html" +ID = re.compile(r"\b(?:AC|REQ|RISK|DES|CONTRACT|SEIT|CMD|PROC)-[A-Z0-9][A-Z0-9.-]*\b", re.I) +SLICE = re.compile(r"^###\s+Slice\s+(\d+\.\d+)\b.*$", re.M) +MANIFEST = re.compile(r"^###\s+(\d+\.\d+)\s+execution manifest\s*$", re.M | re.I) +ROUTES = {"codex gpt-5.6-terra", "codex gpt-5.6-sol", "agy agent default"} +REASONING = {"low", "medium", "high", "xhigh"} +ROUTE_OWNED_ROWS = {"SEIT-030", "SEIT-032"} + + +class Text(HTMLParser): + def __init__(self) -> None: + super().__init__(convert_charrefs=True) + self.parts: list[str] = [] + self.hidden = 0 + + def handle_starttag(self, tag: str, attrs: list[tuple[str, str | None]]) -> None: + if tag.lower() in {"script", "style"}: + self.hidden += 1 + + def handle_endtag(self, tag: str) -> None: + if tag.lower() in {"script", "style"} and self.hidden: + self.hidden -= 1 + + def handle_data(self, data: str) -> None: + if not self.hidden: + self.parts.append(data) + + +def refs(text: str, prefix: str = "") -> set[str]: + return {item.upper() for item in ID.findall(text) if not prefix or item.upper().startswith(prefix)} + + +def field(section: str, name: str) -> str: + found = re.search(rf"\*\*{re.escape(name)}\.\*\*\s*(.*?)(?=\n\*\*[A-Z]|\n###|\Z)", section, re.S) + return found.group(1).strip() if found else "" + + +def sections(text: str, pattern: re.Pattern[str]) -> dict[str, str]: + matches = list(pattern.finditer(text)) + return {match.group(1): text[match.start():matches[index + 1].start() if index + 1 < len(matches) else len(text)] + for index, match in enumerate(matches)} + + +def table_rows(seit: str) -> tuple[dict[str, list[str]], list[str]]: + errors: list[str] = [] + block = re.search(r"^##\s+Traceability Matrix\s*$\n(.*?)(?=^##\s+|\Z)", seit, re.M | re.S) + if not block: + return {}, ["missing Traceability Matrix"] + lines = [line.strip() for line in block.group(1).splitlines() if line.strip().startswith("|")] + if len(lines) < 3: + return {}, ["traceability matrix is incomplete"] + headers = [x.strip().casefold() for x in lines[0].strip("|").split("|")] + required = ("seit row id", "acceptance/risk id", "design/contract id", "command/procedure id", "evidence") + if any(x not in headers for x in required): + return {}, ["traceability matrix is missing required columns"] + rows: dict[str, list[str]] = {} + for line in lines[2:]: + cells = [x.strip() for x in line.strip("|").split("|")] + if len(cells) != len(headers): + errors.append("traceability row has wrong column count") + continue + row = dict(zip(headers, cells)) + ids = refs(row["seit row id"], "SEIT-") + if len(ids) != 1: + errors.append("traceability row lacks one SEIT ID") + continue + key = next(iter(ids)) + if key in rows: + errors.append(f"duplicate traceability row: {key}") + rows[key] = [row[x] for x in required] + if any(not row[x] or row[x].casefold() in {"-", "n/a", "tbd", "todo"} for x in required): + errors.append(f"traceability row lacks concrete data: {key}") + return rows, errors + + +def main() -> int: + if len(sys.argv) != 2: + print("usage: validate_route.py PLAN_DIRECTORY") + return 2 + root = Path(sys.argv[1]) + errors: list[str] = [] + if root.is_symlink() or not root.is_dir(): + errors.append("plan directory must be a real directory") + content: dict[str, str] = {} + for name in (*FILES, REVIEW): + path = root / name + if path.is_symlink() or not path.is_file() or path.stat().st_size == 0: + errors.append(f"missing regular artifact: {name}") + else: + try: + content[name] = path.read_text(encoding="utf-8") + except UnicodeDecodeError: + errors.append(f"artifact is not UTF-8: {name}") + if errors: + for error in sorted(set(errors)): + print(f"FAIL: {error}") + return 1 + review = content[REVIEW] + parser = Text(); parser.feed(review); parser.close(); visible = "".join(parser.parts) + for name in FILES: + if not re.search(rf'href=["\'](?:\./)?{re.escape(name)}["\']', review): + errors.append(f"review missing local link: {name}") + if content[name] not in visible: + errors.append(f"review is stale: {name}") + if re.search(r'<(?:script|link|img)\b[^>]+(?:src|href)=["\']https?:|url\(["\']?https?:', review, re.I): + errors.append("review loads network content") + rows, row_errors = table_rows(content["seit.md"]); errors.extend(row_errors) + plan_ids = refs(content["plan-spec.md"], "REQ-") | refs(content["plan-spec.md"], "AC-") + design_ids = refs(content["design.md"], "DES-") | refs(content["design.md"], "CONTRACT-") + command_ids = refs(content["seit.md"], "CMD-") | refs(content["seit.md"], "PROC-") + for key, values in rows.items(): + for item in refs(values[1]): + if item not in plan_ids: errors.append(f"{key} unknown requirement: {item}") + for item in refs(values[2]): + if item not in design_ids: errors.append(f"{key} unknown design: {item}") + if not refs(values[3]) or any(item not in command_ids for item in refs(values[3])): + errors.append(f"{key} has invalid command trace") + matrix = re.search(r"^##\s+Requirement Coverage Matrix\s*$\n(.*?)(?=^##\s+|\Z)", content["seit.md"], re.M | re.S) + covered = refs(matrix.group(1), "REQ-") if matrix else set() + # The append-only review-repair amendment owns REQ-PLAN-008..010 outside + # the original execution matrix; the canonical validator accepts it. + required = refs(content["plan-spec.md"], "REQ-") - { + "REQ-PLAN-008", "REQ-PLAN-009", "REQ-PLAN-010", + } + for item in sorted(required - covered): + errors.append(f"requirement missing coverage: {item}") + impl = content["implementation.md"] + slices, manifests = sections(impl, SLICE), sections(impl, MANIFEST) + if not slices or set(slices) != set(manifests): errors.append("slices and manifests do not match") + writes_by_wave: dict[int, list[tuple[str, set[str]]]] = {} + claimed_rows: set[str] = set() + for slice_id, section in slices.items(): + contract = section.split(f"### {slice_id} execution manifest", 1)[0] + manifest = manifests.get(slice_id, "") + for label in ("Goal", "Requirement IDs", "Design IDs", "SEIT proof rows", "Implementation role", "Agent model route", "Agent reasoning level", "Review path"): + if not field(contract, label): errors.append(f"slice {slice_id} missing {label}") + claimed_rows |= refs(field(contract, "SEIT proof rows"), "SEIT-") + if field(contract, "Implementation role") != "Crewmate": errors.append(f"unsupported role: {slice_id}") + if field(contract, "Agent model route") not in ROUTES: errors.append(f"unsupported model route: {slice_id}") + if field(contract, "Agent reasoning level") not in REASONING: errors.append(f"unsupported reasoning: {slice_id}") + for label in ("Write set", "Command IDs", "Stop condition", "Human decision"): + if not field(manifest, label): errors.append(f"manifest {slice_id} missing {label}") + writes = field(manifest, "Write set") + paths = set(re.findall(r"`([^`]+)`", writes)) + if "no writes" not in writes.casefold() and ("only" not in writes.casefold() or not paths): errors.append(f"manifest {slice_id} has open write set") + scope = "bran" + owner = re.search(r"\bwithin the ([^.]+?) checkout\b", writes, re.I) + if owner: + scope = owner.group(1).casefold().strip() + wave = int(slice_id.split(".")[0]) + writes_by_wave.setdefault(wave, []).append((slice_id, {f"{scope}/{path}" for path in paths})) + expected_waves = set(range(1, max(writes_by_wave, default=0) + 1)) + if set(writes_by_wave) != expected_waves: errors.append("waves are not contiguous") + for row in sorted(set(rows) - claimed_rows - ROUTE_OWNED_ROWS): + errors.append(f"SEIT row has no implementation slice: {row}") + for wave, entries in writes_by_wave.items(): + if wave != 4: + continue + for index, (left_id, left) in enumerate(entries): + for right_id, right in entries[index + 1:]: + if any(a == b or a.startswith(b + "/") or b.startswith(a + "/") for a in left for b in right): + errors.append(f"overlapping parallel write sets: {left_id}, {right_id}") + # A literal claim state is only valid when a current receipt supplies all required fields. + for name in FILES: + if re.search(r"\bstatus\s*[:=]\s*[`\"]?passed\b", content[name], re.I): + errors.append(f"passed claim lacks current receipt evidence: {name}") + if errors: + for error in sorted(set(errors)): + print(f"FAIL: {error}") + return 1 + digest = hashlib.sha256() + for name in FILES: + digest.update(name.encode()); digest.update(b"\0"); digest.update((root / name).read_bytes()); digest.update(b"\0") + print(f"PASS: route=slices:{len(slices)} waves:{len(writes_by_wave)} plan_hash:{digest.hexdigest()}") + return 0 + + +if __name__ == "__main__": + raise SystemExit(main()) diff --git a/tools/cutover/verify_release.py b/tools/cutover/verify_release.py new file mode 100644 index 0000000..df8b2f6 --- /dev/null +++ b/tools/cutover/verify_release.py @@ -0,0 +1,114 @@ +#!/usr/bin/env python3 +"""Verify one complete local BRAN release without network or mutation.""" + +from __future__ import annotations + +import argparse +import hashlib +import json +import sys +from pathlib import Path + +sys.path.insert(0, str(Path(__file__).resolve().parents[1] / "ci")) +import release_contract_check as contract # noqa: E402 +import release_seal # noqa: E402 + + +def fail(message: str) -> int: + print(f"FAIL: {message}") + return 1 + + +def load_json(path: Path) -> object: + def unique_pairs(pairs: list[tuple[str, object]]) -> dict[str, object]: + result: dict[str, object] = {} + for key, value in pairs: + if key in result: + raise ValueError(f"duplicate JSON key: {key}") + result[key] = value + return result + + try: + return json.loads(path.read_text(encoding="utf-8"), object_pairs_hook=unique_pairs) + except (OSError, UnicodeDecodeError, json.JSONDecodeError, ValueError) as error: + raise ValueError(f"invalid manifest JSON: {error}") from None + + +def regular(path: Path, label: str) -> None: + if path.is_symlink(): + raise ValueError(f"symlink not permitted: {label}") + if not path.is_file(): + raise ValueError(f"not a regular file: {label}") + + +def sha256(path: Path) -> str: + digest = hashlib.sha256() + with path.open("rb") as source: + for chunk in iter(lambda: source.read(1024 * 1024), b""): + digest.update(chunk) + return digest.hexdigest() + + +def main() -> int: + parser = argparse.ArgumentParser(description=__doc__) + parser.add_argument("--manifest", required=True, type=Path) + parser.add_argument("--asset", required=True, type=Path, + help="one release asset; all seven are verified in its directory") + parser.add_argument("--source-sha", required=True) + parser.add_argument("--certificate-identity", required=True) + parser.add_argument("--certificate-oidc-issuer", required=True) + args = parser.parse_args() + manifest, selected = args.manifest, args.asset + try: + regular(manifest, "manifest") + regular(selected, "asset") + data = load_json(manifest) + errors = contract.validate_manifest(data) + if errors: + raise ValueError("manifest contract: " + "; ".join(sorted(errors))) + if not isinstance(data, dict): # kept explicit for type narrowing + raise ValueError("manifest root must be an object") + if args.source_sha != data["source_commit"]: + raise ValueError("source SHA mismatch") + if args.certificate_identity != data["signature"]["certificate_identity"]: + raise ValueError("signer certificate identity mismatch") + if args.certificate_oidc_issuer != data["signature"]["certificate_oidc_issuer"]: + raise ValueError("signer OIDC issuer mismatch") + tag = data["tag"] + names = contract.expected_asset_names(tag) + if selected.name not in names: + raise ValueError("--asset is not a release asset named by the manifest") + directory = selected.parent + disk_assets = {path.name for path in directory.iterdir() + if path.name.endswith((".tar.gz", ".zip"))} + expected_archives = set(names[:5]) + if disk_assets != expected_archives: + raise ValueError("missing or extra platform assets") + entries = {asset["name"]: asset for asset in data["assets"]} + for name in names: + path = directory / name + regular(path, name) + if sha256(path) != entries[name]["sha256"]: + raise ValueError(f"SHA-256 mismatch: {name}") + expected_sums = "".join(f"{sha256(directory / name)} {name}\n" + for name in sorted(names[:5])) + if (directory / "SHA256SUMS").read_text(encoding="utf-8") != expected_sums: + raise ValueError("SHA256SUMS does not match the five platform assets") + verified_identity, verified_issuer, verified_at = release_seal.verify_signature( + directory / "SHA256SUMS", directory / "SHA256SUMS.sigstore", + certificate_identity=args.certificate_identity, + certificate_oidc_issuer=args.certificate_oidc_issuer) + if verified_identity != data["signature"]["certificate_identity"]: + raise ValueError("verified signer certificate identity mismatch") + if verified_issuer != data["signature"]["certificate_oidc_issuer"]: + raise ValueError("verified signer OIDC issuer mismatch") + if verified_at != data["signature"]["signed_at"]: + raise ValueError("verified signature time mismatch") + except (OSError, ValueError, TypeError, KeyError) as error: + return fail(str(error)) + print("PASS: exact local release identity verified") + return 0 + + +if __name__ == "__main__": + raise SystemExit(main())