Skip to content

D209 — an attested project's CI reads the record it judges - #373

Merged
napkinstack-agent[bot] merged 2 commits into
mainfrom
d209-attested-record-read-in-ci
Nov 7, 2026
Merged

napkinstack-agent[bot] merged 2 commits into
mainfrom
d209-attested-record-read-in-ci

Conversation

@napkinstack-agent

@napkinstack-agent napkinstack-agent Bot commented Nov 7, 2026 •

Copy link
Copy Markdown
Contributor

Closes #367

What it changes

flowchart LR
    A["nstack attest<br/>(workstation)"] -->|"notes pushed"| R["remote<br/>refs/notes/nstack/checks"]
    R -->|"fetch, job token in git's env"| C["pr-check in CI"]
    C -->|"record passed"| G["compliant"]
    C -->|"no record / failed"| F["FAIL A1 / A2"]
    C -.->|"remote unreadable"| W["WARNING A1, why"]
Loading

Legend — solid: what happens when the remote answers; dotted: when it does not. Before this change, CI stopped at attested — judged where nstack attest runs, not in CI and printed "compliant" whatever the head held.

  • attest.read_remote lists then fetches the remote's notes; fetch_env puts the job's token in git's environment (http.https://github.com/.extraheader), only towards GitHub, never in an argument a log shows. The remote holding no notes at all counts as read: no record.
  • pull_request.check_attested judges the record in CI as on a workstation (A1, A2); an unreadable remote is a warning that names why. The A1 action says the check reads again on a push or an edit of the description.
  • skeleton/.github/workflows/pull-request.yml already gives the job GH_TOKEN (D208) and contents: read; the comment now says the read covers the record.
  • 07-governance.md §7 and RULES.md A1 say it; workstreams.md row D209.

For a project taking it: a pull request opened before nstack attest turns red until its head is attested and the check runs again — the behaviour the rule always described.

Oracle

  • Written before the implementation: five tests in platform/tests/test_attest.py.
  • Seen failing: 5 failed before the change (the record never read under CI; the silent line).
  • Passes now: test_attest.py 44 passed; uv run bash platform/tests/run.sh → see VERIFIED.

Summary

DONE

  • CI reads the attested record from the remote's notes and judges A1/A2; an unread remote is a warning.

VERIFIED

  • New tests: a record pushed with the notes, read by a fresh checkout under CI (compliant, names the attester); no record on the remote (FAIL A1, not "compliant"); a failed record (FAIL A2); no remote (WARNING A1, never the old line); the credential only in the environment, only for github.com.

  • Oracle: uv run bash platform/tests/run.sh → Platform tests: OK.

  • Independent verifier (fresh session), at 80f8adc after its findings at a8f40dd were fixed (the token was also sent on a workstation, where an expired one refused the fetch; a refusing remote untested; git's reason a fragment; no mask): 48 tests; mutants killed — ls-remote or fetch failure read as read, env not passed, CI guard, mask, github.com guard, fatal line, the old early return; three minor survivors (an action's wording, a condition unreachable in CI, an equivalent index).

  • Probed on a private repository: under GITHUB_ACTIONS, no credential helper, an installation token in GH_TOKEN → notes read (11); no token or an expired one → warning with git's fatal: reason; on a workstation with the remote's helper and a stale GH_TOKEN → notes read. The raw token appears nowhere; only the masked base64 in ::add-mask::, under CI.

ASSUMED

  • The job's own github.token behaves as the App installation token probed (both installation tokens, same header) — the first project that takes the version runs it.

NOT VERIFIED

  • A real run on a project's forge: the first project that takes the version proves it (its "Test sheet and cycle" job, attested and unattested heads).

RISKS

  • A head attested after its push stays red until the next event (push, description edit) — said in the A1 action.

🤖 Generated with Claude Code

On a fourth project, a pull request whose head nobody had attested read
"compliant" on the forge: check_attested returned before reading anything
under GitHub Actions. CI now fetches the remote's notes with the job's
token, carried in git's environment and only towards GitHub, and refuses an
unattested head (A1) or a failed record (A2). A remote it cannot read is a
warning naming why, never the silent line.

Closes #367

Agent-Session: eos-1689a973
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
@napkinstack-agent
napkinstack-agent Bot requested a review from a team as a code owner November 7, 2026 15:07
The token was sent on a workstation too, where an expired one refused the
fetch before the remote's own credential could answer: it now goes only
under GitHub Actions, masked as hold's fetch masks it. A remote that
refuses, notes listed but not fetched, and the token reaching git are
tested; git's reason is its fatal line, not a fragment.

Agent-Session: eos-1689a973
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
@napkinstack-agent
napkinstack-agent Bot merged commit 6de0975 into main Nov 7, 2026
3 checks passed
@napkinstack-agent
napkinstack-agent Bot deleted the d209-attested-record-read-in-ci branch November 7, 2026 15:28
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.

pr-check on the forge says compliant for a head with no attested record (A1 silent in CI)

1 participant