diff --git a/ARCHITECTURE.md b/ARCHITECTURE.md index 9b23ef9f0..fe287389b 100644 --- a/ARCHITECTURE.md +++ b/ARCHITECTURE.md @@ -12,6 +12,7 @@ This file is the canonical product-wide topology and bounded-context view. It is - [Requirement, decision, standards, and implementation traceability](docs/traceability/README.md) - [Research and standards doctoring](docs/doctoring.md) - [Product roadmap](docs/product-roadmap.md) +- [Live product and technical gap baseline](docs/product-technical-gap-baseline.md) Protected-main code and executable tests define current implementation truth; deployed build/release artifacts, migrations, and configuration are additional operational evidence when they exist. Accepted ADRs define design authority, not proof that planned behavior has shipped. The PRD/TRD/diagrams may also contain `Planned`, `Proposed`, or `Open` product direction; those labels must remain explicit until corresponding implementation and review evidence reaches protected `main`. diff --git a/CHANGELOG.md b/CHANGELOG.md index d17419927..9846f6968 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -6,6 +6,9 @@ All notable changes to OriginWeave are documented in this file. The format follo ### Added +- Refreshed the product and technical gap baseline with the 2026-08-24 live inventory: 158 open pull requests (44 ready, 114 draft), refreshed exact base/head evidence for the #208–#222 release, enterprise-approval, BAP, and WARC/PROV chains, the governance issue additions #212 and #215, and a required-check provider-failure record for the fail-closed Strix re-dispatches on #208/#218/#220. +- Added a dated product and technical gap baseline that separates protected-main implementation truth, active pull-request evidence, live review/check blockers, and the next buyer-visible Phase 1 acceptance work. +- Refreshed the product and technical gap baseline with the current open-PR inventory and exact base/head evidence for the newest Chromium, BAP, extraction, WARC, and idempotency slices. - Bound explicit extension-to-Agent grants to exclusive trusted-time expiry in addition to extension identity, session, browsing context, and canonical origin, so a same-origin grant cannot be reused at or after the deadline. - Bound explicit extension-to-Agent grants to the exact canonical origin in addition to extension identity, session, and browsing context, so a same-session navigation or port change cannot reuse the grant. - Rust workspace for independently reusable core, policy, destination, network, TLS, resource, and evidence modules. @@ -41,8 +44,16 @@ All notable changes to OriginWeave are documented in this file. The format follo - Updated the first Chromium slice to distinguish implemented origin, destination, direct TCP, and TLS identity kernels from the remaining trusted DNS adapter, proxy/PAC, HTTP budget, MIME, download, and Chromium integration required before safe navigation can be claimed. - Separated hourly product PR publication authority from the organization review and merge system, and added live default-branch and release-blocker rechecks immediately before publication. - Made the agent-development contract work-conserving: completing one bounded slice, RCA, review request, check, merge, or documentation change is an intermediate state; maintenance must return to the live queue, treat waits as item-local, and perform a mandatory exit sweep before terminating while executable OriginWeave work remains. +- Hardened the dated baseline evidence collector with fail-fast isolated artifacts, paginated branch and collaborator rules, and post-collection exact-head revalidation. +- Flattened every paginated workflow-run page in the baseline merge verdict so exact-head evidence cannot silently discard later runs. +- Hardened the baseline evidence procedure with exact-head legacy status and workflow-run capture, counted approval binding, required-workflow recording, merge verdict artifacts, and bounded moving-head retries. - Moved autonomous-agent Cargo targets and Python bytecode caches outside the proposed source tree and prefetched locked Cargo dependencies for offline verification. - Updated research doctoring to pin Chromium canonicalizer evidence to an immutable revision, add RFC 9293, RFC 5280, RFC 8446, RFC 9525, rustls 0.23.42, and Rust `TcpStream` evidence, distinguish the April 2026 Fugu beta from the June 2026 release, and treat vendor benchmark claims as first-party evidence rather than independent validation. +- Tightened the product-baseline contract so the BiDi opening path and VPN/profile evidence retain their explicit not-shipped status within their own documentation sections. +- Refreshed the product and technical gap baseline against the 2026-08-21 live inventory: 150 open pull requests, 110 drafts, and the new hardened-runner/MV3 evidence gap issue #206. +- Tightened the baseline completion-gap contract so superseded inventory counts (including the 2026-08-21 150/40/110 snapshot) can no longer pass as current evidence. +- Refreshed the baseline's merge-authority statement to the live ruleset: two approving reviews are required, while the collaborator inventory still contains only the solo maintainer. +- Corrected the baseline evidence collector to flatten every paginated input, apply current reviewer and last-push approval semantics, and discard verdicts when either the PR head or base moves. ### Security diff --git a/docs/README.md b/docs/README.md index 03b573c54..775dd0de6 100644 --- a/docs/README.md +++ b/docs/README.md @@ -22,6 +22,7 @@ - [OriginWeave API and protocol contract](API_CONTRACT.md) - [Release and rollback contract](RELEASE_AND_ROLLBACK.md) - [Product roadmap](product-roadmap.md) +- [Product and technical gap baseline](product-technical-gap-baseline.md) - [Research and standards](doctoring.md) - [Browser and Agent protocol standards evidence](doctoring/browser-agent-protocols.md) - [Current product-baseline standards addendum](doctoring/product-documentation-baseline.md) diff --git a/docs/product-technical-gap-baseline.md b/docs/product-technical-gap-baseline.md new file mode 100644 index 000000000..234e6ae5c --- /dev/null +++ b/docs/product-technical-gap-baseline.md @@ -0,0 +1,325 @@ +# Product and Technical Gap Baseline + +This is a dated delivery baseline, not a substitute for the PRD, TRD, roadmap, architecture decisions, or live GitHub state. It keeps buyer-visible gaps, current issues, active pull-request evidence, and commercial completion tracks in one discoverable place. Protected `main` is the implementation boundary: code in an open pull request is not shipped behavior. + +## Observed snapshot: 2026-08-24 + +### Protected-main truth + +- Protected `main` remained at `0841d2ab3d8b5e60a03c0a8e818cf438e2716829` when this snapshot was refreshed. +- Phase 0 is documented as complete as a reusable safety-kernel foundation: typed policy contracts, destination classification, direct TCP peer verification, TLS service identity, evidence bounds, resource mitigation, document-node authority, and protected-main tests. +- Phase 1 is **in progress**, not shipped. The first real Chromium vertical slice still needs the active WebDriver BiDi transport stack to reach protected `main`, then compose isolated Chromium launch, session/context identity, semantic observation, typed action authorization, native browser input, post-condition proof, evidence, cancellation, crash recovery, and profile/process teardown. +- HTTP/1.1 bounds, downloads/MIME, proxy/PAC consumption, full browser-network integration, the sensitive-data broker runtime, durable WARC/PROV capture, persistent task/API surfaces, signed cross-platform distribution, enterprise administration, and release-grade buyer acceptance remain open. +- Active pull requests remain evidence, not shipped behavior. Successful checks on a feature or stacked branch do not prove that protected `main` contains the capability or that a child can merge before its prerequisite. + +### Open pull requests + +The live repository contained **158 open pull requests: 44 non-draft and 114 draft** when this snapshot re-paginated the complete open inventory. The volume and stack depth are themselves a product-delivery risk: review, exact-head checks, dependency order, and integration truth can drift faster than a buyer-visible vertical slice reaches protected `main`. + +Representative active workstreams at this snapshot were: + +| Workstream | Representative active PR evidence | Delivery boundary | +|---|---|---| +| Product baseline | #196 | Ready/non-draft documentation PR; all exact-head checks passed and review threads resolved, blocked only by the reviewer-provisioning gap below | +| Enterprise approval authority | #220 | Ready/non-draft bounded maker-checker approval lifecycle on the exact `ApprovalScope`; Strix re-scan was re-dispatched after a provider-unavailability failure | +| Release artifact identity | #218 and #219 | Ready/non-draft fail-closed benchmark release decision and canonical release manifest binding; #218's Strix re-scan was re-dispatched after provider unavailability | +| Evidence path conformance | #216 | Ready/non-draft RFC 3986 evidence-path syntax enforcement | +| Schema-bound extraction and BAP lifecycle | #209 and #208 | Ready/non-draft schema-bound extraction contract and resumable task-lifecycle kernel; #208's Strix re-scan was re-dispatched after provider unavailability | +| WebDriver BiDi transport | #188 through #205 | Draft stack exercising framed `locateNodes` exchange over a bounded WebSocket opening path; still no authenticated browser-process provenance, semantic task execution, or protected-main shipment | +| MCP adapter | #168 and #170 | Typed MCP routing and conservative `tools/list` metadata are active-PR foundations; complete authenticated transport, durable task lifecycle, cancellation/resume, and browser execution remain open under #200 | +| Controlled Chromium and recovery | #65, #70-#73, #100, #105, #142-#153 and descendants | Real pinned-browser fixture, semantic location, resource, crash, and teardown evidence exists on active stacks; evidence does not transfer across heads or prerequisites | +| Durable WARC/PROV evidence | #210, #217 | Bounded WARC resource records and PROV JSON-LD binding are draft active-PR foundations; durable ownership, replay, retention/deletion, and browser side-effect reconciliation remain open | +| Manifest V3 and native messaging | #27 and its active extension/native-host stack, including #154 and #169 | Compatibility and Agent-authority isolation remain incomplete until exact release artifacts and platform matrices are proven | +| Sensitive-data and model route policy | #10 and its active policy stacks | Deterministic policy values exist, but trusted broker execution, retention/deletion, runtime isolation, and auditable product workflows remain open | +| VPN/profile intent | #149 | Bounded WireGuard/IKEv2 profile authority is active-PR evidence; it does not create a tunnel, route, DNS state, authenticated gateway, or connectivity proof | + +Draft PR #205 is the current top WebDriver BiDi locate-nodes slice; its opening-path prerequisites #195 and #198 remain draft evidence and cannot be treated as shipped behavior. + +#### Current exact-head active PR evidence + +The following newest product slices were re-fetched from GitHub for this snapshot. Their exact base/head pairs are recorded so later checks, reviews, and restacks cannot be confused with predecessor evidence: + +| PR | State | Exact base head | Exact head | +|---|---|---|---| +| #73 | Draft | `da99395b09b419845b4a1222a0725482e9231466` | `7861d88d21ed0f0adaeb467957e809826f835071` | +| #208 | Draft | `0841d2ab3d8b5e60a03c0a8e818cf438e2716829` | `c3b6e1a475dce333f6115e5113cae9c07974835f` | +| #209 | Draft | `0841d2ab3d8b5e60a03c0a8e818cf438e2716829` | `69bc738bd45a1b61a4673b122dc3eec8814baa22` | +| #210 | Draft | `69bc738bd45a1b61a4673b122dc3eec8814baa22` | `999979a511c3a890ba93a1a09da8810858877940` | +| #211 | Draft | `c3b6e1a475dce333f6115e5113cae9c07974835f` | `f6e3a3adcfb9cc7a60ef1d79e2aeee27ba54c084` | + +These rows are delivery evidence only. #73's latest Strix remediation is locally verified but its required policy workflows remain queued; #208–#211 are stacked product-gap foundations with no protected-main promotion. None has counted independent approval in the current collaborator inventory. + +#### Refreshed exact-head active PR evidence: 2026-08-24 + +The following newest slices were re-fetched from GitHub for this snapshot. Heads have moved since the 2026-08-21 rows above; those predecessor rows are retained as regression anchors and must never be promoted to current-head evidence: + +| PR | State | Exact base head | Exact head | +|---|---|---|---| +| #222 | Draft | `56fcfa56525e4f2e980e0ee05b6776d621bcddc5` | `1e2ce3d4071a1a75ee891bdcd71c506b3b50d4bc` | +| #221 | Draft | `8145d40f1b028a8f4dc7e7da47ac89bb9e5bb2c7` | `6f339df1e5b3ddb265f4ddd7b262d4de1e0b5e1f` | +| #220 | Ready | `0841d2ab3d8b5e60a03c0a8e818cf438e2716829` | `ed4cab16cf88c76ce1c145a22d0a274ef2d57263` | +| #219 | Ready | `0841d2ab3d8b5e60a03c0a8e818cf438e2716829` | `8145d40f1b028a8f4dc7e7da47ac89bb9e5bb2c7` | +| #218 | Ready | `0841d2ab3d8b5e60a03c0a8e818cf438e2716829` | `49e98fba6974219b3bb0336c822b12667f1e1c03` | +| #217 | Draft | `529d11a3571f6b1834b9baa49ef67eb08f043978` | `56fcfa56525e4f2e980e0ee05b6776d621bcddc5` | +| #216 | Ready | `0841d2ab3d8b5e60a03c0a8e818cf438e2716829` | `75130851a0f7ce528a7a36382eb026ac7942a0aa` | +| #214 | Draft | `40d642d5470a7753b8211907c190367f742f2f12` | `f79999681866ecf0e5fe17d895170f3f6cae7361` | +| #211 | Draft | `85cc477688246900697f4cfb91c0c8f1f692934a` | `40d642d5470a7753b8211907c190367f742f2f12` | +| #210 | Draft | `c38b9665774d6b3754e572bed527737b5e179833` | `529d11a3571f6b1834b9baa49ef67eb08f043978` | +| #209 | Ready | `0841d2ab3d8b5e60a03c0a8e818cf438e2716829` | `c38b9665774d6b3754e572bed527737b5e179833` | +| #208 | Ready | `0841d2ab3d8b5e60a03c0a8e818cf438e2716829` | `85cc477688246900697f4cfb91c0c8f1f692934a` | + +The stack topology shows #209 → #210 → #217 → #222 (WARC/PROV chain), #208 → #211 → #214 (BAP chain), #218 → #221 → #220 (release/enterprise chain) at this snapshot. Every row above remains active-PR evidence; none is protected-main behavior. + +### Required-check provider failure record + +On 2026-08-23 the required Strix security scan failed closed on exact heads of #220 (`ed4cab16…`), #218 (`49e98fba…`), and #208 (`85cc4776…`) because its LLM provider/backend was unavailable (rate limit, token cap, connection, warm-up, or model-behavior failure); no vulnerability report artifact was produced, so the workflow correctly refused to convert an incomplete scan into passing security evidence. Failed jobs were re-dispatched on the unchanged exact heads on 2026-08-24. This is a provider-infrastructure failure record, not a weakening of the fail-closed gate or a substitute for a completed authoritative scan. + +#### #195/#198 WebDriver BiDi opening path status + +Phase 1 is **in progress**, not shipped. #195 and #198 provide bounded WebSocket opening-path evidence on active branches; framed BiDi commands, authenticated browser-process provenance, semantic task execution, and protected-main integration remain open. + +#### #149 VPN/profile intent status + +It remains draft evidence and cannot be treated as shipped behavior. #149 describes bounded WireGuard/IKEv2 profile authority, but it does not create a tunnel, route, DNS state, authenticated gateway, or connectivity proof. + +The current queue must be processed in dependency order. A green child branch cannot substitute for current checks and review on its prerequisite, synthetic merge, or eventual protected-main commit. PRs that only duplicate, supersede, or preserve stale branch topology should be closed with explicit replacement evidence rather than retained indefinitely. + +### Review and merge authority + +The active `CWL Central required workflows` ruleset requires two approving reviews, approval after the last push, resolved review threads, and configured required workflows. The current collaborator inventory contains only `seonghobae` with administration and push permissions, creating a **reviewer-provisioning gap** for counted non-author approval. + +This gap does not authorize self-approval, administrative bypass, stale-head merge, or weaker checks. Exact current-head checks, security gates, complete coverage, rustdoc/Clippy, thread resolution, and branch protection remain mandatory. Before any merge decision, re-fetch the exact ruleset, collaborators, PR head/base, reviews, unresolved threads, and required checks; do not assume this dated observation remains current. + +### Open issues and operational signals + +| Issue | Current gap or signal | +|---|---| +| #28 | First real Chromium Agent Task vertical slice; highest immediate Phase 1 buyer-visible gap | +| #27 | Complete Manifest V3 compatibility and extension-authority isolation matrix | +| #9 | Bounded HTTP/1.1 semantics over the authenticated TLS stream | +| #10 | Purpose-bound operational PII disclosure and trusted broker/storage lifecycle | +| #123 | Fleet incident: disable orphaned TLS, HTTP, and one-shot workflow identities | +| #187 | Manual-authority review of the coverage-diagnostics workflow delta | +| #212 | Governance: remove or independently authorize the PR #43 MV3 workflow mutation | +| #215 | Governance: restore an enforceable protected-main policy that does not create a routine admin bypass | +| #199 | Schema-bound extraction with durable WARC/PROV replay, retention, deletion, and offline verification | +| #200 | Stable BAP/MCP runtime API with authenticated, idempotent, cancellable, resumable task lifecycle | +| #201 | Signed cross-platform Chromium distribution, installer/updater, patch SLA, rollback, SBOM, and provenance | +| #202 | Enterprise control and experience plane: operator UI, Keyverse-compatible identity, tenancy, approval, audit, SLO, Figma, and Storybook | +| #203 | Release-grade web-agent benchmark and commercial acceptance gate bound to exact signed artifacts | + +Issue #206 (harden-runner custom detection initialization failure) was closed after its remediation landed on protected `main` between snapshots. + +The five newly separated product-completion tracks are **durable WARC/PROV replay**, **stable BAP/MCP runtime API**, **signed cross-platform Chromium distribution**, **enterprise control and experience plane**, and the **commercial acceptance gate**. They are separate issues because each has a distinct authority, data, release, and buyer-acceptance boundary. + +The hourly product-development loop is operational infrastructure, not proof that a browser product, issue, pull request, or release meets buyer acceptance. + +## Buyer-visible and technical gap matrix + +| Priority | Buyer-visible outcome | Protected-main status | Completion issue and acceptance evidence | +|---|---|---|---| +| P0 | A bounded task observes a real Chromium page, performs one typed action, verifies the post-condition, and emits provenance | **Open / Phase 1** | #28; repeated real Chromium E2E with isolated context, exact session/node authority, typed dispatch, post-condition, crash cleanup, and protected-main checks | +| P0 | Navigation consumes approved origin, resolution, route, TCP peer, TLS identity, bounded HTTP, redirect, MIME, and download policy | **Partial foundation** | #9 plus #28; real browser-network adapter proves the governed path is consumed end to end | +| P1 | Existing Chromium extensions remain compatible while Agent authority stays separate | **Partial active-PR evidence** | #27; exact supported-build/platform compatibility matrix, managed allow-list, native-host isolation, repeatability, and release binding | +| P1 | Authorized work can use necessary PII without ambient exposure | **Policy foundation; runtime open** | #10; opaque broker, exact field/purpose/destination/model policy, atomic use/revocation, retention/deletion, and value-free telemetry | +| P1 | Every released structured field is traceable to replayable source evidence | **Foundations only** | #199; durable WARC/PROV replay, integrity, retention, deletion, offline verification, extraction precision/recall, and 100% provenance completeness | +| P1 | External Agents integrate through a stable, authenticated product contract | **Partial active-PR MCP primitives** | #200; BAP 1.0, MCP 2026-07-28 adapter, idempotency, task cancellation/resume, checkpoint/reconciliation, and SDK conformance | +| P1 | Buyers can install, update, verify, and roll back a supported product | **Not shipped** | #201; signed Windows/macOS/Linux/headless artifacts, Chromium revision manifest, updater security, patch SLA, SBOM, SLSA provenance, and recovery | +| P1 | Enterprise teams can provision, approve, audit, operate, and recover the service | **Not shipped** | #202; Keyverse-compatible OIDC/SCIM, tenant isolation, policy/approval/evidence UI, SLO/incident controls, data residency, CSAP/SOC 2 evidence mapping, WCAG 2.2, Figma File ID, and Storybook | +| P0 | A release has reproducible proof of usefulness, safety, evidence completeness, and recovery | **No product-wide release gate** | #203; deterministic, compatibility, adversarial, recovery, and enterprise suites with statistical reporting and an exact-artifact commercial acceptance gate | +| P0 | Valid changes reach protected `main` without authority improvisation or unbounded stack growth | **Blocked / high integration debt** | Shrink the 158-PR queue in dependency order, provision legitimate review authority, require exact-current evidence, and close duplicates/superseded branches | + +## Commercial completion definition + +OriginWeave is not complete merely because every low-level primitive exists in some open branch. A release candidate is commercially complete only when all of the following are true for the declared support profile: + +1. #9, #10, #27, and #28 are integrated on protected `main` as a complete browser/network/action/evidence chain. +2. #199 provides replayable, retention-governed evidence for every released structured result. +3. #200 exposes a stable authenticated runtime API and task lifecycle without raw Chromium authority leakage. +4. #201 produces signed, updateable, rollback-capable release artifacts bound to Chromium, SBOM, and provenance. +5. #202 supplies tenant-safe enterprise administration, approvals, audit, SLOs, incident recovery, accessible Figma/Storybook-backed UX, and control evidence. +6. #203 accepts the exact signed artifacts through a reproducible benchmark; missing or inconclusive evidence cannot be promoted to success. +7. Production function, line, region, and branch coverage and public API documentation remain exactly complete for OriginWeave-owned code. +8. CHANGELOG, version, supported-platform matrix, security policy, runbooks, licensing, release notes, upgrade/rollback guidance, and procurement evidence match the exact release. +9. No required check, browser/platform lane, security case, benchmark case, or independent review is skipped, stale, inherited, or represented by status-only evidence. +10. The open PR queue is reduced to bounded active work rather than being the only place where the product exists. + +## Next executable queue + +1. Re-fetch all 158 open PRs and compute the dependency graph, exact heads/bases, reviews, unresolved threads, current required checks, duplicate/supersession relationships, and branch ancestry. Re-dispatch required checks that failed closed on provider infrastructure instead of code defects. +2. Integrate merge-ready root PRs first; restack and independently revalidate only the immediate children. Close obsolete alternatives instead of carrying parallel truth. +3. Finish the #9/#28 browser-network and Chromium vertical slice, including the #195/#198 WebSocket opening path and the remaining framed BiDi command/response, semantic observation, policy, action, post-condition, and recovery boundaries. +4. Finish #27 and #10 as separate security tracks; neither should be hidden inside the first browser PR. +5. Implement #199, then #200, so durable evidence and stable task authority precede broad enterprise integrations. +6. Implement #201 before making release/support claims; exact CI browser evidence must be bound to the actual signed artifact. +7. Design #202 in Figma, record the Figma File ID in the ADR, implement reusable design tokens and Storybook components, then add identity/tenant/approval/audit/operations integration. +8. Make #203 the final release gate across the exact signed distribution, not a source branch or model narrative. +9. Only after the commercial acceptance gate passes, increment the version, finalize CHANGELOG/release notes, publish signed artifacts, and verify upgrade/rollback from the prior supported release. + +## Evidence commands + +The volatile counts above are reproducible by paginating the complete open-PR inventory, flattening every page, and then inspecting each PR's exact head, checks, reviews, and review threads: + +```bash +set -euo pipefail +EVIDENCE_DIR="$(mktemp -d /tmp/originweave-evidence.XXXXXX)" +printf 'Evidence directory: %s\n' "$EVIDENCE_DIR" >&2 + +gh api --paginate --slurp 'repos/ContextualWisdomLab/OriginWeave/pulls?state=open&per_page=100' \ + > "$EVIDENCE_DIR/open-pr-pages.json" +jq '[.[][]]' "$EVIDENCE_DIR/open-pr-pages.json" \ + > "$EVIDENCE_DIR/open-prs.json" +jq '{ + open_pull_requests: length, + non_draft: (map(select(.draft == false)) | length), + draft: (map(select(.draft == true)) | length) +}' "$EVIDENCE_DIR/open-prs.json" + +gh api 'repos/ContextualWisdomLab/OriginWeave/branches/main' \ + > "$EVIDENCE_DIR/main-branch.json" +gh api --paginate --slurp \ + 'repos/ContextualWisdomLab/OriginWeave/rules/branches/main?per_page=100' \ + > "$EVIDENCE_DIR/main-branch-rule-pages.json" +jq '[.[][]]' "$EVIDENCE_DIR/main-branch-rule-pages.json" \ + > "$EVIDENCE_DIR/main-branch-rules.json" +gh api --paginate --slurp \ + 'repos/ContextualWisdomLab/OriginWeave/collaborators?affiliation=all&per_page=100' \ + > "$EVIDENCE_DIR/collaborator-pages.json" +jq '[.[][]]' "$EVIDENCE_DIR/collaborator-pages.json" \ + > "$EVIDENCE_DIR/collaborators.json" + +jq -r '.[].number' "$EVIDENCE_DIR/open-prs.json" | while read -r PR; do + STABLE_HEAD=false + for ATTEMPT in 1 2 3; do + VERDICT_PATH="$EVIDENCE_DIR/pr-${PR}-merge-verdict.json" + VERDICT_TMP="$EVIDENCE_DIR/pr-${PR}-merge-verdict.json.tmp" + rm -f "$VERDICT_PATH" "$VERDICT_TMP" "$EVIDENCE_DIR/pr-${PR}-rechecked.json" + PR_JSON="$EVIDENCE_DIR/pr-${PR}.json" + gh api "repos/ContextualWisdomLab/OriginWeave/pulls/$PR" > "$PR_JSON" + HEAD_SHA=$(jq -r '.head.sha' "$PR_JSON") + BASE_SHA=$(jq -r '.base.sha' "$PR_JSON") + + gh api --paginate --slurp \ + "repos/ContextualWisdomLab/OriginWeave/commits/$HEAD_SHA/check-runs?per_page=100" \ + > "$EVIDENCE_DIR/pr-${PR}-check-runs.json" + gh api --paginate --slurp \ + "repos/ContextualWisdomLab/OriginWeave/commits/$HEAD_SHA/statuses?per_page=100" \ + > "$EVIDENCE_DIR/pr-${PR}-statuses.json" + gh api --paginate --slurp \ + "repos/ContextualWisdomLab/OriginWeave/pulls/$PR/reviews?per_page=100" \ + > "$EVIDENCE_DIR/pr-${PR}-reviews.json" + gh api --paginate --slurp \ + "repos/ContextualWisdomLab/OriginWeave/actions/runs?head_sha=$HEAD_SHA&per_page=100" \ + > "$EVIDENCE_DIR/pr-${PR}-workflow-runs.json" + gh api graphql --paginate --slurp \ + -F owner=ContextualWisdomLab \ + -F name=OriginWeave \ + -F number="$PR" \ + -f query=' +query($owner: String!, $name: String!, $number: Int!, $endCursor: String) { + repository(owner: $owner, name: $name) { + pullRequest(number: $number) { + reviewThreads(first: 100, after: $endCursor) { + nodes { id isResolved isOutdated } + pageInfo { hasNextPage endCursor } + } + } + } +}' > "$EVIDENCE_DIR/pr-${PR}-review-threads.json" + + jq -n \ + --arg head "$HEAD_SHA" \ + --slurpfile pr "$PR_JSON" \ + --slurpfile checks "$EVIDENCE_DIR/pr-${PR}-check-runs.json" \ + --slurpfile statuses "$EVIDENCE_DIR/pr-${PR}-statuses.json" \ + --slurpfile reviews "$EVIDENCE_DIR/pr-${PR}-reviews.json" \ + --slurpfile workflow_runs "$EVIDENCE_DIR/pr-${PR}-workflow-runs.json" \ + --slurpfile rules "$EVIDENCE_DIR/main-branch-rules.json" \ + --slurpfile collaborators "$EVIDENCE_DIR/collaborators.json" \ + --slurpfile threads "$EVIDENCE_DIR/pr-${PR}-review-threads.json" \ + --arg base "$BASE_SHA" \ + '( + [ + $rules[][]? + | select(.type == "pull_request") + | .parameters + ] | first // {} + ) as $pull_request_parameters + | ( + [ + $reviews[][][]? + | {reviewer: .user.login, state, submitted_at, commit_id} + | select(.submitted_at != null) + | select(.reviewer != $pr[0].user.login) + | select(.reviewer as $reviewer | + any($collaborators[][]?; + .login == $reviewer and + (.permissions.push == true or + .permissions.maintain == true or + .permissions.admin == true))) + ] + | group_by(.reviewer) + | map(sort_by(.submitted_at) | last) + | map(select(.state == "APPROVED" and .commit_id == $head)) + ) as $current_approvals + | ($pull_request_parameters.required_approving_review_count // 0) as $required_review_count + | ($pull_request_parameters.require_last_push_approval // false) as $require_last_push_approval + | { + head_sha: $head, + base_sha: $base, + required_status_checks: { + check_runs: [$checks[][].check_runs[]?], + legacy_statuses: [$statuses[][][]?] + }, + workflow_runs: [$workflow_runs[][].workflow_runs[]?], + counted_approvals: ($current_approvals | length), + required_approving_review_count: $required_review_count, + require_last_push_approval: $require_last_push_approval, + last_push_approval_authority: ( + if $require_last_push_approval == true + then "github_rule_evaluation_required" + else "not_required" + end + ), + approval_gate_satisfied: ( + if $pull_request_parameters.require_last_push_approval == true then false + else (($current_approvals | length) >= $required_review_count) + end + ), + required_workflows: [ + $rules[][]? + | select(.type == "workflows") + | .parameters.workflows[] + ], + unresolved_threads: [ + $threads[][].data.repository.pullRequest.reviewThreads.nodes[]? + | select(.isResolved == false and .isOutdated == false) + ] + }' > "$VERDICT_TMP" + + RECHECKED_PR_JSON="$EVIDENCE_DIR/pr-${PR}-rechecked.json" + RECHECKED_HEAD_SHA=$(gh api "repos/ContextualWisdomLab/OriginWeave/pulls/$PR" \ + | tee "$RECHECKED_PR_JSON" \ + | jq -r '.head.sha') + RECHECKED_BASE_SHA=$(jq -r '.base.sha' "$RECHECKED_PR_JSON") + if [[ "$RECHECKED_HEAD_SHA" == "$HEAD_SHA" && "$RECHECKED_BASE_SHA" == "$BASE_SHA" ]]; then + mv "$VERDICT_TMP" "$VERDICT_PATH" + mv "$RECHECKED_PR_JSON" "$PR_JSON" + STABLE_HEAD=true + break + fi + rm -f "$VERDICT_TMP" "$RECHECKED_PR_JSON" + printf 'Discarding moving head/base evidence for PR #%s (head %s -> %s, base %s -> %s) and retrying.\n' \ + "$PR" "$HEAD_SHA" "$RECHECKED_HEAD_SHA" "$BASE_SHA" "$RECHECKED_BASE_SHA" >&2 + done + if [[ "$STABLE_HEAD" != true ]]; then + rm -f "$EVIDENCE_DIR"/pr-${PR}-*.json + printf 'Unable to collect stable exact-head/base evidence for PR #%s after 3 attempts.\n' "$PR" >&2 + exit 1 + fi +done +``` + +The branch-scoped rules response determines the active rules affecting `main`; each PR's exact `HEAD_SHA` then determines which check runs, legacy statuses, workflow runs, reviews, and unresolved threads are current. The saved merge verdict binds counted approvals to the latest review per eligible collaborator, excludes the PR author, and requires `APPROVED` on the exact head. It deliberately does **not** infer GitHub's actual last-push actor from commit author or committer metadata: when `require_last_push_approval` is active, this portable evidence procedure records `github_rule_evaluation_required` and keeps `approval_gate_satisfied` false until GitHub's authoritative rule evaluation is consulted. The saved PR JSON also preserves the exact base reference and branch ancestry input for the dependency graph. Evidence is retained only when both `RECHECKED_HEAD_SHA` and `RECHECKED_BASE_SHA` match the collected values; a moving head or base discards the temporary verdict, and three failed attempts leave no unstable merge verdict. + +For standards and binding architecture, use [`doctoring.md`](doctoring.md), [`doctoring/browser-agent-protocols.md`](doctoring/browser-agent-protocols.md), [`PRD.md`](PRD.md), [`TRD.md`](TRD.md), [`product-roadmap.md`](product-roadmap.md), and linked ADR/UML/ERD/traceability records. Issues #199-#203 contain their own APA 7th standards and research traceability. This baseline intentionally records delivery state and never promotes planned adapters or active pull-request code to implemented behavior. \ No newline at end of file diff --git a/tests/test_documentation_active_pr_evidence_contract.py b/tests/test_documentation_active_pr_evidence_contract.py index d2a067e50..34e8a0238 100644 --- a/tests/test_documentation_active_pr_evidence_contract.py +++ b/tests/test_documentation_active_pr_evidence_contract.py @@ -8,6 +8,8 @@ DOCS = ROOT / "docs" FITNESS = DOCS / "DOCUMENTATION_FITNESS.md" MATURITY = DOCS / "evidence" / "2026-08-10-active-pr-maturity.md" +BASELINE = DOCS / "product-technical-gap-baseline.md" +CHANGELOG = ROOT / "CHANGELOG.md" def active_pr_row(text: str, pr_number: int) -> str: @@ -28,6 +30,31 @@ class ActivePullRequestDocumentationContractTests(unittest.TestCase): def setUpClass(cls) -> None: cls.fitness = FITNESS.read_text(encoding="utf-8") cls.maturity = MATURITY.read_text(encoding="utf-8") + cls.baseline = BASELINE.read_text(encoding="utf-8") + cls.changelog = CHANGELOG.read_text(encoding="utf-8") + + def test_latest_live_pr_snapshot_is_recorded_in_the_product_baseline(self) -> None: + """The baseline must preserve exact heads for the newest active product slices.""" + for marker in ( + "Current exact-head active PR evidence", + "| #73 | Draft | `da99395b09b419845b4a1222a0725482e9231466` | `7861d88d21ed0f0adaeb467957e809826f835071` |", + "| #208 | Draft | `0841d2ab3d8b5e60a03c0a8e818cf438e2716829` | `c3b6e1a475dce333f6115e5113cae9c07974835f` |", + "| #209 | Draft | `0841d2ab3d8b5e60a03c0a8e818cf438e2716829` | `69bc738bd45a1b61a4673b122dc3eec8814baa22` |", + "| #210 | Draft | `69bc738bd45a1b61a4673b122dc3eec8814baa22` | `999979a511c3a890ba93a1a09da8810858877940` |", + "| #211 | Draft | `c3b6e1a475dce333f6115e5113cae9c07974835f` | `f6e3a3adcfb9cc7a60ef1d79e2aeee27ba54c084` |", + ): + with self.subTest(marker=marker): + self.assertIn(marker, self.baseline) + + def test_baseline_refresh_changelog_matches_the_live_snapshot(self) -> None: + """The changelog must classify and state the same baseline refresh.""" + refresh = "Refreshed the product and technical gap baseline with the current open-PR inventory" + added = self.changelog.split("### Added", 1)[1].split("### Changed", 1)[0] + changed = self.changelog.split("### Changed", 1)[1].split("### Security", 1)[0] + self.assertIn(refresh, added) + self.assertNotIn(refresh, changed) + self.assertIn("150 open pull requests, 110 drafts", self.changelog) + self.assertNotIn("150 open pull requests, 112 drafts", self.changelog) def test_dependency_stacks_are_explicit_and_non_shipped(self) -> None: """Current browser, network, sensitive and compatibility stacks stay active-only.""" diff --git a/tests/test_product_completion_gap_contract.py b/tests/test_product_completion_gap_contract.py new file mode 100644 index 000000000..839393f30 --- /dev/null +++ b/tests/test_product_completion_gap_contract.py @@ -0,0 +1,111 @@ +"""Regression contract for the dated commercial-completion gap baseline.""" + +from __future__ import annotations + +import pathlib +import unittest + +ROOT = pathlib.Path(__file__).resolve().parents[1] +BASELINE = ROOT / "docs/product-technical-gap-baseline.md" + + +class ProductCompletionGapContractTests(unittest.TestCase): + """Keep the exact repository snapshot and completion tracks reviewable.""" + + def test_baseline_records_current_inventory_and_completion_issues(self) -> None: + """The dated baseline must not retain superseded queue counts or omit buyer tracks.""" + text = BASELINE.read_text(encoding="utf-8") + + for phrase in ( + "158 open pull requests", + "44 non-draft", + "114 draft", + "#198", + "#199", + "#200", + "#201", + "#202", + "#203", + "durable WARC/PROV replay", + "stable BAP/MCP runtime API", + "signed cross-platform Chromium distribution", + "enterprise control and experience plane", + "commercial acceptance gate", + ): + with self.subTest(phrase=phrase): + self.assertIn(phrase, text) + + for stale_phrase in ( + "100 open pull requests", + "22 non-draft", + "78 draft", + "148 open pull requests", + "79 draft PRs", + "150 open pull requests", + "40 non-draft", + "110 draft", + ): + with self.subTest(stale_phrase=stale_phrase): + self.assertNotIn(stale_phrase, text) + + def test_evidence_commands_reproduce_inventory_checks_and_review_state(self) -> None: + """The evidence procedure must paginate the queue and inspect each exact PR head.""" + text = BASELINE.read_text(encoding="utf-8") + evidence = text.split("## Evidence commands", 1)[1].split("\n## ", 1)[0] + shell = evidence.split("```bash", 1)[1].split("```", 1)[0] + + for phrase in ( + "--paginate --slurp 'repos/ContextualWisdomLab/OriginWeave/pulls?state=open&per_page=100'", + "set -euo pipefail", + 'EVIDENCE_DIR="$(mktemp -d /tmp/originweave-evidence.XXXXXX)"', + '"$EVIDENCE_DIR/open-pr-pages.json"', + "jq '[.[][]]' \"$EVIDENCE_DIR/open-pr-pages.json\"", + '"repos/ContextualWisdomLab/OriginWeave/pulls/$PR"', + '"repos/ContextualWisdomLab/OriginWeave/commits/$HEAD_SHA/check-runs?per_page=100"', + '"repos/ContextualWisdomLab/OriginWeave/commits/$HEAD_SHA/statuses?per_page=100"', + '"repos/ContextualWisdomLab/OriginWeave/pulls/$PR/reviews?per_page=100"', + '"repos/ContextualWisdomLab/OriginWeave/actions/runs?head_sha=$HEAD_SHA&per_page=100"', + "check_runs: [$checks[][].check_runs[]?],", + "legacy_statuses: [$statuses[][][]?]", + "workflow_runs: [$workflow_runs[][].workflow_runs[]?],", + "reviewThreads(first: 100, after: $endCursor)", + "rules/branches/main?per_page=100", + '"$EVIDENCE_DIR/main-branch-rule-pages.json"', + '"$EVIDENCE_DIR/collaborator-pages.json"', + '"$EVIDENCE_DIR/collaborators.json"', + '"$EVIDENCE_DIR/pr-${PR}-merge-verdict.json.tmp"', + '.state == "APPROVED"', + ".submitted_at != null", + ".commit_id == $head", + "group_by(.reviewer)", + "required_approving_review_count", + "require_last_push_approval", + "last_push_approval_authority", + '"github_rule_evaluation_required"', + "if $pull_request_parameters.require_last_push_approval == true then false", + "$pr[0].user.login", + '.type == "workflows"', + ".parameters.workflows", + "required_status_checks", + '"$EVIDENCE_DIR/pr-${PR}-merge-verdict.json"', + "for ATTEMPT in 1 2 3; do", + "RECHECKED_HEAD_SHA=", + "RECHECKED_BASE_SHA=", + 'if [[ "$RECHECKED_HEAD_SHA" == "$HEAD_SHA" && "$RECHECKED_BASE_SHA" == "$BASE_SHA" ]]; then', + ): + with self.subTest(phrase=phrase): + self.assertIn(phrase, shell) + + self.assertNotIn("while :; do", shell) + self.assertNotIn("/tmp/originweave-open-pr", shell) + self.assertNotIn("check_runs: [$checks[]?.check_runs[]?],", shell) + self.assertNotIn("legacy_statuses: [$statuses[][]?]", shell) + self.assertNotIn("workflow_runs: [$workflow_runs[]?.workflow_runs[]?],", shell) + self.assertNotIn("$reviews[][]?\n | select(.state", shell) + self.assertNotIn("head-commit.json", shell) + self.assertNotIn("$head_commit[0].committer.login", shell) + self.assertNotIn("$head_commit[0].author.login", shell) + + +if __name__ == "__main__": + unittest.main() diff --git a/tests/test_product_documentation_contract.py b/tests/test_product_documentation_contract.py index 1313189ea..5a1c1133c 100644 --- a/tests/test_product_documentation_contract.py +++ b/tests/test_product_documentation_contract.py @@ -11,6 +11,14 @@ class ProductDocumentationContractTests(unittest.TestCase): """Keep product requirements, technical design, diagrams, and traceability discoverable.""" + @staticmethod + def _subsection(text: str, heading: str) -> str: + """Return one fourth-level documentation subsection.""" + start = text.index(heading) + len(heading) + remainder = text[start:] + end = remainder.find("\n#### ") + return remainder if end == -1 else remainder[:end] + def test_authoritative_product_documentation_graph_exists(self) -> None: """Major product decisions must not require reconstructing chat or PR history.""" required_paths = { @@ -25,10 +33,50 @@ def test_authoritative_product_documentation_graph_exists(self) -> None: "docs/OPERABILITY.md", "docs/API_CONTRACT.md", "docs/RELEASE_AND_ROLLBACK.md", + "docs/product-technical-gap-baseline.md", } missing = sorted(path for path in required_paths if not (ROOT / path).is_file()) self.assertEqual(missing, []) + def test_product_technical_gap_baseline_records_live_delivery_state(self) -> None: + """Buyers and maintainers must see implementation gaps and current delivery blockers together.""" + baseline = ROOT / "docs/product-technical-gap-baseline.md" + self.assertTrue(baseline.is_file()) + text = baseline.read_text(encoding="utf-8") + for phrase in ( + "Observed snapshot: 2026-08-24", + "Protected-main truth", + "Open pull requests", + "Open issues", + "#195", + "#149", + "reviewer-provisioning gap", + "Phase 1", + ): + with self.subTest(phrase=phrase): + self.assertIn(phrase, text) + + protected_main = text.split("### Open pull requests", 1)[0] + open_pull_requests = text.split("### Open pull requests", 1)[1].split( + "### Review and merge authority", 1 + )[0] + self.assertIn("Phase 1 is **in progress**, not shipped.", protected_main) + self.assertIn( + "It remains draft evidence and cannot be treated as shipped behavior.", + open_pull_requests, + ) + bidi_status = self._subsection( + open_pull_requests, "#### #195/#198 WebDriver BiDi opening path status" + ) + vpn_status = self._subsection( + open_pull_requests, "#### #149 VPN/profile intent status" + ) + self.assertIn("Phase 1 is **in progress**, not shipped.", bidi_status) + self.assertIn( + "It remains draft evidence and cannot be treated as shipped behavior.", + vpn_status, + ) + def test_root_architecture_links_the_authoritative_product_graph(self) -> None: """Architecture readers must be able to reach requirements, decisions, diagrams, and data.""" architecture = (ROOT / "ARCHITECTURE.md").read_text(encoding="utf-8") @@ -39,6 +87,7 @@ def test_root_architecture_links_the_authoritative_product_graph(self) -> None: "docs/uml/README.md", "docs/erd/README.md", "docs/traceability/README.md", + "docs/product-technical-gap-baseline.md", ): with self.subTest(link=link): self.assertIn(link, architecture)