Skip to content

docs(governance): add GOVERNANCE.md with the tag-ruleset record corrected - #204

Merged
PeterGuy326 merged 1 commit into
mainfrom
docs/governance-charter
Sep 11, 2026
Merged

PeterGuy326 merged 1 commit into
mainfrom
docs/governance-charter

Conversation

@PeterGuy326

Copy link
Copy Markdown
Collaborator

What this does

Adds GOVERNANCE.md, the release governance charter for this repository: branch
protection on main, refs/tags/v* immutability, the stricter bar for release-cut pull
requests, the CODEOWNERS policy, and an incident runbook.

It is additive. It does not change any workflow, setting, or rule, and it explicitly
subordinates itself to live repository configuration.

Why this is a new pull request rather than #125

#125 carries the same charter, but its head branch lives in a fork
(waterbro-8/mem). .github/workflows/bytefolk-security.yml:36 guards the codeql job
with:

if: ${{ github.event_name != 'pull_request' || github.event.pull_request.head.repo.full_name == github.repository }}

codeql needs security-events: write to upload SARIF, which GitHub does not grant to a
pull_request run from a fork, so skipping it there is correct. The problem is what
skipping produces. Because codeql is a matrix job skipped by a job-level if:, GitHub
never expands the matrix and publishes the check run under the literal, un-interpolated
name CodeQL (${{ matrix.language }}) with conclusion SKIPPED. That name matches none of
CodeQL (go), CodeQL (javascript-typescript), or CodeQL (python), which main
requires. Required contexts that are never reported are treated as pending forever.

So #125 cannot merge at any number of approvals. Update branch, auto-merge, and
re-running workflows all fail to change that. Re-pointing the work onto a branch inside
bytefolk/mem is the only resolution that needs no policy change and grants no new
permission, which is why this pull request exists.

#125 should be closed as superseded by this one.

What differs from #125's content

The charter is otherwise the same document, but four claims in its Tag immutability and
Incident runbook sections did not match the live configuration. They are corrected here.

1. "two active rulesets, neither of which has bypass actors" — false.

Ruleset Blocks Bypass actors
21888356 Protect stable release tags update, deletion none
21899500 Restrict stable release tag creation creation repository role admin (repositoryRoleDatabaseId 5), bypass_mode: always

Read from GET /repos/bytefolk/mem/rulesets/{id}, and confirmed via GraphQL
RepositoryRulesetBypassActor.repositoryRoleName, which returns the string admin
directly rather than an id that has to be interpreted.

The asymmetry is deliberate and is now stated as such: creation stays reachable so a
release can always be cut, while published tags are immutable for every role including
admin. Immutability is enforced by 21888356, not by 21899500.

2. "GitHub exposes no creation timestamp for rulesets" — false.

The individual ruleset endpoint returns created_at and updated_at, so the pair is
orderable: 21888356 at 2026-08-31T00:34:47Z, 21899500 at 2026-08-31T04:47:11Z
(updated 54 seconds later at 04:48:05Z). The charter previously declined to say which
rule came first on the strength of that incorrect premise.

3. "If no such path exists when a release is needed, that is a blocker" — a path exists.

A repository admin can cut a v* tag directly. v0.1.1 demonstrates it: annotated tag
object c2ecc1c49ff8bbe13b9d7800bc910e4b7ac99b74 dereferences to commit
cc727db0bc72655f299166de1f60756f5c686cc7 and is tagged 2026-08-31T06:32:10Z, one hour
and forty-five minutes after 21899500 became active, by a repository admin.

4. Incident runbook step 4 repeated claim 1.

This is the one with operational consequences. As drafted, a maintainer working a
compromised-release incident at 3am would have read that tag creation "has no bypass
actors" and that a missing creation path "is escalated, not worked around" — and would
have escalated a tag cut that a repository admin can simply perform. The step now says it
is an admin action that requires no ruleset change, and that no ruleset change should be
made in order to perform it.

Probable cause of the error, now recorded in the document. The collection endpoint
GET /repos/{owner}/{repo}/rulesets renders bypass_actors as null for every ruleset.
A reader who trusts that rendering concludes no bypass actors exist anywhere. The
corrected section names the per-ruleset endpoint explicitly so the mistake is harder to
repeat.

What was verified and left alone

All nine branch-protection values the charter asserts were re-read from
GET /repos/bytefolk/mem/branches/main/protection and are correct as written, so that
section is unchanged:

enforce_admins: true · required_approving_review_count: 1 ·
require_code_owner_reviews: true · dismiss_stale_reviews: true ·
require_last_push_approval: true · required_linear_history: true ·
required_conversation_resolution: true · allow_force_pushes: false ·
allow_deletions: false · bypass_pull_request_allowances: null

One sentence was added to that section to keep the two controls distinct: branch
protection having no bypass actors is a separate fact from tag creation having an admin
bypass, and conflating them is what makes claim 1 plausible on a first read.

The required-check enumeration in that section is unchanged and remains explicitly hedged
as "evidence of what runs, not a substitute for the configuration". It is dated 2026-09-03
and does not list CodeQL (go), CodeQL (javascript-typescript), CodeQL (python), or
Dependency review, all of which are in fact required on main today. The hedge already
covers this, but a reviewer who wants the list refreshed should say so rather than let it
stand as a near-miss.

Attribution

The charter's first commit (d2600211, aligning it with the enforced protections) and the
main-sync merges are PeterGuy326's. The commit tracking the live CODEOWNERS policy and
both tag rulesets (470babed, 2026-09-03) is waterbro-8's and is credited via
Co-authored-by. The four corrections above are mine and are not attributed to waterbro-8.

Checks

  • Docs-only. Adds one file, GOVERNANCE.md. No code, workflow, configuration, or
    dependency change, so no runtime behaviour is affected.
  • Title is Conventional and the body links #124 and #125 for pr-policy.
  • Head branch is inside bytefolk/mem, so codeql is not skipped and the three required
    CodeQL contexts will be reported normally.

Refs #124
Refs #125

GOVERNANCE.md as drafted in #125 made four claims about the refs/tags/v*
rulesets that do not match the live configuration:

1. "two active rulesets, neither of which has bypass actors" -- false.
   21899500 "Restrict stable release tag creation" has exactly one bypass
   actor: repository role admin (repositoryRoleDatabaseId 5),
   bypass_mode ALWAYS. 21888356 "Protect stable release tags" has none.
2. "GitHub exposes no creation timestamp for rulesets" -- false.
   GET /repos/{owner}/{repo}/rulesets/{id} returns created_at and
   updated_at, so the pair is orderable: 21888356 at
   2026-08-31T00:34:47Z, 21899500 at 2026-08-31T04:47:11Z.
3. "If no such path exists when a release is needed, that is a blocker" --
   a permitted creation path does exist for repository admins.
4. Incident runbook step 4 repeated claim 1 and told a maintainer that a
   missing creation path "is escalated, not worked around".

v0.1.1 demonstrates the admin creation bypass empirically: tag object
c2ecc1c -> commit
cc727db, tagged 2026-08-31T06:32:10Z,
1h45m after 21899500 became active, by a repository admin.

The likely source of the error is that the collection endpoint
GET /repos/{owner}/{repo}/rulesets renders bypass_actors as null for every
ruleset. The corrected section names the per-ruleset endpoint and the
GraphQL repositoryRoleName field so the next reader does not repeat it.

Claim 4 is the one that matters operationally: during a security incident
the runbook would have sent a maintainer to escalate a tag cut that an
admin can perform directly.

All nine branch-protection values asserted by the charter were re-read
against GET /repos/bytefolk/mem/branches/main/protection and are unchanged
and correct, so no edit was made there.

Refs #124
Refs #125

Co-authored-by: waterbro-8 <318569545+waterbro-8@users.noreply.github.com>
@sun-970

sun-970 commented Sep 11, 2026

Copy link
Copy Markdown
Contributor

Review: Suggested improvements

Overall document quality is high. Below are a few places that could be further polished:

1. Issue #81 missing link format

Problem: The Motivation section mentions Issue #81 as plain text, which does not use GitHub's issue reference format and will not auto-link. Meanwhile #124 and #125 in the same paragraph are correctly referenced.

Suggested fix: Change Issue #81 to #81 for consistency with the other issue references:

- 2. Issue #81 resolved the structurally unsatisfiable single-CODEOWNER setup
+ 2. #81 resolved the structurally unsatisfiable single-CODEOWNER setup

2. GOVERNANCE.md's own amendment process is not explicitly stated

Problem: The CODEOWNERS section explains how to modify the CODEOWNERS file, and the branch protection section records configuration values, but the process for changing the document itself is not stated. As a governance document, it should cover this.

Suggested fix: Add a short section at the end of the document (after the Incident runbook):

## Amendments

Changes to this document go through the same pull-request review process
described above. A governance change that weakens an existing control must
cite the decision authorizing the weakening.

3. "roughly four hours" mixed with precise timestamps

Problem: The Tag immutability section gives timestamps precise to the second (2026-08-31T00:34:47Z and 2026-08-31T04:47:11Z), immediately followed by "roughly four hours". The actual difference is 4h12m24s — mixing a vague statement with precise data leaves the reader unsure which is authoritative.

Suggested fix: Pick one and be consistent:

- `21888356` was created at `2026-08-31T00:34:47Z`, roughly four hours before
- `21899500` at `2026-08-31T04:47:11Z`
+ `21888356` was created at `2026-08-31T00:34:47Z`, 4 hours 12 minutes before
+ `21899500` at `2026-08-31T04:47:11Z`

Or if you prefer to stay approximate:

- `21888356` was created at `2026-08-31T00:34:47Z`, roughly four hours before
+ `21888356` was created at `2026-08-31T00:34:47Z`, approximately four hours before

4. Required status checks are enumerated at length but disclaimed as imprecise

Problem: The Branch protection section lists 13+ check names, then follows with "not presented here as the exact required set". The reader is left wondering: if the list is not guaranteed accurate, what is the point of enumerating them?

Suggested fix: Simplify — do not maintain a potentially stale list in the document:

- **Strict required status checks** (`strict: true`): every required check must pass on a
-   head that is up to date with `main` before a merge. The authoritative required-check list
-   is repository configuration readable only by administrators. As of 2026-09-03 the check
-   jobs observed on this repository are `Go`, `Worker`, `Web`,
-   `Conventional title and linked issue`, `Workflow, scripts and Compose`,
-   `PostgreSQL integration`, `Web memory and transfer acceptance`,
-   `HTTP, CLI and MCP lifecycle`, `Agent host MCP contract`, `Deployment profiles`,
-   `Offline recall benchmark`, `npm wrapper`, and `npm wrapper compatibility`
-   (`node18-linux`, `node20-linux`, `node24-windows`). That enumeration is evidence of what
-   runs, not a substitute for the configuration, and it is not presented here as the exact
-   required set.
+ **Strict required status checks** (`strict: true`): every required check must pass on a
+   head that is up to date with `main` before a merge. The authoritative required-check list
+   is maintained in repository settings and is readable only by administrators. As of
+   2026-09-03, required checks include CI jobs for Go, Worker, Web, integration tests,
+   and npm wrapper compatibility across multiple Node versions. The full list is
+   repository configuration, not reproduced here.

All minor improvement suggestions, none blocking merge. The document quality is high overall, particularly the API endpoint divergence notes and the practical value of the incident runbook.

@PeterGuy326

Copy link
Copy Markdown
Collaborator Author

Correction to this description

The body above states:

codeql needs security-events: write to upload SARIF, which GitHub does not grant to a pull_request run from a fork, so skipping it there is correct.

That is wrong, and #205 depends on the opposite being true.

bytefolk/digital-employee#250 is a fork pull request whose codeql-fork job declares permissions: security-events: write, contains no continue-on-error on the job or any step, and concluded success (check runs 102757987331, 102757703884). github/codeql-action/analyze returns HTTP 403 when security-events: write is absent, so a successful job conclusion means the SARIF upload succeeded. GitHub does grant that permission to fork pull_request runs. What fork runs never get is secrets and writable contents.

The consequence: the guard is not "correct but badly named". It is unnecessary. The un-interpolated check name described above is a real symptom, but the right fix is to remove the skip rather than work around its naming. That is #205 for this repository and bytefolk/.github#36 for the template; the mechanism and evidence are recorded in bytefolk/.github#35.

One qualification to this PR's stated rationale

This description says re-pointing onto a branch inside bytefolk/mem is "the only resolution that needs no policy change and grants no new permission". That was accurate when written and is no longer accurate: #205 also needs no policy change and grants no new permission.

This PR is still needed on its own merits. It is the only path that makes the GOVERNANCE.md charter from #125 mergeable now, whereas #205 helps fork PRs only after it merges and the fork branch is then updated. But this PR should not be read as an argument that #205 is unnecessary, or that the guard was a deliberate security decision worth preserving. It was neither.

Everything else in the description above — the four tag-ruleset corrections, the branch-protection re-reads, the attribution split and the note that #125 should be closed as superseded — stands unchanged.

@waterbro-8 waterbro-8 left a comment

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Independence disclosure, before anything else

I am posting an approving review, so the conflict comes first: I am waterbro-8, one of the two
reviewers requested on this pull request, and the head commit b5e7433bfe342b85656561ad1d03a17b4591be07
carries Co-authored-by: waterbro-8
. One of the commits it squashes (470babed, 2026-09-03,
docs(governance): track live CODEOWNERS policy and both tag rulesets) is mine.

That matters because this is the property the charter itself defines at the CODEOWNERS section —
"a pull request whose author is a CODEOWNER requires approval from another current CODEOWNER.
Self-approval … not permitted." I am not the commit author and not the last pusher
(author.login = committer.login = PeterGuy326, read from pulls/204/commits), so under
require_last_push_approval my vote is mechanically live. But whether a co-author may supply the
"independent" approval is a reading of this repo's own rule that I should not settle by casting the
vote and staying quiet about the overlap. @Bindy-lbb is the unambiguous signer for this one;
treat my approval as corroboration of the facts, not as the gate being satisfied.

Everything below is a live read taken while writing this, not carried over from an earlier round.

The PR's own thesis is true, and it is now measurable on both sides

This is the one thing I can add that is not in the body. The claim under dispute was "#125 cannot
merge at any number of approvals because a fork run never publishes the required CodeQL contexts."
Both sides of that experiment exist in this repository now:

head branch lives in check names published interpolated CodeQL contexts
7ee1cfbeb475 (#125, closed) waterbro-8/mem 17 none — one run literally named CodeQL (${{ matrix.language }}), conclusion skipped
a29e9163594b (#172, open) sun-970/mem 17 none — same literal name, same skipped
b5e7433bfe34 (this PR) bytefolk/mem 20 CodeQL (go), CodeQL (python), CodeQL (javascript-typescript) — all completed / success, plus Dependency review success

So the mechanism described at bytefolk-security.yml:36 (the job-level if: — I read line 36 and it
is that guard verbatim, with name: CodeQL (${{ matrix.language }}) on line 35) reproduces exactly as
written, and re-pointing the branch in-repo fixes it without any policy change. All 20 checks on this
head are success at attempt 1. The reason for this PR's existence is not rhetorical.

The four corrections: three verified end to end, one verified except for the role name

  • Ruleset asymmetry — verified. 21888356 Protect stable release tags blocks update + deletion
    with bypassActors.totalCount = 0; 21899500 Restrict stable release tag creation blocks creation
    with totalCount = 1. Both target: tag, enforcement: active, conditions include: ["refs/tags/v*"].
    The asymmetry the whole section is built on is real.
  • Timestamps — verified to the second. The REST endpoint returns +08:00; converted,
    21888356 is created 2026-08-31T00:34:47Z and 21899500 2026-08-31T04:47:11Z updated
    04:48:05Z — the "54 seconds later" and "roughly four hours" both hold (actual gap 4 h 12 m 24 s).
  • v0.1.1 as empirical proof — verified. Annotated tag object
    c2ecc1c49ff8bbe13b9d7800bc910e4b7ac99b74 dereferences to commit
    cc727db0bc72655f299166de1f60756f5c686cc7, tag date 2026-08-31T06:32:10Z, tagger PeterGuy326.
    That is 1 h 44 m 59 s after the creation restriction became active, i.e. a v* tag was created under
    an active creation block. Independent of any bypass-actor field, that is the proof.
  • Item 4 (the runbook consequence) — I agree this is the one with teeth, and it is the reason to
    take this PR over #125 rather than as a wording polish. A 3am reader was told to escalate something an
    admin can do. v0.1.0 itself being cut on 2026-08-30 (tag 17:08:32Z, release published 17:10:00Z)
    is consistent with the path existing all along.

One correction to the correction

The "probable cause" paragraph says the collection endpoint renders bypass_actors as null and that
the per-ruleset endpoint is the remedy. The endpoint is not the variable — caller privilege is.
As a non-admin (push=true / triage=true / maintain=false / admin=false):

  • GET /repos/bytefolk/mem/rulesets/21899500 — the individual endpoint — also returns
    bypass_actors: null. Following the charter's instruction does not recover the field.
  • GraphQL returns bypassActors { totalCount nodes } as 1 and [null]: the count is accurate,
    the node is redacted
    , so repositoryRoleName did not give me the string admin. It is readable to
    an admin, which is presumably how the body read it, but the sentence "GraphQL's repositoryRoleName
    … is the clearest check" will send a non-admin reader to a null.

Two things follow, and both are worth a line in the document: bypassActors { totalCount } is the
form of this check that works for the contributors who actually read governance docs, and the
sub-claim "which role holds the creation bypass" is not independently checkable by them — the
v0.1.1 tag establishes that an admin-reachable path exists, not the role id. The charter already
practices exactly this honesty one section earlier, where it says contributors without admin verify
enforce_admins "by observing that a merge is blocked, not by reading it". The tag section should
carry the same sentence; right now it points at a read that fails for them. Not blocking — the
conclusion is right and better-supported than #125's was.

A live collision this PR cannot merge through without someone deciding

#172 is open (mergeable_state=behind, 0 reviews, non-draft) and its GOVERNANCE.md is an
add, not a modify: main has no GOVERNANCE.md at 3e8acaeb1b8c. So #172 and #204 both create
the same path with different content — 100 lines, blob 5e191b9f9d8df171b16f3644c23328a92a695b1c
against 162 lines, blob 8c53b3b08ee5a09b61e1c25a39665800397cef61. A three-way merge with an empty
base returns one conflicting hunk, i.e. whichever merges second goes dirty, and this is the
CHANGELOG insertion-point shape this org has now hit seven times, arriving in a new file.

The cheap way out is already visible in this PR's own argument: #172's head is a fork head publishing
only the literal skipped CodeQL (${{ matrix.language }}) run, so by the mechanism documented above
it cannot merge at any approval count either. If #204 lands, #172's governance content needs to be
re-cut in-repo or dropped, and #172 also carries a change #204 does not — docs/maintainers/releasing.md
+5/−1 — which is the part of #172 worth not losing. I am not asking for that to be resolved inside this
PR; I am saying the merge order needs a decision recorded somewhere, and this thread is where I would
look for it.

Verification I could not perform — and the charter is up front about most of it

  • The ten branch-protection values are unreadable to me: GET /repos/bytefolk/mem/branches/main/protection
    returns 404 for my role, while GET /branches/main confirms only protected: true. The charter's
    own text discloses that limitation, so I record it as "not verified by this review" rather than as a defect.
  • The v0.1.0 "multiple create/delete cycles in one day" is not observable from outside — tag reflog is
    not exposed. It reads as an incident record, which is what a charter is for.
  • Whether those five contexts are the required set (as opposed to the set that ran) is admin-only,
    and the enumeration says so and hedges itself. I checked the hedge rather than trusting it: all
    15 names in the 2026-09-03 enumeration are still reported on today's head, so no entry in it has
    gone false; the omissions are exactly the four the body self-declares (CodeQL (go),
    CodeQL (python), CodeQL (javascript-typescript), Dependency review), plus the aggregate bare
    CodeQL name the body does not mention. Refreshing it is optional.

Two nits, neither worth a round trip

  1. The commit message and body both say "nine branch-protection values"; the list under that
    sentence has ten backticked values (bypass_pull_request_allowances: null being the tenth).
  2. "Issue #81 resolved … by adding a second owner" is right in substance — #81 closed
    2026-08-03T07:39:56Z — but the owner addition is the commit one second earlier,
    8f04bee079 chore: add @Bindy-lbb as code owner (#80). Crediting the PR alongside the issue makes
    the trail followable in one hop.

Status of the asks in this PR

#125 is already closed (closed_at = 2026-09-11T02:00:16Z, three minutes after this PR opened),
so the "should be closed as superseded" ask needs no action.

I approved, and nothing else: I did not merge, did not close #172 or anything else, did not
change labels or assignees, did not click Update branch, and did not touch any ref. #204 is
mergeable=true, base is current main tip 3e8acaeb1b8c, no conflict and no rebase needed — which
makes it the only PR in the open set whose blocker is reviews rather than state, and precisely the one
where my co-authorship is the thing to weigh before counting this ticket as the gate.

@PeterGuy326
PeterGuy326 merged commit 3c13f04 into main Sep 11, 2026
20 checks passed
@PeterGuy326
PeterGuy326 deleted the docs/governance-charter branch September 11, 2026 16:49
waterbro-8 added a commit that referenced this pull request Sep 17, 2026
## Canonical requirement

Refs bytefolk/.github#32

- Canonical Issue URL: bytefolk/.github#32
- Consumed revision: R1
- No automatic close keywords: acknowledged

Decision reference: the initial R1 Issue body. It explicitly records
that local candidates preceded this prospective publication record; no
retrospective approval is claimed.

## Requirement trace

| REQ/AC IDs | Changed files / domain | Tests or review evidence |
|---|---|---|
| REQ-001 / AC-001 | 4 exact-pinned version annotations | Exact
expected-byte replacement PASS |
| REQ-002 / AC-002 | 2 files in bytefolk/mem | Repository inventory
PASS; aggregate 7 repositories, 13 files, 21 lines |
| REQ-003 / AC-003 | Existing workflow content and modes | Parsed YAML
and comment-stripped bytes identical |
| REQ-004 / AC-004 | Current-head CI and independent review | Local
independent replay recorded in the canonical R1 Issue linked above;
hosted CI collected on head `f464f686` (19 of 20 checks succeed, see
Validation); independent human review requested and still pending |

## File domains

`.github/workflows/bytefolk-scorecard.yml` (47);
`.github/workflows/bytefolk-security.yml` (58, 65, 68).

Prepared parent / merge base: `2986fe38175f54d99f15dd38a498708c6ecd88cd`
PR base at publication: `87db0dfe0507be2190fe2fdcce0e267be8224f4d`.
Since that baseline `main` advanced by six commits through `3c13f04e`
(#162, #160, #165, #188, #158, #204) — not only `web/package-lock.json`
as previously stated here. None of them touched `.github/workflows/`, so
the F9 workflow blobs and the PR diff are unchanged. The reviewed commit
and original parent are preserved.
Head: `f464f68636adc6bb5295c3818aa6654c46a3caad` — `d2a9ec5` plus one
non-forced `Merge branch 'main'` commit (`f464f686`) that brought the
branch up to `3c13f04e` so it is no longer `BEHIND`. Verified: `git
rev-parse d2a9ec5:.github/workflows/bytefolk-scorecard.yml` and
`...:bytefolk-security.yml` return the same blobs (`2058126c`,
`48a507e0`) as at `f464f686`, and `git diff main...f464f68` is still
exactly these 2 files, `+4/-4`. The comment-only payload is therefore
byte-identical to the reviewed commit and the equality proof above holds
on the current head.

## Scope and non-goals

Correct only `# v4.37.4` to `# v4.37.9` on CodeQL uses-lines pinned to
`cdf488f595d80d6e07e03d4674febd5ab45fa938`. The [official tag
object](https://api.github.com/repos/github/codeql-action/git/tags/a35ac6e6798d72df5475948b28efb89edc2e19ca)
resolves to that existing pin. Action SHAs, permissions, triggers,
steps, matrices, other pins, and runtime code are unchanged.

## Validation

- Exact commands: `ruby evidence/verify.rb --baseline` and `ruby
evidence/verify.rb --committed` from the retained review packet; `git
diff --check 2986fe3
d2a9ec5` from this repository.
- Observed counts/results: PASS 2/2 files and 4/4 replacements here;
aggregate PASS 13/13 files and 21/21 replacements. Baseline
intentionally exits 1 after detecting all 21 stale annotations;
committed verification exits 0.
- Check URLs: collected on head `f464f686` — 19 of 20 checks succeed.
The single failure is [`HTTP, CLI and MCP
lifecycle`](https://github.com/bytefolk/mem/actions/runs/34807101354/job/103861020551),
whose log is `pull access denied for minio/minio` at ~13s: a
container-image pull failure in an unrelated job. The same workflow was
green on `main` at `3c13f04e`, and the identical failure is present on
#198 and #199, so it is not caused by this comment-only change.
Root-cause tracking is separate and open.

The strict verifier checks the changed-file allowlist; exact old blobs
and line inventory; complete expected-byte replacement; absence of stale
target annotations; parsed YAML equality; comment-stripped byte equality
and SHA-256 digests; whitespace and unchanged modes; one commit with the
exact parent; and clean worktrees with no untracked files. All passed.
The independent replay is recorded in canonical R1. The verifier and
inventory are retained outside repository commits.

| ID | REQ/AC | Observable acceptance criterion | Command or manual
steps | Environment | Expected | Observed | Status |
|---|---|---|---|---|---|---|---|
| V1 | AC-001, AC-002, AC-003 | Exact annotations with executable YAML
unchanged | `ruby evidence/verify.rb --committed` | Ruby 2.6.10, Psych
3.1.0, isolated review packet | Exact scoped replacements and equality |
2/2 files; 4/4 lines; all invariants pass | PASS |
| V2 | AC-004 | Hosted checks on this exact head | Inspect this PR's
checks at `f464f686` | GitHub Actions | Applicable checks succeed | 19
of 20 succeed; `HTTP, CLI and MCP lifecycle` fails on `pull access
denied for minio/minio` (infra, unrelated job, also failing on
#198/#199, green on `main`) | PARTIAL |

## Security and compatibility

Documentation annotation only. No dependencies, permissions,
credentials, data flows, or runtime behavior change. The diff and commit
identity were inspected for public-safe content. No CHANGELOG entry or
behavior-documentation update is needed because only explanatory
comments change.

## Known limitations

Runtime suites, build, coverage, and dependency audits were not rerun
for this comment-only change; no runtime test result is claimed. Hosted
CI is separate from local equality proof. Two limits now apply: (1) the
strict verifier's `one commit with the exact parent` invariant describes
the reviewed payload commit `d2a9ec5`, not the current branch shape,
which carries two additional `Merge branch 'main'` commits; (2) this PR
is **not merge-ready yet** — repository `AGENTS.md` step 6 requires
passing CI *and* an approval from someone other than the author, and
`HTTP, CLI and MCP lifecycle` is red on the unrelated `minio` pull, so
the green-CI half is unmet until that infrastructure failure is fixed.

## Risk and rollback

Low-risk annotation correction. Roll back through an ordinary revert of
this single commit. There is no migration or release action.

## Product review handoff

- Implementation/publication owner: @PeterGuy326
- Automated pre-review result: independent local replay recorded in R1;
no human approval implied.
- Human final review: PENDING; no human review requested by this
publication.
- Merge ledger owner: @PeterGuy326
- Product reviewer: @PeterGuy326
- Milestone or release packet: N/A: bounded documentation annotation
maintenance
- Merge, CI, release, and model judgment do not accept or close the
Issue: acknowledged


## Maintenance update (2026-09-14, @waterbro-8)

Records written by the maintainer account, not by the implementation
owner:

- `f464f686 Merge branch 'main'` was pushed to this head branch
(non-forced, `main` at `3c13f04e` is an ancestor of the head) to clear
the `BEHIND` state this PR's own body said blocked merging. No workflow
file content changed: both blobs are identical to `d2a9ec5`.
- The stale facts above were corrected in place: the recorded head SHA,
the "Main advanced only `web/package-lock.json` in PR #192" claim, the
`NOT VERIFIED` hosted-CI rows, and the "this is a draft, not
merge-ready" note.
- This PR was marked ready for review and an independent review was
requested. The maintainer account that pushed the merge commit did
**not** approve it: `AGENTS.md` step 6 requires an approval from someone
other than the author, and a commit author on the head cannot supply
that approval for their own push. `@PeterGuy326` remains implementation
and merge-ledger owner.

Co-authored-by: 勒布朗-詹姆斯 <2986253039@qq.com>
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.

3 participants