How GrantTrace works

Understand scenario coverage, evidence sources, and deterministic solving.

The claim

GrantTrace answers a narrow question:

Which GitHub App REST permissions do these named, recorded scenarios demonstrably require?

That boundary matters. GrantTrace does not infer unexecuted paths, intercept arbitrary HTTP traffic, inspect GraphQL, or prove that production behavior is fully covered. Automatic recording observes supported Node.js global fetch calls to exactly https://api.github.com, including standard Octokit traffic. Off-origin requests are ignored even when a response imitates GitHub's permission header. Requests that bypass the global-fetch path are outside the result unless they use GrantTrace's explicit adapter.

Scenarios make coverage explicit

Each recording has a stable, lowercase scenario name such as issue-triage. Routes in the contract retain the names of the scenarios that exercised them. This lets a reviewer tell the difference between a permission change and a coverage change.

Local recordings are kept under .granttrace/observations/. They are input to check, not an append-only history. Recording the same name replaces its previous successful observation set.

record then solves the aggregate contract and presents the same diff as check. An interactive terminal can explicitly accept it in place. A noninteractive run never accepts and exits 6 when review is required.

Two evidence sources

For every recognized canonical route, GrantTrace can use:

  1. GitHub's runtime X-Accepted-GitHub-Permissions response header, accepted by automatic capture only from https://api.github.com.
  2. A pinned offline catalog reviewed against official GitHub documentation for API version 2026-03-10.

When both sources exist, they must agree after canonicalization. Agreement keeps both provenance labels. Disagreement, malformed runtime evidence, an unknown route, or an unsupported API blocks the contract.

A missing runtime header may fall back only to a known catalog entry. Missing evidence never means “no permission required.”

Off-origin traffic does not create an automatic observation and cannot force a runtime/catalog contradiction. This origin boundary prevents a local or third-party server from manufacturing GitHub runtime evidence.

Permission alternatives stay exact

GitHub expresses requirements as disjunctive normal form:

issues=write; pull_requests=write

The semicolon means OR. A comma means AND:

contents=read, pull_requests=read

Within a permission, write satisfies read. Different permission names are not interchangeable.

GrantTrace retains every nondominated sufficient assignment in permissionFrontier. For a new contract, it selects one deterministic default assignment by preferring:

  1. fewer write permissions;
  2. lower total access weight;
  3. fewer distinct permissions; and
  4. lexical order.

This is a stable default review policy, not a universal definition of optimal access. granttrace frontier list displays every complete candidate, and granttrace frontier select NUMBER can explicitly persist another candidate as selectedPermissions. Checks retain that choice while it remains in the recomputed frontier. If it becomes invalid, the deterministic default appears as an ordinary blocking contract diff and still requires explicit acceptance.

What gets committed

granttrace.lock.json contains:

  • tool, API, schema, and catalog identity;
  • scenario names and canonical route templates;
  • canonical permission requirements and evidence provenance;
  • route-to-scenario attribution;
  • selected permissions and the full nondominated frontier;
  • separately documented manual keeps; and
  • safe blocking findings.

The mandatory metadata:read baseline participates in solving and live-token validation but is not presented as observed selected access.

What stays local

GrantTrace does not intentionally store raw URLs, query strings, request or response bodies, commands, tokens, private keys, owners, repositories, or resource identifiers in observations, contracts, or proof reports.

See the protocol for the normative model and security and privacy for the trust boundary.