docs: contribution policy — CONTRIBUTING, PR template, changelog CI guards - #100
Open
Anarchid wants to merge 3 commits into
Open
docs: contribution policy — CONTRIBUTING, PR template, changelog CI guards#100Anarchid wants to merge 3 commits into
Anarchid wants to merge 3 commits into
Conversation
Ports the policy set deployed to connectome-host (PR #49) to this repo, codifying norms already practiced here rather than introducing new ones: merge-commit-only history, comment-based evidence review, declared AI authorship, companion-PR merge-order declarations. Adds the changelog discipline this repo has never had — 25 releases, no changelog — with enforcement layered cheapest-first: an entry-with-the-change rule binding direct pushes as well as PRs, a soft PR check (src/ touched => CHANGELOG.md touched, `no-changelog` label escape), and a tag-time publish guard that refuses to release a tag with no matching section. A `github-release` job mirrors that section into the GitHub release notes, deliberately independent of npm publish so github-clone consumers still get notes when publish fails. `npm version` now cuts the Unreleased section via scripts/release-changelog.mjs. Two hardenings over the connectome-host original, whose CHANGELOG.md accumulated six `## Unreleased` headings with one stranding ~60 lines of entries that reached no release: - refuses to run when more than one `## Unreleased` heading exists, since only the first is ever cut and later ones are silently never released; - splices by match index instead of `String.replace(substring)`, which hits the first *substring* occurrence — an inline `## Unreleased` mention in prose comes first and the version heading lands inside it. Verified: release script refuses the empty Unreleased (exit 1); full ritual exercised on a copy — entry -> cut -> tag guard pass/refuse -> notes extraction; all three workflows parse. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
This branch was cut 2026-07-27; three releases have shipped since, including two minors. The policy it introduces binds direct pushes as much as PRs — and version bumps are direct-pushed release-time actions by construction — so landing the file already three releases behind main would undercut the point of adding it. Entries reconstructed from v0.7.3..v0.9.0, grouped by the release that carried them. 0.9.0's release commit already itemized its own breaking surface and dependency floors; those are carried over rather than re-derived, including the chronicle 0.3.0 cold-backup deploy note, which belongs in front of anyone upgrading a residence. Breaking entries are audience-scoped per the policy: consumers (sendAfterInference removal, the 5000-char spill default), MCPL servers (0.5 deny-by-default before the policy handshake, §7 removal — un-migrated servers go dark), and dependency floors separately, since the audiences act on different things. Test-only and refactor commits are omitted per the policy's own rule. Review-response commits are folded into the entry for the feature they correct rather than listed separately. Verified: tag guard matches all three sections; release-notes awk extracts 45/79/162 lines with no cross-section bleed; release-changelog.mjs refuses the empty Unreleased, cuts 0.9.1 cleanly, then refuses the duplicate. Build clean, tsc --noEmit clean, npm test 560/560 pass 0 fail. Note for anyone reproducing that suite locally: the workspace-symlinked membrane and context-manager checkouts had stale dist/ (membrane's from June, against 0.5.78 sources), which fails AF's build on the 'retrying' event type. Rebuild those two first. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
…edentials Greptile flagged the new github-release job (contents: write) for running actions/checkout at a mutable major-version ref: retargeting that tag would change the code running with permission to create and edit releases. Valid, and it undersells the exposure — that job is the LEAST privileged of the write-capable ones. Fixed across every workflow rather than just the flagged line, because a half-pinned repo invites the same finding next time: - 8 actions pinned (checkout, setup-node) across changelog.yml, ci.yml and publish.yml. Two things the review did not name: - The npm publish job holds `id-token: write` for OIDC trusted publishing. A swapped action there can reach a live publish credential, which is a worse outcome than editing release notes. - checkout defaults to persist-credentials: true, writing the job token into .git/config where every later step in the job can read it. Nothing here pushes over git — publish uses OIDC, the release job uses gh with GH_TOKEN — so all 4 checkouts now set it false. Version tags are kept as trailing comments so the pins stay readable and Dependabot can still bump them. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
This was referenced Aug 7, 2026
Open
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Problem
agent-framework has no
CONTRIBUTING.md, no PR template, and no changelog —and no mechanism that would notice one was missing.
@animalabs/agent-frameworkis at 0.9.0 on npm, and the newest GitHub release in this repo is v0.3.0 from
April. Everything since is discoverable only by reading
git log.Three releases have shipped in the last two weeks, two of them minors carrying
real breaking changes, and none of them announced anywhere a consumer would
look:
McplServerConfig.tokenProvider→accessProvider.default (tool results now spill at 5,000 chars), enforced MCPL 0.5
deny-by-default before the policy handshake — which darkens un-migrated
MCPL servers — and raised the chronicle floor to
^0.3.0, whose storeformat 0.2.x cannot reopen. That last one wants cold backups before
upgrading a residence, and the only place it was ever written down is a
release commit body.
A PR-side check alone can't carry the rule: across the ecosystem 52–85% of
commits on
mainland by direct push, and version bumps are release-timemaintainer actions by construction. The load-bearing layer is the tag-time
guard. This is the third rollout of the same policy, after connectome-host #49
and context-manager #51.
Changes
Ported from those two, adapted to this repo (build-before-test caveat,
stale-
dist/warning in the template):CONTRIBUTING.md— codifies existing practice rather than aspiration:merge commits only, comment-based review with run-the-branch transcripts,
evidence-over-assertion test reporting, and AI attribution as the norm.
Explicitly binds direct pushes and PRs, human and AI authors, identically.
.github/PULL_REQUEST_TEMPLATE.md— Problem / Changes / Tests / Notverified, plus a changelog checkbox.
.github/workflows/changelog.yml— soft PR check: touchingsrc/without
CHANGELOG.mdfails, with ano-changeloglabel opt-out (labelcreated).
publish.yml— the publish job is now gated on the ref rather than theevent, so a manual dispatch against a branch can no longer publish
whatever version
package.jsonhappens to carry; a tag with no matching## X.Y.Zsection fails the release; and a newgithub-releasejob mirrorsthe tag's section into GitHub release notes, independent of npm publish so
notes exist even when publish fails.
scripts/release-changelog.mjs+ aversionhook inpackage.json—npm version <level>cutsUnreleasedinto## X.Y.Z — YYYY-MM-DDpre-tag, so the tag and tarball carry it. Refuses an empty Unreleased, a
duplicate section, and more than one
Unreleasedheading (a second onesilently strands entries).
CHANGELOG.md, watermarked at 0.7.3, with 0.7.4, 0.8.0 and 0.9.0written up in full.
That last point is deliberate. The earliest policy PRs held that the
enforcement PR should itself conform; this branch was cut 2026-07-27 and three
releases have shipped since. Landing an empty changelog would mean adding a
file already three releases behind
main— the exact failure this PR existsto prevent, committed by the PR that prevents it.
Entries are reconstructed from
v0.7.3..v0.9.0and grouped by the releasethat carried them. Notes on the judgment calls:
(the
sendAfterInferenceremoval, the spill default), MCPL servers (0.5deny-by-default, §7 removal), and dependency floors separately — the three
audiences act on different things, and only the third needs the backup
warning.
that is carried over rather than re-derived.
correct, not listed separately — the changelog describes released
behavior, not the path to it.
what needs an entry.
The
package.jsonconflict from the rebase was resolved in favour ofmain's--test-force-exittest script, with only theversionhook added.Tests
npm test: 560 tests, 560 pass, 0 fail, 0 skipped (70 suites).npm run buildclean;tsc --noEmit: 0 errors. Green on this branch, ahead of the539/538/1-skipped baseline the 0.9.0 release commit reported.
No
src/changes — this is docs, CI config, and one npm lifecycle hook — sothe suite is a regression check, not a demonstration. What was exercised
directly is the tooling this branch adds, against the real
CHANGELOG.md:0.7.4,0.8.0,0.9.0—all match.
respectively, each starting at its first
###heading and stopping at thenext
##— no bleed across section boundaries.scripts/release-changelog.mjsagainst a copy,package.jsonat 0.9.1:empty
Unreleased→ refused, exit 1; one entry added →cut Unreleased into '## 0.9.1 — 2026-08-07', exit 0, fresh emptyUnreleasedleft above it;re-run → refused as duplicate, exit 1.
Unreleasedheading count: exactly 1.One reproduction note that cost time here and may cost a reviewer the same:
the workspace-symlinked
membraneandcontext-managercheckouts had staledist/(membrane's dated June, against 0.5.78 sources), which fails AF'sbuild on the
retryingevent type with 5TS2678/TS2339errors inframework.ts. Rebuild those two first — it is a local-environment artifact,not a branch or
maindefect, and CI installs from the registry so it cannothit this.
Not verified
live inference, MCPL connection or store was exercised.
changelog.ymlcheck has not run yet — this PR touches nosrc/files,so it will pass trivially rather than exercising its failure path. The
equivalent workflow was verified live on connectome-host test: add channel_publish fence coverage (home-default + foreign-reject) #49.
github-releasejob cannot run until the next release andstay unexercised on real infrastructure until then, as on the previous two
rollouts. The next
npm version <level> && git push --follow-tagswill bethis repo's first GitHub release since v0.3.0.
measurements quoted in them, not re-measured. Incident details (token
counts, outage durations, crash-cycle counts, dates) are as their authors
reported them. Where a commit body and a release body disagreed on framing,
I took the release body.
McplServerConnection.sendAfterInference; the changelog repeats chore(mcpl): drop the dead context/afterInference send surface (issue #39) #86's own14-tree grep rather than re-running it.
CHANGELOG.mdupdated under## Unreleased— or this change isinternal-only / test-only / docs-only (apply the
no-changeloglabel).Docs-only by the letter of the check, but the file ships with three releases
written up rather than empty, per the self-conformance point above.
🤖 Generated with Claude Code