forked from heavy-duty/ceremony
Compare commits
1 commit
main
...
release-0.
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
ba3b17af88 |
19 changed files with 420 additions and 467 deletions
2
.github/workflows/labels-sweep.yml
vendored
2
.github/workflows/labels-sweep.yml
vendored
|
|
@ -63,7 +63,7 @@ on:
|
|||
env:
|
||||
# A called workflow arrives without its repository. Keep this literal pin
|
||||
# aligned with the ceremony release consumed by callers (issue #9 D3).
|
||||
CEREMONY_SELF_REF: "0.6.0"
|
||||
CEREMONY_SELF_REF: "0.6.1"
|
||||
|
||||
jobs:
|
||||
reconcile:
|
||||
|
|
|
|||
2
.github/workflows/labels.yml
vendored
2
.github/workflows/labels.yml
vendored
|
|
@ -48,7 +48,7 @@ on:
|
|||
env:
|
||||
# A called workflow arrives without its repository. Keep this literal pin
|
||||
# aligned with the ceremony release consumed by callers (issue #9 D3).
|
||||
CEREMONY_SELF_REF: "0.6.0"
|
||||
CEREMONY_SELF_REF: "0.6.1"
|
||||
|
||||
jobs:
|
||||
scope:
|
||||
|
|
|
|||
2
.github/workflows/release.yml
vendored
2
.github/workflows/release.yml
vendored
|
|
@ -129,7 +129,7 @@ env:
|
|||
# `ref:` accepts ${{ env }}; `uses:` strings do not — which is why the
|
||||
# shared logic arrives as script files via checkout, not as inner `uses:`
|
||||
# references.
|
||||
CEREMONY_SELF_REF: "0.6.0"
|
||||
CEREMONY_SELF_REF: "0.6.1"
|
||||
VERSION_SOURCE: ${{ inputs.version-source }}
|
||||
|
||||
jobs:
|
||||
|
|
|
|||
416
CHANGELOG.md
416
CHANGELOG.md
|
|
@ -22,6 +22,422 @@ section is deliberately not carried — the tag published here is the one this
|
|||
section is the body of. Each sync updates this line
|
||||
(docs/UPSTREAM-SYNC.md, #200).
|
||||
|
||||
## 0.6.1 — 2026-08-09
|
||||
|
||||
### Added
|
||||
|
||||
- `test/labels-bootstrap.test.sh` pins the bridge at every hop: the declared
|
||||
boundary, both gate sites as the identity, no expression reading
|
||||
`github.event.inputs`, and the caller and stub pass-throughs
|
||||
byte-exact (#215).
|
||||
|
||||
- The same test drives the four value paths — schedule-empty, `no`, `yes`,
|
||||
invalid — through the shipped expressions into the action's real
|
||||
validator (#215).
|
||||
|
||||
- The taxonomy bootstrap keys on the `BOOTSTRAP` input, never the event name.
|
||||
It tested `GITHUB_EVENT_NAME = workflow_dispatch` — correct while an
|
||||
operator's manual dispatch was the only dispatch there was, inert-by-
|
||||
construction from #209 on, when every machine wake became a dispatch
|
||||
event (#215).
|
||||
|
||||
- The venue drill caught that: with the bridge delivering `no` perfectly,
|
||||
drill runs 16/17 still bootstrapped, because the script never read the
|
||||
input the whole chain existed to deliver (#215).
|
||||
|
||||
- `test/labels-reconcile.test.sh` pins the regression pair exactly: a
|
||||
`workflow_dispatch` event with `BOOTSTRAP=no` (or unset) creates and
|
||||
deletes nothing; only `BOOTSTRAP=yes` bootstraps (#215).
|
||||
- A gather-level case drives the real board read against a Forgejo-shaped
|
||||
fixture — every entry carrying the key. The existing discriminator cases
|
||||
assert `jq` expressions in isolation and passed throughout this regression
|
||||
(#210).
|
||||
|
||||
- A source pin forbids `has("pull_request")` on this surface, because the rule
|
||||
was stated in a comment and violated forty lines below it. It strips comments,
|
||||
so the #188 warning that explains the trap is allowed to stay (#210).
|
||||
|
||||
- All three sites are covered behaviourally, not only by the pin: the board
|
||||
gather, the release-body gather through an observable window flag, and the
|
||||
per-issue payload check (#210).
|
||||
- `test/forge-backends.test.sh` pins each backend's path **and** field, because
|
||||
a stubbed `forge_api` cannot catch a wrong path — which is how this shipped
|
||||
and why a live sweep was what found it (#209).
|
||||
- `test/labels-dispatch.test.sh` extracts the shipped step and executes it
|
||||
against a recording stub, asserting the method, endpoint, ref and
|
||||
`inputs.bootstrap` actually sent (#205).
|
||||
|
||||
- That test also drives the failure path: any non-204 still fails the job, so
|
||||
the misconfiguration alarm the trigger exists to be cannot decay into a
|
||||
warning (#205).
|
||||
|
||||
- An unset `GITHUB_API_URL` refuses before any request instead of defaulting
|
||||
to `api.github.com`. Guessing sent this forge's dispatch to GitHub and
|
||||
reported success — the "Never 'probably github'" rule, and the same
|
||||
unset-environment refusal #201 established for docs-sync (#205).
|
||||
|
||||
- A dispatch that never reaches the forge names the failure. Letting `set -e`
|
||||
carry curl's exit code out did fail the job, but with a bare status and no
|
||||
sentence (#205).
|
||||
|
||||
- `docs/CONSUMERS.md` and both caller comments describe the REST dispatch, and
|
||||
the manual bootstrap command carries a forge-neutral form beside the `gh`
|
||||
one — a cross-forge runbook that directs this forge to a missing binary is
|
||||
wrong even where the surrounding prose is right (#205).
|
||||
- `docs/RUNNER-PROBES.md` documents the standing runner-probe venue,
|
||||
`heavy-duty/ceremony-runner-probe` — the place runner-only facts are measured
|
||||
on demand, ruled as option A by the operator (#202).
|
||||
|
||||
- `drills/README.md` cross-links it beside the disposal rule, so the exception
|
||||
is visible where the dangerous habit lives (#202).
|
||||
|
||||
- The runbook states that the drill disposal rule does **not** apply to it.
|
||||
Archiving it defeats its purpose, and that is exactly how the three existing
|
||||
drill repos each became unavailable (#202).
|
||||
|
||||
- It records that a probe must run as an Actions job under the workflow token:
|
||||
the same call answers 500 there and 204 under a PAT, so a probe run any other
|
||||
way produces a confident wrong answer (#202).
|
||||
|
||||
- Creating the repo is recorded as the operator's step, measured rather than
|
||||
assumed: a fleet identity gets 403 on org repo creation and 201 in its own
|
||||
namespace (#202).
|
||||
|
||||
- It carries an executable two-layer arming procedure: an immutable candidate
|
||||
code SHA and an armed workflow commit on top of it. A single layer is
|
||||
self-referential — rewriting a workflow makes a new commit, and a commit
|
||||
cannot contain its own object ID (#202).
|
||||
|
||||
- Callers are pinned by layer: composite actions to the candidate code SHA,
|
||||
reusable workflows to the armed SHA, which is the only revision whose inner
|
||||
checkout points at the fork (#202).
|
||||
|
||||
- The arming gate asserts what each carrier IS, not only that the old literal
|
||||
is gone: every `repository:` equals the fork, every `CEREMONY_SELF_REF` value
|
||||
equal the candidate code SHA, and callers match the layer they belong to
|
||||
(#202).
|
||||
|
||||
- It enumerates the carriers from the tree rather than encoding a count, and
|
||||
distinguishes ceremony's internal self-checkouts from the consumer checkouts
|
||||
that must stay `${{ github.repository }}` (#202).
|
||||
|
||||
- Both published snippets are ShellCheck-clean when extracted and linted
|
||||
directly, not merely as part of the repository sweep (#202).
|
||||
|
||||
- The checker validates the MANIFEST against the target it was given, so a
|
||||
manifest that describes a wrong arming consistently — wrong fork, or the
|
||||
armed SHA where the candidate belongs — refuses instead of matching a tree
|
||||
rewritten to the same wrong value (#202).
|
||||
|
||||
- The manifest is generated from the PRE-arming tree, which is the only order
|
||||
that enumerates the carriers that must change (#202).
|
||||
|
||||
- Both published snippets were driven against a constructed candidate/probe
|
||||
pair: deletion, both role swaps, wrong owner, wrong
|
||||
SHA, wrong path, a deleted caller class and an extra carrier all refuse, and
|
||||
the armed control passes (#202).
|
||||
|
||||
- The manifest records complete caller coordinates, so a path swapped under the
|
||||
right owner and SHA is caught (#202).
|
||||
|
||||
- Generator and checker share one domain — ceremony callers — so a third-party
|
||||
`actions/checkout` is neither manifested nor reported as unrecognised (#202).
|
||||
|
||||
- Probe results are written to an issue in the probe repo and carried to the
|
||||
ceremony issue by a human, so the probe holds no path that can write to the
|
||||
live board (#202).
|
||||
- `test/docs-sync.test.sh` drives the fetch path, which had no coverage at all:
|
||||
every existing row passes `--source`, which overrides the fetch entirely
|
||||
(#201).
|
||||
|
||||
- A stubbed `curl` records the requested URL and serves a tarball, so which
|
||||
forge a pin resolves against is a tested decision rather than plumbing (#201).
|
||||
- `docs/UPSTREAM-SYNC.md` — the recurring upstream sync as a runbook: the
|
||||
standing resolutions, which side wins each and the issue that decided it
|
||||
(#200).
|
||||
|
||||
- It names the step the 0.6.0 sync nearly shipped without: auditing what the
|
||||
merge brought in that did **not** conflict. `git merge` asks no question
|
||||
about a function upstream added to a file this tree owns (#200).
|
||||
|
||||
- It records that the same mechanic applies to state, not just to call sites: a
|
||||
resolved region can silently remove a producer whose consumers auto-merged,
|
||||
and every one of those consumers degrades to empty rather than erroring
|
||||
(#200).
|
||||
|
||||
- It says to verify with the runner's tooling, because "green locally" was
|
||||
wrong three times in one sync — untracked files, a pinned linter, and a
|
||||
pinned `jq` whose empty-input exit code differs (#200).
|
||||
|
||||
- It says every branch open across a sync is stale afterwards — Forgejo never
|
||||
re-tests an open PR when main moves, so a prior approval is evidence about a
|
||||
tree that no longer exists (#200).
|
||||
|
||||
- It says to audit post-merge runs by executed steps rather than colour, and to
|
||||
inventory what the sync changed about workflow triggers and jobs first (#200).
|
||||
|
||||
- `.upstream-ref` records the upstream commit this tree carries, in
|
||||
machine-readable form beside the CHANGELOG's prose (#200).
|
||||
|
||||
- `test/upstream-delta.test.sh` fails the PR that scatters a forge decision
|
||||
into a file the inventory does not name. Discovery is derived from the tree,
|
||||
so a composite `action.yml` or a `.yaml` workflow is seen without anyone
|
||||
remembering to add a glob (#200).
|
||||
|
||||
- Discovery is git's, not the filesystem's: `ls-files`, so the tarballs `ci.yml`
|
||||
extracts into the checkout and any developer cache are not parsed as source
|
||||
(#200).
|
||||
|
||||
- It refuses when the recorded commit is missing, absent from the object store,
|
||||
or not an ancestor — three distinct refusals, none of them a skip. `ci.yml`
|
||||
fetches that exact object so the test reads local evidence without CI
|
||||
omitting it (#200).
|
||||
|
||||
- Its mutation cases drive the real check against a constructed tree, so
|
||||
replacing the guard with `return 0` reds five of them (#200).
|
||||
|
||||
- `docs/CONSUMERS.md` states that two ceremonies answer to the same version
|
||||
number, and how a consumer says which one it pinned (#200).
|
||||
- `lib/issue_references.sh` — the LOCAL/CROSS classifier, moved out of
|
||||
`actions/issueflow-reconcile`'s executable so a second caller can use it
|
||||
without sourcing a reconciler, which would run one (#199, #61).
|
||||
|
||||
- `test/refs-not-closing.test.sh` drives the action's boundary on **both**
|
||||
backends with stubs at the transport, proving one fixture yields the same
|
||||
verdict on each — including a closing keyword that appears only in a commit
|
||||
message (#199).
|
||||
- This tree carries upstream ceremony through `8c3a4d1` (upstream `0.6.0`):
|
||||
`lib/attention.sh`, `lib/read.sh`, `actions/refs-not-closing`, the guarded
|
||||
reads, and the ruling and window rules (#198).
|
||||
|
||||
- `test/no-runtime-gh.test.sh` — the forge-portability guard: no runtime `gh`
|
||||
outside `lib/forge-github.sh` unless the file declares
|
||||
`CEREMONY_FORGE_CLIENT=gh` (#198).
|
||||
|
||||
- `CHANGELOG.md` names the upstream commit this tree carries, so a drill
|
||||
record can say which `0.6.0` it exercised (#197, #198).
|
||||
- `test/labels.test.sh` holds the conf's roster and `CONTRIBUTING.md`'s roster
|
||||
table to the same set, in both directions, so a roster edit that touches one
|
||||
file and not the other goes red instead of drifting quietly (#195).
|
||||
- `test/forge-backends.test.sh` pins the replacement contract: preserve
|
||||
unrelated labels across a combined add+remove, an absent removal as a
|
||||
successful no-op, the empty set as a full clear, and `forge_labels_add`
|
||||
still `POST`-only, per ceremony#128 (#192).
|
||||
|
||||
- `test/labels-reconcile.test.sh` drives a failing write through `main()` — the
|
||||
swallow was in the loop, where a fixture-level probe cannot reach (#192).
|
||||
|
||||
### Changed
|
||||
|
||||
- The review panel restores `kimi-reviewer-andresmgsl` alongside GLM. The
|
||||
four-identity panel now requires three cross-vendor approvals after the PR
|
||||
author recuses (#224).
|
||||
- The review panel names `glm-reviewer-andresmgsl` in place of
|
||||
`kimi-reviewer-andresmgsl` while that identity is unavailable. The panel
|
||||
stays three, so a PR still requires two cross-vendor approvals (#222).
|
||||
|
||||
- `test/labels.test.sh`'s table-side roster mutation names an identity the
|
||||
table actually carries. Naming a departed one would mutate nothing and the
|
||||
case would pass while proving nothing — #195's rot class one layer down
|
||||
(#222).
|
||||
- This forge's release line runs `0.4.1 → 0.6.1`: versions 0.5.0 and 0.6.0
|
||||
arrived here by merge from the read-only upstream and were never released
|
||||
on this forge (#220).
|
||||
|
||||
- The `## 0.6.0` section this changelog carries is upstream's — its entries
|
||||
describe upstream's work under upstream's issue numbers. The forge port's
|
||||
own work ships first in 0.6.1 (#220).
|
||||
- `docs/RUNNER-PROBES.md` records the venue's first delivered drills — the
|
||||
#192 asymmetry re-observed on demand under the workflow token, the dispatch
|
||||
route's 204 under both identities, and #215's boundary finding — each with
|
||||
the probe-issue URL it is recorded in (#202).
|
||||
|
||||
- Two venue lessons join the runbook where the next probe author will look:
|
||||
findings must be written to issues because the venue's log route 404s for
|
||||
non-admin reads, and report content sent to the forge must never contain a
|
||||
credential expression or value (#202).
|
||||
|
||||
### Fixed
|
||||
|
||||
- The sweep's `bootstrap` value crosses the `workflow_call` boundary as a
|
||||
declared input, explicitly passed by the caller — the one channel measured
|
||||
to work; the called workflow did not see the caller's event inputs as an
|
||||
implicit substitute on this instance (#215).
|
||||
|
||||
- Before the bridge, `github.event.inputs` was empty inside the called
|
||||
workflow, so every dispatch-woken sweep bootstrapped: ~20 label upserts on
|
||||
each board event (#215).
|
||||
|
||||
- The caller maps an empty top-level value to `no` explicitly, so a
|
||||
cron-woken sweep can never bootstrap; the declared input also defaults to
|
||||
`no`, so a consumer that passes nothing gets the safe path (#215).
|
||||
|
||||
- The gate feeds the declared input to `labels-reconcile` unchanged, so an
|
||||
invalid value meets the action's own `yes|no` refusal instead of being
|
||||
silently coerced (#215).
|
||||
|
||||
- `docs/CONSUMERS.md`'s published sweep stub carries the same pass-through —
|
||||
without it every consumer inherits the defect ceremony fixed for
|
||||
itself (#215).
|
||||
- `issueflow-reconcile` sees this forge's issues again. The board gather used
|
||||
`has("pull_request")`, and every Forgejo entry carries that key — so it
|
||||
selected zero rows on every sweep while printing `reconciled.` (#210).
|
||||
|
||||
- Three sites take `.pull_request == null`, the discriminator the file's own
|
||||
comment already specified and that one of its four call sites already used
|
||||
(#210).
|
||||
|
||||
- `post-merge` transitions can fire again: they could not, because the sweep
|
||||
saw no issues to transition (#210).
|
||||
- `blocker:unrequested` is judged on this forge again. The head-commit date was
|
||||
read from `repos/{o}/{r}/commits/{sha}`, which Forgejo answers **404** — so
|
||||
every sweep degraded and left the blocker unjudged (#209).
|
||||
|
||||
- `forge_commit_at` is a verb on both backends: GitHub serves a single commit at
|
||||
the bare path with the date nested, Forgejo at `git/commits/{sha}` with it
|
||||
under `.created`. The caller asks for one timestamp and knows neither shape
|
||||
(#209).
|
||||
- `.github/workflows/labels.yml` wakes the sweep over REST instead of
|
||||
`gh workflow run`, so a board event reconciles within seconds on any forge
|
||||
rather than waiting up to an hour for the scheduled sweep (#205).
|
||||
|
||||
- The workflow-dispatch endpoint has the same shape on both forges, so that
|
||||
step no longer decides one: the `CEREMONY_FORGE_CLIENT=gh` declaration and
|
||||
both inline refusals are gone rather than ported (#205).
|
||||
|
||||
- The dispatch supplies its `ref` explicitly, because REST has no default
|
||||
branch where `gh workflow run` had one, and refuses without it (#205).
|
||||
|
||||
- It takes that ref from the repository, never from `GITHUB_REF_NAME` — on a
|
||||
`pull_request_target` run that is `<n>/merge`, which is not a branch (#205).
|
||||
|
||||
- A failed dispatch names the endpoint, the ref and the status, and says that
|
||||
an empty `500` body from Forgejo means the workflow name or the ref did not
|
||||
resolve — a bare status sends the reader after a server fault that is not
|
||||
there (#205).
|
||||
- `actions/docs-sync` fetches the doctrine mirror from the forge named by
|
||||
`GITHUB_SERVER_URL` instead of a hard-coded `github.com` (#201).
|
||||
|
||||
- The same pin ref names a different tree on each forge, so a consumer's mirror
|
||||
was verified against a tree it never pinned — and with HTTP 200, so `--check`
|
||||
reported drift that could not be fixed (#201).
|
||||
|
||||
- A fetch that cannot name its forge now refuses instead of guessing: no
|
||||
`GITHUB_SERVER_URL` and no `--source` exits naming the variable, having
|
||||
reached for no network (#201).
|
||||
|
||||
- A failed fetch names the URL it actually tried, and asks whether the ref
|
||||
exists on that forge rather than in the abstract (#201).
|
||||
- `actions/refs-not-closing` gathers over REST through the forge shim instead
|
||||
of one GraphQL query, so it produces a real verdict on Forgejo — which
|
||||
serves no GraphQL surface at all — rather than refusing (#199).
|
||||
|
||||
- The closing set is parsed by `lib/closes_references.sh` over the PR body
|
||||
**and** every commit message, unioned. Forgejo honours closing keywords in
|
||||
commit messages, so a body-only port would miss a PR that closes an issue
|
||||
from a commit subject (#199).
|
||||
|
||||
- The `hasNextPage` refusal is carried onto the paginated commit read: an
|
||||
incomplete gather refuses instead of returning a partial verdict, reusing
|
||||
the backend's `x-total-count` completeness proof (#199).
|
||||
|
||||
- A failed read never reaches the parser. An unread body parses to an empty
|
||||
closing set, which is a passing verdict the action never earned (#199).
|
||||
|
||||
- `.github/workflows/refs-guard.yml` no longer gates the job on the forge.
|
||||
A portable action behind a github-only gate is a guard that passes by never
|
||||
running (#199, #198).
|
||||
|
||||
- The `CEREMONY_FORGE_CLIENT=gh` declaration is gone, and the contract test
|
||||
asserts its absence: an opt-out with no `gh` behind it is a standing
|
||||
permission slip (#199).
|
||||
- Eight runtime `gh` call sites arrived with the merge outside every conflict
|
||||
hunk, in functions upstream added to files this tree already owned. Seven
|
||||
are ported onto the shim; the eighth is named with its reason (#198).
|
||||
|
||||
- The open-PR gather reads `Refs`, not only closing keywords. Reading one side
|
||||
for closing links and the other for `Refs` is what released a live claim in
|
||||
crew#321, and this tree carried that shape (#198).
|
||||
|
||||
- The merged record gains `merged_at`, so `post_merge_pr_for_issue` answers
|
||||
the PR that merged last rather than the highest-numbered one. Without the
|
||||
column every sort key ties and the old order returns silently (#198).
|
||||
|
||||
- The open gather feeds `open_pr_issues` one record per physical body line. A
|
||||
whole decoded body as one record loses every declaration including the
|
||||
first, and reclaims a claim a live PR was holding (#198).
|
||||
|
||||
- The post-merge nudge links the issue on the forge in play rather than a
|
||||
hard-coded `github.com` (#198).
|
||||
|
||||
- `actions/refs-not-closing` reports and skips on a forge it cannot speak,
|
||||
naming the client and #199, instead of standing red on every PR. It reaches
|
||||
the forge zero times, so no verdict is produced either way (#198).
|
||||
|
||||
- `.github/workflows/labels.yml`'s sweep dispatch declares the client it
|
||||
speaks and decides the FORGE before the binary, so a Forgejo runner that
|
||||
happens to ship `gh` cannot dispatch against a forge that cannot serve it.
|
||||
#205 ports it to REST (#198).
|
||||
|
||||
- `actions/refs-not-closing` fails closed on a forge it cannot speak, and
|
||||
`.github/workflows/refs-guard.yml` carries the scheduling decision — the
|
||||
action never reports a success it did not earn (#198).
|
||||
|
||||
- `issue_payload_valid` refuses an empty payload on jq 1.6 as well as 1.7.
|
||||
`jq -e` exits 4 on empty input under 1.7 and **0** under 1.6, and this
|
||||
instance's runner carries 1.6 — so the guard #247 D3 added to refuse an
|
||||
unreadable read was accepting one here (#198).
|
||||
|
||||
- The post-merge nudge strips a trailing slash from the server URL, so a forge
|
||||
URL carrying one does not render `//owner/repo` (#198).
|
||||
|
||||
- `.github/scripts/release-path.sh` names `lib/forge.sh`: #191 put the shim on
|
||||
the release doors' executable path here, so a doors-unchanged record that
|
||||
omitted it was measuring the wrong set (#198).
|
||||
- `.github/labels.conf` names identities that exist on the forge this repo
|
||||
lives on. All five it named before were absent, so `panel=` could never
|
||||
converge a review round and `triage-actors=` made every issue a stray mint
|
||||
nobody could normalize (#195).
|
||||
|
||||
- `CONTRIBUTING.md`'s roster table matches the conf: three identities, the
|
||||
human row is `andres`, and the approval count states what panel-minus-author
|
||||
actually resolves to on this roster rather than a stale three (#195).
|
||||
- Label removal on Forgejo is a full-set `PUT`, not a per-label `DELETE`. The
|
||||
workflow token gets HTTP 500 on every `DELETE .../labels/{id}` on this
|
||||
instance, so the state machine could only ever ADD labels (#192).
|
||||
|
||||
- Every `state:*` transition that needs the previous state cleared, and every
|
||||
`blocker:*` that should lift, can now actually clear. They were inert (#192).
|
||||
|
||||
- A label edit that fails is fatal to `labels-reconcile`, matching
|
||||
`issueflow-reconcile`. One cause had two contradictory policies (#192).
|
||||
|
||||
- A failed write reaches the sweep's exit code: per-PR tolerance is kept for
|
||||
READS, but a sweep that could not write exits non-zero and its output carries
|
||||
no `reconciled.` token at all (#192).
|
||||
|
||||
- Every label mutation goes through one checked helper, so clearing
|
||||
`merge-next` or either `stale` edit fails the sweep too — not only the
|
||||
primary state edit (#192).
|
||||
|
||||
- A preserved label keeps the id the issue payload already carried, so
|
||||
preservation does not depend on a repository-wide list that has nothing to do
|
||||
with the issue (#192).
|
||||
|
||||
- A removal that changes nothing writes nothing, rather than replacing the set
|
||||
with itself and opening a race for no state change (#192).
|
||||
|
||||
- Every failure diagnostic on the forgejo backend names the verb as well as the
|
||||
path and the status. A read used to say `HTTP 500 from 'repos/…'`, which
|
||||
cannot be told from a failed write of the same path (#192).
|
||||
|
||||
- The diagnostic names what was attempted and that it did not happen, instead
|
||||
of blaming a missing label and telling the operator to bootstrap — a cause it
|
||||
had not established (#192, #101).
|
||||
|
||||
- An add-label the repo does not carry refuses before any write, so a
|
||||
replacement `PUT` can never drop a label nobody asked to remove (#192).
|
||||
|
||||
## 0.6.0 — 2026-08-05
|
||||
|
||||
### Added
|
||||
|
|
|
|||
2
VERSION
2
VERSION
|
|
@ -1 +1 @@
|
|||
0.6.1-dev
|
||||
0.6.1
|
||||
|
|
|
|||
|
|
@ -1,47 +0,0 @@
|
|||
### Fixed
|
||||
|
||||
- Label removal on Forgejo is a full-set `PUT`, not a per-label `DELETE`. The
|
||||
workflow token gets HTTP 500 on every `DELETE .../labels/{id}` on this
|
||||
instance, so the state machine could only ever ADD labels (#192).
|
||||
|
||||
- Every `state:*` transition that needs the previous state cleared, and every
|
||||
`blocker:*` that should lift, can now actually clear. They were inert (#192).
|
||||
|
||||
- A label edit that fails is fatal to `labels-reconcile`, matching
|
||||
`issueflow-reconcile`. One cause had two contradictory policies (#192).
|
||||
|
||||
- A failed write reaches the sweep's exit code: per-PR tolerance is kept for
|
||||
READS, but a sweep that could not write exits non-zero and its output carries
|
||||
no `reconciled.` token at all (#192).
|
||||
|
||||
- Every label mutation goes through one checked helper, so clearing
|
||||
`merge-next` or either `stale` edit fails the sweep too — not only the
|
||||
primary state edit (#192).
|
||||
|
||||
- A preserved label keeps the id the issue payload already carried, so
|
||||
preservation does not depend on a repository-wide list that has nothing to do
|
||||
with the issue (#192).
|
||||
|
||||
- A removal that changes nothing writes nothing, rather than replacing the set
|
||||
with itself and opening a race for no state change (#192).
|
||||
|
||||
- Every failure diagnostic on the forgejo backend names the verb as well as the
|
||||
path and the status. A read used to say `HTTP 500 from 'repos/…'`, which
|
||||
cannot be told from a failed write of the same path (#192).
|
||||
|
||||
- The diagnostic names what was attempted and that it did not happen, instead
|
||||
of blaming a missing label and telling the operator to bootstrap — a cause it
|
||||
had not established (#192, #101).
|
||||
|
||||
- An add-label the repo does not carry refuses before any write, so a
|
||||
replacement `PUT` can never drop a label nobody asked to remove (#192).
|
||||
|
||||
### Added
|
||||
|
||||
- `test/forge-backends.test.sh` pins the replacement contract: preserve
|
||||
unrelated labels across a combined add+remove, an absent removal as a
|
||||
successful no-op, the empty set as a full clear, and `forge_labels_add`
|
||||
still `POST`-only, per ceremony#128 (#192).
|
||||
|
||||
- `test/labels-reconcile.test.sh` drives a failing write through `main()` — the
|
||||
swallow was in the loop, where a fixture-level probe cannot reach (#192).
|
||||
|
|
@ -1,16 +0,0 @@
|
|||
### Fixed
|
||||
|
||||
- `.github/labels.conf` names identities that exist on the forge this repo
|
||||
lives on. All five it named before were absent, so `panel=` could never
|
||||
converge a review round and `triage-actors=` made every issue a stray mint
|
||||
nobody could normalize (#195).
|
||||
|
||||
- `CONTRIBUTING.md`'s roster table matches the conf: three identities, the
|
||||
human row is `andres`, and the approval count states what panel-minus-author
|
||||
actually resolves to on this roster rather than a stale three (#195).
|
||||
|
||||
### Added
|
||||
|
||||
- `test/labels.test.sh` holds the conf's roster and `CONTRIBUTING.md`'s roster
|
||||
table to the same set, in both directions, so a roster edit that touches one
|
||||
file and not the other goes red instead of drifting quietly (#195).
|
||||
|
|
@ -1,58 +0,0 @@
|
|||
### Added
|
||||
|
||||
- This tree carries upstream ceremony through `8c3a4d1` (upstream `0.6.0`):
|
||||
`lib/attention.sh`, `lib/read.sh`, `actions/refs-not-closing`, the guarded
|
||||
reads, and the ruling and window rules (#198).
|
||||
|
||||
- `test/no-runtime-gh.test.sh` — the forge-portability guard: no runtime `gh`
|
||||
outside `lib/forge-github.sh` unless the file declares
|
||||
`CEREMONY_FORGE_CLIENT=gh` (#198).
|
||||
|
||||
- `CHANGELOG.md` names the upstream commit this tree carries, so a drill
|
||||
record can say which `0.6.0` it exercised (#197, #198).
|
||||
|
||||
### Fixed
|
||||
|
||||
- Eight runtime `gh` call sites arrived with the merge outside every conflict
|
||||
hunk, in functions upstream added to files this tree already owned. Seven
|
||||
are ported onto the shim; the eighth is named with its reason (#198).
|
||||
|
||||
- The open-PR gather reads `Refs`, not only closing keywords. Reading one side
|
||||
for closing links and the other for `Refs` is what released a live claim in
|
||||
crew#321, and this tree carried that shape (#198).
|
||||
|
||||
- The merged record gains `merged_at`, so `post_merge_pr_for_issue` answers
|
||||
the PR that merged last rather than the highest-numbered one. Without the
|
||||
column every sort key ties and the old order returns silently (#198).
|
||||
|
||||
- The open gather feeds `open_pr_issues` one record per physical body line. A
|
||||
whole decoded body as one record loses every declaration including the
|
||||
first, and reclaims a claim a live PR was holding (#198).
|
||||
|
||||
- The post-merge nudge links the issue on the forge in play rather than a
|
||||
hard-coded `github.com` (#198).
|
||||
|
||||
- `actions/refs-not-closing` reports and skips on a forge it cannot speak,
|
||||
naming the client and #199, instead of standing red on every PR. It reaches
|
||||
the forge zero times, so no verdict is produced either way (#198).
|
||||
|
||||
- `.github/workflows/labels.yml`'s sweep dispatch declares the client it
|
||||
speaks and decides the FORGE before the binary, so a Forgejo runner that
|
||||
happens to ship `gh` cannot dispatch against a forge that cannot serve it.
|
||||
#205 ports it to REST (#198).
|
||||
|
||||
- `actions/refs-not-closing` fails closed on a forge it cannot speak, and
|
||||
`.github/workflows/refs-guard.yml` carries the scheduling decision — the
|
||||
action never reports a success it did not earn (#198).
|
||||
|
||||
- `issue_payload_valid` refuses an empty payload on jq 1.6 as well as 1.7.
|
||||
`jq -e` exits 4 on empty input under 1.7 and **0** under 1.6, and this
|
||||
instance's runner carries 1.6 — so the guard #247 D3 added to refuse an
|
||||
unreadable read was accepting one here (#198).
|
||||
|
||||
- The post-merge nudge strips a trailing slash from the server URL, so a forge
|
||||
URL carrying one does not render `//owner/repo` (#198).
|
||||
|
||||
- `.github/scripts/release-path.sh` names `lib/forge.sh`: #191 put the shim on
|
||||
the release doors' executable path here, so a doors-unchanged record that
|
||||
omitted it was measuring the wrong set (#198).
|
||||
|
|
@ -1,36 +0,0 @@
|
|||
### Fixed
|
||||
|
||||
- `actions/refs-not-closing` gathers over REST through the forge shim instead
|
||||
of one GraphQL query, so it produces a real verdict on Forgejo — which
|
||||
serves no GraphQL surface at all — rather than refusing (#199).
|
||||
|
||||
- The closing set is parsed by `lib/closes_references.sh` over the PR body
|
||||
**and** every commit message, unioned. Forgejo honours closing keywords in
|
||||
commit messages, so a body-only port would miss a PR that closes an issue
|
||||
from a commit subject (#199).
|
||||
|
||||
- The `hasNextPage` refusal is carried onto the paginated commit read: an
|
||||
incomplete gather refuses instead of returning a partial verdict, reusing
|
||||
the backend's `x-total-count` completeness proof (#199).
|
||||
|
||||
- A failed read never reaches the parser. An unread body parses to an empty
|
||||
closing set, which is a passing verdict the action never earned (#199).
|
||||
|
||||
- `.github/workflows/refs-guard.yml` no longer gates the job on the forge.
|
||||
A portable action behind a github-only gate is a guard that passes by never
|
||||
running (#199, #198).
|
||||
|
||||
- The `CEREMONY_FORGE_CLIENT=gh` declaration is gone, and the contract test
|
||||
asserts its absence: an opt-out with no `gh` behind it is a standing
|
||||
permission slip (#199).
|
||||
|
||||
### Added
|
||||
|
||||
- `lib/issue_references.sh` — the LOCAL/CROSS classifier, moved out of
|
||||
`actions/issueflow-reconcile`'s executable so a second caller can use it
|
||||
without sourcing a reconciler, which would run one (#199, #61).
|
||||
|
||||
- `test/refs-not-closing.test.sh` drives the action's boundary on **both**
|
||||
backends with stubs at the transport, proving one fixture yields the same
|
||||
verdict on each — including a closing keyword that appears only in a commit
|
||||
message (#199).
|
||||
|
|
@ -1,48 +0,0 @@
|
|||
### Added
|
||||
|
||||
- `docs/UPSTREAM-SYNC.md` — the recurring upstream sync as a runbook: the
|
||||
standing resolutions, which side wins each and the issue that decided it
|
||||
(#200).
|
||||
|
||||
- It names the step the 0.6.0 sync nearly shipped without: auditing what the
|
||||
merge brought in that did **not** conflict. `git merge` asks no question
|
||||
about a function upstream added to a file this tree owns (#200).
|
||||
|
||||
- It records that the same mechanic applies to state, not just to call sites: a
|
||||
resolved region can silently remove a producer whose consumers auto-merged,
|
||||
and every one of those consumers degrades to empty rather than erroring
|
||||
(#200).
|
||||
|
||||
- It says to verify with the runner's tooling, because "green locally" was
|
||||
wrong three times in one sync — untracked files, a pinned linter, and a
|
||||
pinned `jq` whose empty-input exit code differs (#200).
|
||||
|
||||
- It says every branch open across a sync is stale afterwards — Forgejo never
|
||||
re-tests an open PR when main moves, so a prior approval is evidence about a
|
||||
tree that no longer exists (#200).
|
||||
|
||||
- It says to audit post-merge runs by executed steps rather than colour, and to
|
||||
inventory what the sync changed about workflow triggers and jobs first (#200).
|
||||
|
||||
- `.upstream-ref` records the upstream commit this tree carries, in
|
||||
machine-readable form beside the CHANGELOG's prose (#200).
|
||||
|
||||
- `test/upstream-delta.test.sh` fails the PR that scatters a forge decision
|
||||
into a file the inventory does not name. Discovery is derived from the tree,
|
||||
so a composite `action.yml` or a `.yaml` workflow is seen without anyone
|
||||
remembering to add a glob (#200).
|
||||
|
||||
- Discovery is git's, not the filesystem's: `ls-files`, so the tarballs `ci.yml`
|
||||
extracts into the checkout and any developer cache are not parsed as source
|
||||
(#200).
|
||||
|
||||
- It refuses when the recorded commit is missing, absent from the object store,
|
||||
or not an ancestor — three distinct refusals, none of them a skip. `ci.yml`
|
||||
fetches that exact object so the test reads local evidence without CI
|
||||
omitting it (#200).
|
||||
|
||||
- Its mutation cases drive the real check against a constructed tree, so
|
||||
replacing the guard with `return 0` reds five of them (#200).
|
||||
|
||||
- `docs/CONSUMERS.md` states that two ceremonies answer to the same version
|
||||
number, and how a consumer says which one it pinned (#200).
|
||||
|
|
@ -1,24 +0,0 @@
|
|||
### Fixed
|
||||
|
||||
- `actions/docs-sync` fetches the doctrine mirror from the forge named by
|
||||
`GITHUB_SERVER_URL` instead of a hard-coded `github.com` (#201).
|
||||
|
||||
- The same pin ref names a different tree on each forge, so a consumer's mirror
|
||||
was verified against a tree it never pinned — and with HTTP 200, so `--check`
|
||||
reported drift that could not be fixed (#201).
|
||||
|
||||
- A fetch that cannot name its forge now refuses instead of guessing: no
|
||||
`GITHUB_SERVER_URL` and no `--source` exits naming the variable, having
|
||||
reached for no network (#201).
|
||||
|
||||
- A failed fetch names the URL it actually tried, and asks whether the ref
|
||||
exists on that forge rather than in the abstract (#201).
|
||||
|
||||
### Added
|
||||
|
||||
- `test/docs-sync.test.sh` drives the fetch path, which had no coverage at all:
|
||||
every existing row passes `--source`, which overrides the fetch entirely
|
||||
(#201).
|
||||
|
||||
- A stubbed `curl` records the requested URL and serves a tarball, so which
|
||||
forge a pin resolves against is a tested decision rather than plumbing (#201).
|
||||
|
|
@ -1,76 +0,0 @@
|
|||
### Added
|
||||
|
||||
- `docs/RUNNER-PROBES.md` documents the standing runner-probe venue,
|
||||
`heavy-duty/ceremony-runner-probe` — the place runner-only facts are measured
|
||||
on demand, ruled as option A by the operator (#202).
|
||||
|
||||
- `drills/README.md` cross-links it beside the disposal rule, so the exception
|
||||
is visible where the dangerous habit lives (#202).
|
||||
|
||||
- The runbook states that the drill disposal rule does **not** apply to it.
|
||||
Archiving it defeats its purpose, and that is exactly how the three existing
|
||||
drill repos each became unavailable (#202).
|
||||
|
||||
- It records that a probe must run as an Actions job under the workflow token:
|
||||
the same call answers 500 there and 204 under a PAT, so a probe run any other
|
||||
way produces a confident wrong answer (#202).
|
||||
|
||||
- Creating the repo is recorded as the operator's step, measured rather than
|
||||
assumed: a fleet identity gets 403 on org repo creation and 201 in its own
|
||||
namespace (#202).
|
||||
|
||||
- It carries an executable two-layer arming procedure: an immutable candidate
|
||||
code SHA and an armed workflow commit on top of it. A single layer is
|
||||
self-referential — rewriting a workflow makes a new commit, and a commit
|
||||
cannot contain its own object ID (#202).
|
||||
|
||||
- Callers are pinned by layer: composite actions to the candidate code SHA,
|
||||
reusable workflows to the armed SHA, which is the only revision whose inner
|
||||
checkout points at the fork (#202).
|
||||
|
||||
- The arming gate asserts what each carrier IS, not only that the old literal
|
||||
is gone: every `repository:` equals the fork, every `CEREMONY_SELF_REF` value
|
||||
equal the candidate code SHA, and callers match the layer they belong to
|
||||
(#202).
|
||||
|
||||
- It enumerates the carriers from the tree rather than encoding a count, and
|
||||
distinguishes ceremony's internal self-checkouts from the consumer checkouts
|
||||
that must stay `${{ github.repository }}` (#202).
|
||||
|
||||
- Both published snippets are ShellCheck-clean when extracted and linted
|
||||
directly, not merely as part of the repository sweep (#202).
|
||||
|
||||
- The checker validates the MANIFEST against the target it was given, so a
|
||||
manifest that describes a wrong arming consistently — wrong fork, or the
|
||||
armed SHA where the candidate belongs — refuses instead of matching a tree
|
||||
rewritten to the same wrong value (#202).
|
||||
|
||||
- The manifest is generated from the PRE-arming tree, which is the only order
|
||||
that enumerates the carriers that must change (#202).
|
||||
|
||||
- Both published snippets were driven against a constructed candidate/probe
|
||||
pair: deletion, both role swaps, wrong owner, wrong
|
||||
SHA, wrong path, a deleted caller class and an extra carrier all refuse, and
|
||||
the armed control passes (#202).
|
||||
|
||||
- The manifest records complete caller coordinates, so a path swapped under the
|
||||
right owner and SHA is caught (#202).
|
||||
|
||||
- Generator and checker share one domain — ceremony callers — so a third-party
|
||||
`actions/checkout` is neither manifested nor reported as unrecognised (#202).
|
||||
|
||||
- Probe results are written to an issue in the probe repo and carried to the
|
||||
ceremony issue by a human, so the probe holds no path that can write to the
|
||||
live board (#202).
|
||||
|
||||
### Changed
|
||||
|
||||
- `docs/RUNNER-PROBES.md` records the venue's first delivered drills — the
|
||||
#192 asymmetry re-observed on demand under the workflow token, the dispatch
|
||||
route's 204 under both identities, and #215's boundary finding — each with
|
||||
the probe-issue URL it is recorded in (#202).
|
||||
|
||||
- Two venue lessons join the runbook where the next probe author will look:
|
||||
findings must be written to issues because the venue's log route 404s for
|
||||
non-admin reads, and report content sent to the forge must never contain a
|
||||
credential expression or value (#202).
|
||||
|
|
@ -1,44 +0,0 @@
|
|||
### Fixed
|
||||
|
||||
- `.github/workflows/labels.yml` wakes the sweep over REST instead of
|
||||
`gh workflow run`, so a board event reconciles within seconds on any forge
|
||||
rather than waiting up to an hour for the scheduled sweep (#205).
|
||||
|
||||
- The workflow-dispatch endpoint has the same shape on both forges, so that
|
||||
step no longer decides one: the `CEREMONY_FORGE_CLIENT=gh` declaration and
|
||||
both inline refusals are gone rather than ported (#205).
|
||||
|
||||
- The dispatch supplies its `ref` explicitly, because REST has no default
|
||||
branch where `gh workflow run` had one, and refuses without it (#205).
|
||||
|
||||
- It takes that ref from the repository, never from `GITHUB_REF_NAME` — on a
|
||||
`pull_request_target` run that is `<n>/merge`, which is not a branch (#205).
|
||||
|
||||
- A failed dispatch names the endpoint, the ref and the status, and says that
|
||||
an empty `500` body from Forgejo means the workflow name or the ref did not
|
||||
resolve — a bare status sends the reader after a server fault that is not
|
||||
there (#205).
|
||||
|
||||
### Added
|
||||
|
||||
- `test/labels-dispatch.test.sh` extracts the shipped step and executes it
|
||||
against a recording stub, asserting the method, endpoint, ref and
|
||||
`inputs.bootstrap` actually sent (#205).
|
||||
|
||||
- That test also drives the failure path: any non-204 still fails the job, so
|
||||
the misconfiguration alarm the trigger exists to be cannot decay into a
|
||||
warning (#205).
|
||||
|
||||
- An unset `GITHUB_API_URL` refuses before any request instead of defaulting
|
||||
to `api.github.com`. Guessing sent this forge's dispatch to GitHub and
|
||||
reported success — the "Never 'probably github'" rule, and the same
|
||||
unset-environment refusal #201 established for docs-sync (#205).
|
||||
|
||||
- A dispatch that never reaches the forge names the failure. Letting `set -e`
|
||||
carry curl's exit code out did fail the job, but with a bare status and no
|
||||
sentence (#205).
|
||||
|
||||
- `docs/CONSUMERS.md` and both caller comments describe the REST dispatch, and
|
||||
the manual bootstrap command carries a forge-neutral form beside the `gh`
|
||||
one — a cross-forge runbook that directs this forge to a missing binary is
|
||||
wrong even where the surrounding prose is right (#205).
|
||||
|
|
@ -1,16 +0,0 @@
|
|||
### Fixed
|
||||
|
||||
- `blocker:unrequested` is judged on this forge again. The head-commit date was
|
||||
read from `repos/{o}/{r}/commits/{sha}`, which Forgejo answers **404** — so
|
||||
every sweep degraded and left the blocker unjudged (#209).
|
||||
|
||||
- `forge_commit_at` is a verb on both backends: GitHub serves a single commit at
|
||||
the bare path with the date nested, Forgejo at `git/commits/{sha}` with it
|
||||
under `.created`. The caller asks for one timestamp and knows neither shape
|
||||
(#209).
|
||||
|
||||
### Added
|
||||
|
||||
- `test/forge-backends.test.sh` pins each backend's path **and** field, because
|
||||
a stubbed `forge_api` cannot catch a wrong path — which is how this shipped
|
||||
and why a live sweep was what found it (#209).
|
||||
|
|
@ -1,27 +0,0 @@
|
|||
### Fixed
|
||||
|
||||
- `issueflow-reconcile` sees this forge's issues again. The board gather used
|
||||
`has("pull_request")`, and every Forgejo entry carries that key — so it
|
||||
selected zero rows on every sweep while printing `reconciled.` (#210).
|
||||
|
||||
- Three sites take `.pull_request == null`, the discriminator the file's own
|
||||
comment already specified and that one of its four call sites already used
|
||||
(#210).
|
||||
|
||||
- `post-merge` transitions can fire again: they could not, because the sweep
|
||||
saw no issues to transition (#210).
|
||||
|
||||
### Added
|
||||
|
||||
- A gather-level case drives the real board read against a Forgejo-shaped
|
||||
fixture — every entry carrying the key. The existing discriminator cases
|
||||
assert `jq` expressions in isolation and passed throughout this regression
|
||||
(#210).
|
||||
|
||||
- A source pin forbids `has("pull_request")` on this surface, because the rule
|
||||
was stated in a comment and violated forty lines below it. It strips comments,
|
||||
so the #188 warning that explains the trap is allowed to stay (#210).
|
||||
|
||||
- All three sites are covered behaviourally, not only by the pin: the board
|
||||
gather, the release-body gather through an observable window flag, and the
|
||||
per-issue payload check (#210).
|
||||
|
|
@ -1,47 +0,0 @@
|
|||
### Fixed
|
||||
|
||||
- The sweep's `bootstrap` value crosses the `workflow_call` boundary as a
|
||||
declared input, explicitly passed by the caller — the one channel measured
|
||||
to work; the called workflow did not see the caller's event inputs as an
|
||||
implicit substitute on this instance (#215).
|
||||
|
||||
- Before the bridge, `github.event.inputs` was empty inside the called
|
||||
workflow, so every dispatch-woken sweep bootstrapped: ~20 label upserts on
|
||||
each board event (#215).
|
||||
|
||||
- The caller maps an empty top-level value to `no` explicitly, so a
|
||||
cron-woken sweep can never bootstrap; the declared input also defaults to
|
||||
`no`, so a consumer that passes nothing gets the safe path (#215).
|
||||
|
||||
- The gate feeds the declared input to `labels-reconcile` unchanged, so an
|
||||
invalid value meets the action's own `yes|no` refusal instead of being
|
||||
silently coerced (#215).
|
||||
|
||||
- `docs/CONSUMERS.md`'s published sweep stub carries the same pass-through —
|
||||
without it every consumer inherits the defect ceremony fixed for
|
||||
itself (#215).
|
||||
|
||||
### Added
|
||||
|
||||
- `test/labels-bootstrap.test.sh` pins the bridge at every hop: the declared
|
||||
boundary, both gate sites as the identity, no expression reading
|
||||
`github.event.inputs`, and the caller and stub pass-throughs
|
||||
byte-exact (#215).
|
||||
|
||||
- The same test drives the four value paths — schedule-empty, `no`, `yes`,
|
||||
invalid — through the shipped expressions into the action's real
|
||||
validator (#215).
|
||||
|
||||
- The taxonomy bootstrap keys on the `BOOTSTRAP` input, never the event name.
|
||||
It tested `GITHUB_EVENT_NAME = workflow_dispatch` — correct while an
|
||||
operator's manual dispatch was the only dispatch there was, inert-by-
|
||||
construction from #209 on, when every machine wake became a dispatch
|
||||
event (#215).
|
||||
|
||||
- The venue drill caught that: with the bridge delivering `no` perfectly,
|
||||
drill runs 16/17 still bootstrapped, because the script never read the
|
||||
input the whole chain existed to deliver (#215).
|
||||
|
||||
- `test/labels-reconcile.test.sh` pins the regression pair exactly: a
|
||||
`workflow_dispatch` event with `BOOTSTRAP=no` (or unset) creates and
|
||||
deletes nothing; only `BOOTSTRAP=yes` bootstraps (#215).
|
||||
|
|
@ -1,9 +0,0 @@
|
|||
### Changed
|
||||
|
||||
- This forge's release line runs `0.4.1 → 0.6.1`: versions 0.5.0 and 0.6.0
|
||||
arrived here by merge from the read-only upstream and were never released
|
||||
on this forge (#220).
|
||||
|
||||
- The `## 0.6.0` section this changelog carries is upstream's — its entries
|
||||
describe upstream's work under upstream's issue numbers. The forge port's
|
||||
own work ships first in 0.6.1 (#220).
|
||||
|
|
@ -1,10 +0,0 @@
|
|||
### Changed
|
||||
|
||||
- The review panel names `glm-reviewer-andresmgsl` in place of
|
||||
`kimi-reviewer-andresmgsl` while that identity is unavailable. The panel
|
||||
stays three, so a PR still requires two cross-vendor approvals (#222).
|
||||
|
||||
- `test/labels.test.sh`'s table-side roster mutation names an identity the
|
||||
table actually carries. Naming a departed one would mutate nothing and the
|
||||
case would pass while proving nothing — #195's rot class one layer down
|
||||
(#222).
|
||||
|
|
@ -1,5 +0,0 @@
|
|||
### Changed
|
||||
|
||||
- The review panel restores `kimi-reviewer-andresmgsl` alongside GLM. The
|
||||
four-identity panel now requires three cross-vendor approvals after the PR
|
||||
author recuses (#224).
|
||||
Loading…
Reference in a new issue