Skip to content

fix: accept documented rules plan gate only with complete evidence - #494

Merged
Wibias merged 2 commits into
mainfrom
fix/rules-plan-feature-unavailable
Nov 8, 2026
Merged

Wibias merged 2 commits into
mainfrom
fix/rules-plan-feature-unavailable

Conversation

@Wibias

@Wibias Wibias commented Nov 8, 2026

Copy link
Copy Markdown
Owner

Problem

ship-gate-snapshot treated every non-404 failure from the repository-rules endpoints as incomplete evidence. For a private repository on a plan without protected branches or rulesets, GitHub returns HTTP 403 with Upgrade to GitHub Pro or make this repository public to enable this feature. from /rulesets, /rules/branches/{branch}, and /branches/{branch}/protection. The gate therefore could never produce a non-unknown decision on Wibias/streamer-content.

Change

The snapshot now attempts an authoritative plan/feature-unavailable classification only when the rules read fails. It accepts that boundary only when all of the following agree:

  • the exact documented 403 message, HTTP status, and the endpoint's exact documentation URL from all three plan-gated reads;
  • repository metadata: private: true, visibility: "private";
  • branch metadata: protected: false, protection disabled, enforcement off, and no required status checks or contexts;
  • GraphQL branchProtectionRules complete and empty.

Everything else stays fail-closed: permission-denied 403, 401, 404, 5xx, mixed or ambiguous probes, malformed bodies, message variants, public repositories, protected branches, existing rules, and boundary drift during capture. The snapshot is still captured; the rules boundary is re-probed at the final boundary and must match. Existing rules and required checks continue to be derived and enforced, and snapshot replay revalidates the carried evidence before trusting it.

Evidence

  • node scripts/ship-gate-snapshot.mjs Wibias/streamer-content 863 -> complete snapshot; activeRules.complete=true with plan-feature evidence.
  • node scripts/ship-gate.mjs Wibias/streamer-content 863 -> decision: blocked (draft), unknowns: []; the rules boundary no longer forces unknown.
  • Targeted suites: 107 tests pass, including the new rules-boundary regression matrix.

Scope

Only the rules boundary capture, its evaluation guard, pagination failure passthrough, and the new regression tests change. No GitHub plan, visibility, permission, protection, required-check, or threshold changes.

@coderabbitai

coderabbitai Bot commented Nov 8, 2026 •

Copy link
Copy Markdown

Important

  • Trigger review

This repository does not receive automatic reviews because it has fewer than 10 stars.

Run configuration

  • Source mode: Auto
  • Repository: Unavailable
  • Branch: Unavailable
  • File: No configuration file from this repository applied
  • Commit: Unavailable
  • Layers: defaults
  • Review profile: CHILL
  • Plan: Advanced
  • Run ID: 2813328a-8040-4e39-9639-8db101639aa8
  • Autofix · Keep fixing CodeRabbit findings and required CI, and resolving merge conflicts

Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out.

Share

@Wibias
Wibias marked this pull request as ready for review November 8, 2026 03:33
@Wibias

Wibias commented Nov 8, 2026

Copy link
Copy Markdown
Owner Author

[GD] Verdict: approve-comment

TLDR

  • PR: #494 — fix: accept documented rules plan gate only with complete evidence
  • Head: 3b6b50ef on main (mergeStateStatus: CLEAN)
  • Decision: useful and ready to merge
  • Usefulness: Removes the false unknown that blocked every merge on Wibias/streamer-content: the gate now proves the documented plan/feature-unavailable boundary from independent reads instead of treating every rules 403 as incomplete.
  • Bugs: none blocking; 107 targeted tests pass on the change, including the new fail-closed matrix; a mutation check failed the spoof test when the message guard was removed.
  • Security: none; acceptance requires the exact documented 403 message, exact per-endpoint documentation URL, private repository metadata, unprotected branch metadata, and empty classic rules; permission, server, malformed, spoofed, and drifted evidence stays fail-closed.
  • Spec / standards: clean; the snapshot schema stays additive, release metadata is 1.9.1 with a changelog entry, and no plan, visibility, permission, protection, required-check, or threshold is changed.
  • Reviews: no human threads; CodeRabbit skipped the PR because the repository does not receive automatic reviews; the pre-open gate cleared 25/25 required evidence rows on this head.
  • Base / CI: green on 3b6b50ef; base main at b9869074; all required checks pass; live ship-gate.mjs is ready.
  • Gate: none.
  • Owner actions (foreign PR): none.
  • Bottom line: Ship it. The fix was verified against the real private repository, where the snapshot is now complete and the gate returns blocked only for the genuine draft state with zero unknowns.
Full verdict

Semantic propagation

  • Concepts audited: authoritative rules-boundary evidence, plan/feature-unavailable classification, snapshot source completeness, required-check and review-policy derivation, boundary drift, and snapshot replay validation.
  • Authoritative sources: scripts/lib/rules-boundary.mjs, scripts/ship-gate-snapshot.mjs, scripts/lib/snapshot-capture-payload.mjs, scripts/lib/snapshot-evaluators.mjs, and GitHub's live documented 403 payloads.
  • Producers and consumers checked: capture and boundary verification; ship-gate.mjs; merge-pr-driver.mjs recaptures; the Actions snapshot adapter; and every snapshot consumer that derives required checks or review policy.
  • Public/derived representations checked: snapshot sources, evidence.rulesBoundary, captureBoundary.rulesBoundaryFingerprint, snapshot integrity, changed-file scope, package version, and changelog entry.
  • Material variant partitions checked: public repository (rules readable), private paid plan, private plan without rulesets, explicit 404 protection with readable rules, permission-denied 403, 5xx, mixed probes, malformed payloads, public-repository spoof, protected branch, non-empty classic rules, and mid-capture drift.
  • Positive and negative assertions checked: 107 targeted tests pass; the spoof-rejection test fails when the exact-message guard is removed; a plan-feature snapshot without valid carried evidence evaluates to unknown.
  • Unmapped surfaces: GitHub Enterprise Server variants are intentionally unhandled and fail closed because their status, message, or documentation URL differs.
  • Unproven equivalence assumptions: none; the code commit is unchanged by the 1.9.1 metadata commit.
  • Representation mismatches: none.
  • Variant coverage gaps: none material; token/permission variance is covered by the fail-closed tests.
  • Axis verdict: pass

Usefulness

Before this head, ship-gate-snapshot treated every non-404 rules failure as incomplete, so a private repository on a plan without protected branches or rulesets could never produce a non-unknown decision. The live run on Wibias/streamer-content now produces a complete snapshot and ship-gate.mjs returns blocked for the draft with unknowns: []. The change is bounded to the rules boundary and its consumers.

Bugs / correctness

  • Method: static review of all eight changed files, the 107-test targeted run, the mutation check, and live snapshot/ship-gate dry runs against the real private repository.
  • Findings: none blocking. The accepted absence requires three exact documented endpoint responses plus structured repository, branch, and GraphQL corroboration; the final boundary is re-probed and fingerprinted.
  • Fail-closed paths: permission-denied 403, 401, 404, 5xx, non-JSON or unexpected payloads, duplicated or mismatched HTTP status, message or documentation-URL variants, public repositories, protected branches, non-empty classic rules, and changed evidence all remain unresolved.
  • Existing behavior: rules and required checks are still derived and enforced; a feature-unavailable marker without valid evidence evaluates to unknown.

Security

  • Scope reviewed: trust in GitHub error text, endpoint identity, repository visibility, branch protection metadata, snapshot replay, and argument construction.
  • Findings: none. The error text is compared, never executed; gh arguments remain array-passed; path segments are encoded; no secrets are added or printed; no permission, plan, visibility, protection, required-check, or authority boundary is changed.
  • Fixed this session: verified.

Spec / standards

  • Spec sources: repository policy kernel, mutation/evidence rules, references/versioning-release.md, and the snapshot schema.
  • Gaps: none. The snapshot change is additive; the release commit is version 1.9.1 with a consumer-facing changelog entry.

Reviews

  • Owners/maintainers: no open threads.
  • Bots: CodeRabbit skipped the PR (repository receives no automatic reviews).
  • Pre-open evidence: 25/25 lens, surface, and probe rows cleared on 3b6b50ef.

Base / CI

  • Head/base: 3b6b50ef on main b9869074; mergeStateStatus CLEAN.
  • Required CI: CodeQL (both languages), Node 22/24 on Linux, Node 24 on Windows, Dependency Review, and Windows trace bins all pass; the live ship gate is ready.

Gate

  • Draft/WIP/do-not-merge: cleared; the PR is non-draft.
  • Merge state: clean.

@Wibias
Wibias merged commit c6d4d0e into main Nov 8, 2026
13 checks passed
@Wibias
Wibias deleted the fix/rules-plan-feature-unavailable branch November 8, 2026 04:02
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant