mirror of
https://github.com/paperclipai/paperclip.git
synced 2026-10-06 10:48:12 +02:00
e3eed3a3ae4151a3c98d9a99266b2a3efe15263d
166
Commits
| Author | SHA1 | Message | Date | |
|---|---|---|---|---|
|
|
e6ad2ea3d9 |
ci: activate stacked pull request optimization (#12509)
## Thinking Path > - Paperclip uses GitHub Actions to verify pull requests before merge. > - The pull request workflow calls a trusted reusable workflow at an immutable commit SHA. > - Pull request #12507 added stack-aware CI scope to that reusable workflow. > - The caller still points to the prior workflow commit, so the new behavior is not active. > - This pull request advances the caller to the merged commit from pull request #12507. > - The benefit is that native stack middle layers stop starting redundant full CI matrices. ## Linked Issues or Issue Description Refs #12507 **What existing behavior does this improve?** The pull request workflow still calls the trusted CI definition that predates stack-aware scope selection. **Subsystem affected** GitHub Actions pull request verification. **Current behavior** Every pull request layer in a native stack starts the complete test, build, canary, and E2E matrix. **Proposed behavior** Call the trusted workflow from merged master commit `39b8ee2960541d14b380f95365deecba6723d9bd`. That workflow runs full CI for ordinary, top, and lowest-unmerged pull requests. It keeps policy and required aggregate checks on middle layers. **Reason and benefit** This completes the two-step immutable workflow rollout from pull request #12507. Large stacks will use fewer runners and will spend less time waiting for duplicate jobs. **Breaking changes** Middle native stack layers no longer run the complete CI matrix. Required aggregate checks remain present and fail closed if the stack scope is missing or invalid. ## What Changed - Pin `.github/workflows/pr.yml` to merged master commit `39b8ee2960541d14b380f95365deecba6723d9bd`. - Activate the stack-aware trusted workflow that merged in pull request #12507. ## Verification - `node --test scripts/__tests__/e2e-shard.test.mjs` — 11 tests passed. - `actionlint .github/workflows/pr.yml .github/workflows/pr-trusted.yml` — passed. - `git diff --check origin/master...HEAD` — passed. - Confirm that the caller SHA equals the merge commit for pull request #12507. ## Risks - The caller is immutable and points to a commit that exists on `master`. - Ordinary pull requests and merge-relevant stack layers still run full CI. - A rollback can restore the prior immutable SHA in one line. > For core feature work, check [`ROADMAP.md`](ROADMAP.md) first and discuss it in `#dev` before opening the PR. Feature PRs that overlap with planned core work may need to be redirected — check the roadmap first. See `CONTRIBUTING.md`. ## Model Used - OpenAI Codex with GPT-5. The exact deployment suffix and context window are not exposed. The model used reasoning, repository tools, code execution, Git, and GitHub API access. ## Checklist - [x] I have included a thinking path that traces from project context to this change - [x] I have specified the model used (with version and capability details) - [x] I have checked ROADMAP.md and confirmed this PR does not duplicate planned core work - [x] I have searched GitHub for duplicate or related PRs and linked them above - [x] I have either (a) linked existing issues with `Fixes: #` / `Closes #` / `Refs #` OR (b) described the issue in-PR following the relevant issue template - [x] I have not referenced internal/instance-local Paperclip issues or links (only public GitHub `#NNN` / `github.com/paperclipai/paperclip` URLs) - [x] My branch name describes the change (e.g. `docs/...`, `fix/...`) and contains no internal Paperclip ticket id or instance-derived details - [x] I have run tests locally and they pass - [x] I have added or updated tests where applicable - [x] I have updated relevant documentation to reflect my changes - [x] I have considered and documented any risks above - [ ] All Paperclip CI gates are green - [ ] Greptile is 5/5 with no open P2s, recommendations, or follow-ups - [x] I will address all Greptile and reviewer comments before requesting merge Co-authored-by: Paperclip <noreply@paperclip.ing> |
||
|
|
39b8ee2960 |
ci: optimize checks for stacked pull requests (#12507)
## Thinking Path > - Paperclip uses GitHub Actions to protect changes before they enter `master`. > - GitHub evaluates every pull request in a native stack against the stack base. > - The current workflow therefore starts the complete CI matrix for every layer in a stack. > - A large stack can queue many copies of the same integrated verification and delay every pull request. > - GitHub provides stack position and base metadata so workflows can select merge-relevant layers. > - This pull request keeps policy and required check names on every layer, but runs full CI only for ordinary pull requests, the top layer, and the lowest unmerged layer. > - The benefit is much lower CI load without weakening the required-check contract. ## Linked Issues or Issue Description **What existing behavior does this improve?** The trusted pull request workflow currently runs every test, build, canary, and E2E lane for every pull request in a native stack. **Subsystem affected** GitHub Actions pull request verification. **Current behavior** A stack with 61 pull requests can start 61 complete CI matrices after a cascading rebase. **Proposed behavior** Run the always-on policy job and stable required-check aggregators for every layer. Run the complete verification matrix only for ordinary pull requests, the top stack layer, and the lowest unmerged stack layer. **Reason and benefit** The top layer verifies the integrated stack. The lowest unmerged layer verifies the current merge candidate. Middle layers keep branch-protection checks without consuming the complete runner matrix. **Breaking changes** Middle stack layers no longer run the complete CI matrix. Their `ci / verify` and `ci / e2e` checks still require the policy job to pass and require every expensive lane to be intentionally skipped. ## What Changed - Add a fail-safe stack scope decision to the trusted PR runner gate. - Run typecheck, general tests, build, serialized tests, canary, and E2E shards only for ordinary, top, and lowest-unmerged pull requests. - Preserve the required `ci / verify` and `ci / e2e` names on every layer. - Make the required aggregators distinguish valid middle-layer skips from failures or missing scope decisions. - Add regression coverage for ordinary, top, bottom, middle, and malformed stack metadata. ## Verification - `node --test scripts/__tests__/e2e-shard.test.mjs` — 11 tests passed. - `actionlint .github/workflows/pr-trusted.yml .github/workflows/pr.yml` — passed. - `git diff --check origin/master...HEAD` — passed. - The caller remains pinned to the current trusted workflow. A separate activation change must advance the immutable SHA after this pull request lands. ## Risks - Incorrect stack classification could skip important jobs. Missing or malformed stack metadata defaults to full CI. - Middle-layer required checks depend on the policy job and verify that all expensive jobs have the `skipped` result. - The reusable workflow change does not become active until the immutable caller SHA advances in a separate change. > For core feature work, check [`ROADMAP.md`](ROADMAP.md) first and discuss it in `#dev` before opening the PR. Feature PRs that overlap with planned core work may need to be redirected — check the roadmap first. See `CONTRIBUTING.md`. ## Model Used - OpenAI Codex with GPT-5. The exact deployment suffix and context window are not exposed. The model used reasoning, repository tools, code execution, Git, and GitHub API access. ## Checklist - [x] I have included a thinking path that traces from project context to this change - [x] I have specified the model used (with version and capability details) - [x] I have checked ROADMAP.md and confirmed this PR does not duplicate planned core work - [x] I have searched GitHub for duplicate or related PRs and linked them above - [x] I have either (a) linked existing issues with `Fixes: #` / `Closes: #` / `Refs: #` OR (b) described the issue in-PR following the relevant issue template - [x] I have not referenced internal/instance-local Paperclip issues or links (only public GitHub `#NNN` / `github.com/paperclipai/paperclip` URLs) - [x] My branch name describes the change (e.g. `docs/...`, `fix/...`) and contains no internal Paperclip ticket id or instance-derived details - [x] I have run tests locally and they pass - [x] I have added or updated tests where applicable - [x] I have updated relevant documentation to reflect my changes - [x] I have considered and documented any risks above - [ ] All Paperclip CI gates are green - [x] Greptile is 5/5 with no open P2s, recommendations, or follow-ups - [x] I will address all Greptile and reviewer comments before requesting merge --------- Co-authored-by: Paperclip <noreply@paperclip.ing> |
||
|
|
d7ff895a9a |
chore: add @forgottendev to CODEOWNERS (#12501)
## Thinking Path > - Paperclip uses GitHub ownership rules to protect critical repository files. > - These rules cover release infrastructure, GitHub configuration, skills, and dependency files. > - The current rules do not include `@forgottendev`. > - The new maintainer needs the same review scope as the existing code owners. > - This pull request adds `@forgottendev` to every existing CODEOWNERS rule. > - The benefit is consistent review ownership without a change to the protected path set. ## Linked Issues or Issue Description **What existing behavior does this improve?** This change improves the GitHub review ownership for critical repository files. **Subsystem affected** Repository governance and GitHub configuration. **Current behavior** The 13 existing CODEOWNERS rules list `@cryppadotta`, `@devinfoley`, and `@nickyleach`. They do not list `@forgottendev`. **Proposed behavior** Every existing CODEOWNERS rule also lists `@forgottendev`. **Reason and benefit** This gives `@forgottendev` the same review ownership scope as the existing maintainers. It keeps ownership consistent across all protected paths. **Breaking changes** None. This change does not remove an owner or change a path pattern. ## What Changed - Added `@forgottendev` to all 13 existing entries in `.github/CODEOWNERS`. - Kept all existing owners and path patterns unchanged. ## Verification - Ran `git diff --check origin/master..HEAD`. - Confirmed that all 13 active CODEOWNERS rules contain `@forgottendev`. - Confirmed that the commit changes only `.github/CODEOWNERS`. - Confirmed that the GitHub account `forgottendev` exists. - Did not run the application test suite because this change only updates GitHub ownership metadata. ## Risks - Low risk. This is an additive ownership change. - GitHub can request review from `@forgottendev` for future pull requests that change a covered path. > For core feature work, check [`ROADMAP.md`](ROADMAP.md) first and discuss it in `#dev` before opening the PR. Feature PRs that overlap with planned core work may need to be redirected — check the roadmap first. See `CONTRIBUTING.md`. ## Model Used OpenAI Codex based on GPT-5, with reasoning, shell access, and GitHub CLI tool use. The hosted context-window size was not exposed. ## Checklist - [x] I have included a thinking path that traces from project context to this change - [x] I have specified the model used (with version and capability details) - [x] I have checked ROADMAP.md and confirmed this PR does not duplicate planned core work - [x] I have searched GitHub for duplicate or related PRs and linked them above - [x] I have either (a) linked existing issues with `Fixes: #` / `Closes #` / `Refs #` OR (b) described the issue in-PR following the relevant issue template - [x] I have not referenced internal/instance-local Paperclip issues or links (only public GitHub `#NNN` / `github.com/paperclipai/paperclip` URLs) - [x] My branch name describes the change (e.g. `docs/...`, `fix/...`) and contains no internal Paperclip ticket id or instance-derived details - [x] I have run tests locally and they pass - [x] I have added or updated tests where applicable - [x] I have updated relevant documentation to reflect my changes - [x] I have considered and documented any risks above - [ ] All Paperclip CI gates are green - [ ] Greptile is 5/5 with no open P2s, recommendations, or follow-ups - [x] I will address all Greptile and reviewer comments before requesting merge Co-authored-by: Paperclip <noreply@paperclip.ing> |
||
|
|
40d8cbc41a |
ci: activate stacked lockfile regeneration (#12464)
## Thinking Path > - Paperclip uses trusted GitHub Actions workflows to verify each pull request. > - The caller pins the reusable workflow to an immutable merged commit. > - Native stacked pull requests can inherit a stale lockfile from a parent layer. > - Pull request #12461 added safe merge-tree lockfile regeneration to the trusted workflow. > - The caller must now select that merged workflow version. > - This pull request advances the immutable pin to the merge commit from #12461. > - The benefit is reliable verification for native stacked pull requests. ## Linked Issues or Issue Description Refs #12461 ## What Changed - Pin the trusted pull request workflow to merged commit `1da6b37fc56dacf5e7ffbd31da35756a1cba41f8`. - Activate stale lockfile regeneration for native stacked pull requests. ## Verification - `actionlint .github/workflows/pr.yml` - `node --test scripts/__tests__/e2e-shard.test.mjs` ## Risks - Low risk. This changes only the immutable reusable-workflow pin. - The target commit is merged into `master` and passed all required checks. - The target workflow adds one lockfile-only install to the policy job. > For core feature work, check [`ROADMAP.md`](ROADMAP.md) first and discuss it in `#dev` before opening the PR. Feature PRs that overlap with planned core work may need to be redirected — check the roadmap first. See `CONTRIBUTING.md`. ## Model Used OpenAI Codex with model `gpt-5`, reasoning, tool use, and code execution. ## Checklist - [x] I have included a thinking path that traces from project context to this change - [x] I have specified the model used (with version and capability details) - [x] I have checked ROADMAP.md and confirmed this PR does not duplicate planned core work - [x] I have searched GitHub for duplicate or related PRs and linked them above - [x] I have either (a) linked existing issues with `Fixes: #` / `Closes #` / `Refs #` OR (b) described the issue in-PR following the relevant issue template - [x] I have not referenced internal/instance-local Paperclip issues or links (only public GitHub `#NNN` / `github.com/paperclipai/paperclip` URLs) - [x] My branch name describes the change (e.g. `docs/...`, `fix/...`) and contains no internal Paperclip ticket id or instance-derived details - [x] I have run tests locally and they pass - [x] I have added or updated tests where applicable - [x] I have updated relevant documentation to reflect my changes - [x] I have considered and documented any risks above - [x] All Paperclip CI gates are green - [x] Greptile is 5/5 with no open P2s, recommendations, or follow-ups - [x] I will address all Greptile and reviewer comments before requesting merge |
||
|
|
1da6b37fc5 |
fix(ci): regenerate stale stacked lockfiles (#12461)
## Thinking Path > - Paperclip uses trusted GitHub Actions workflows to verify every pull request > - Native stacked pull requests use another pull request branch as their base > - A parent layer can change a package manifest without committing `pnpm-lock.yaml` > - A child layer can inherit that manifest change without changing a manifest itself > - The current policy skips lockfile regeneration for that child and downstream frozen installs fail > - This pull request validates the complete merge tree and shares a regenerated lockfile only when needed > - The benefit is reliable stacked pull request verification without weakening the trusted workflow boundary ## Linked Issues or Issue Description **What happened?** A stacked child pull request inherited a package manifest change from its parent. The child did not change a manifest itself. The policy job skipped lockfile regeneration. Downstream jobs tried to restore an artifact that did not exist and then failed during frozen dependency installation. **Expected behavior** The policy job must validate the complete pull request merge tree. It must upload a regenerated lockfile when the checked-in lockfile is stale, including on a stacked child layer. **Steps to reproduce** 1. Create a parent pull request that changes `package.json` without committing `pnpm-lock.yaml`. 2. Create a child pull request on that branch without another manifest change. 3. Run the trusted pull request workflow for the child. 4. Observe that frozen dependency installation fails because no `pr-lockfile` artifact exists. **Paperclip version or commit** `f173ee09fa5c2ced7806bba47b54c3df853ab4df` **Deployment mode** GitHub Actions trusted pull request workflow. **Agent adapter(s) involved** Not adapter-specific. This is a core CI workflow bug. ## What Changed - Regenerate the lockfile from every checked-out merge tree. - Compare the generated lockfile with the checked-in copy before upload. - Download the artifact only when the policy job reports that it uploaded one. - Fail closed when a reported artifact is missing. - Add a workflow contract test for stacked lockfile handling. - Keep the caller pinned to the last merged trusted SHA; after this implementation merges, a separate activation PR will advance the immutable pin to its merge commit. ## Verification - `actionlint .github/workflows/pr-trusted.yml` - `node --test scripts/__tests__/e2e-shard.test.mjs` ## Risks - The policy job runs one lockfile-only install for every pull request. This can add a small amount of CI time. - A missing artifact now fails immediately when the policy job reports an upload. This is intentional because it exposes workflow corruption. - No runtime or product behavior changes. - The implementation/activation split is intentional: unmerged PR-authored workflow code must never execute on trusted runners. ## Model Used OpenAI Codex with model `gpt-5`, reasoning, tool use, and code execution. ## Checklist - [x] I have included a thinking path that traces from project context to this change - [x] I have specified the model used (with version and capability details) - [x] I have checked ROADMAP.md and confirmed this PR does not duplicate planned core work - [x] I have searched GitHub for duplicate or related PRs and linked them above - [x] I have either (a) linked existing issues with `Fixes: #` / `Closes #` / `Refs #` OR (b) described the issue in-PR following the relevant issue template - [x] I have not referenced internal/instance-local Paperclip issues or links (only public GitHub `#NNN` / `github.com/paperclipai/paperclip` URLs) - [x] My branch name describes the change (e.g. `docs/...`, `fix/...`) and contains no internal Paperclip ticket id or instance-derived details - [x] I have run tests locally and they pass - [x] I have added or updated tests where applicable - [x] I have updated relevant documentation to reflect my changes - [x] I have considered and documented any risks above - [x] All Paperclip CI gates are green - [x] Greptile is 5/5 with no open P2s, recommendations, or follow-ups - [x] I will address all Greptile and reviewer comments before requesting merge |
||
|
|
f173ee09fa |
ci: activate stale base handling (#12463)
## Thinking Path
> - Paperclip uses pull request checks to protect changes.
> - The trusted workflow selects GitHub or AWS runners.
> - Pull request #12462 removed an unreliable stale API equality.
> - The public caller must pin an immutable trusted workflow commit.
> - This pull request changes only that pin.
> - The benefit is correct AWS routing for trusted stacked pull
requests.
## Linked Issues or Issue Description
Refs #12339
Refs #12462
## What Changed
- Pin the thin pull request caller to
|
||
|
|
f9c32513b2 |
ci: ignore stale PR API base snapshots (#12462)
## Thinking Path > - Paperclip uses pull request checks to protect changes. > - The trusted CI gate selects GitHub or AWS runners. > - GitHub can return an old pull request base SHA after the live base advances. > - The signed event, live Git ref, ancestry, and merge parents provide the required proof. > - The stale API field rejects a safe run even when those proofs pass. > - This pull request removes that unreliable equality. > - The benefit is correct AWS routing for trusted stacked pull requests. ## Linked Issues or Issue Description Refs #12339 Refs #12459 ## What Changed - Stop treating pull request base.sha as a current-state signal. - Keep the signed event base SHA and live ref descendant check. - Keep the live base or synthetic base merge-parent proof. - Keep all numeric identity, repository, head SHA, and triggering actor checks. ## Verification - actionlint .github/workflows/pr-trusted.yml .github/workflows/pr.yml - github-runners/tests/test-workflow.sh .github/workflows/pr-trusted.yml .github/workflows/pr.yml - The corrected gate selected the Fleet label with the exact live event data from PR #12339 run 33201610330. ## Risks - The pull request API base SHA can be stale and is no longer compared. - Replaced ancestry, a changed head, a changed merge parent, and a changed merge tree still fail closed. ## Model Used - OpenAI Codex, GPT-5.6, with reasoning and terminal tool use. ## Checklist - [x] I have included a thinking path that traces from project context to this change - [x] I have specified the model used with version and capability details - [x] I have checked ROADMAP.md and confirmed this PR does not duplicate planned core work - [x] I have searched GitHub for duplicate or related PRs and linked them above - [x] I have linked existing public pull requests - [x] I have not referenced internal or instance-local Paperclip issues or links - [x] My branch name describes the change and contains no internal ticket ID - [x] I have run tests locally and they pass - [x] I have added or updated tests where applicable - [x] I have updated relevant documentation in the operations repository - [x] I have considered and documented risks above - [ ] All Paperclip CI gates are green - [ ] Greptile is 5/5 with no open findings - [x] I will address all Greptile and reviewer comments before requesting merge |
||
|
|
30ac5e116e |
ci: activate live stacked base validation (#12460)
## Thinking Path
> - Paperclip uses pull request checks to protect changes.
> - The trusted CI workflow selects GitHub or AWS runners.
> - Pull request #12459 fixed validation when a stacked base advances.
> - The public caller must use an immutable trusted workflow SHA.
> - This pull request changes only that SHA.
> - The benefit is automatic AWS routing for the affected trusted stack
runs.
## Linked Issues or Issue Description
Refs #12339
Refs #12459
## What Changed
- Pin the thin pull request caller to
|
||
|
|
f929355fb9 |
ci: allow validated stacked base advances (#12459)
## Thinking Path > - Paperclip uses pull request checks to protect changes. > - The trusted CI workflow selects GitHub or AWS runners. > - Stacked pull requests can advance their base branch while a gate waits. > - The gate already proves that the live base descends from the event base. > - An earlier exact base check rejects that safe state before the ancestry check runs. > - This pull request removes the conflicting check and verifies live API consistency. > - The benefit is automatic AWS routing for trusted stacked pull requests without weaker identity checks. ## Linked Issues or Issue Description Refs #12339 Refs #12457 ## What Changed - Allow the live pull request base SHA to advance from the signed event base snapshot. - Require the pull request API base SHA to match the live Git ref during validation. - Keep the numeric author, sender, and triggering actor checks. - Keep descendant ancestry and synthetic merge validation. ## Verification - actionlint .github/workflows/pr-trusted.yml .github/workflows/pr.yml - github-runners/tests/test-workflow.sh .github/workflows/pr-trusted.yml .github/workflows/pr.yml - The routing suite covers a live stacked base advance and a base change during validation. ## Risks - A trusted stacked run can use a newer descendant base than its signed event snapshot. - Replaced ancestry still fails closed. - A live base change during gate validation still fails closed. ## Model Used - OpenAI Codex, GPT-5.6, with reasoning and terminal tool use. ## Checklist - [x] I have included a thinking path that traces from project context to this change - [x] I have specified the model used (with version and capability details) - [x] I have checked ROADMAP.md and confirmed this PR does not duplicate planned core work - [x] I have searched GitHub for duplicate or related PRs and linked them above - [x] I have either linked existing issues or described the issue in this pull request - [x] I have not referenced internal or instance-local Paperclip issues or links - [x] My branch name describes the change and contains no internal ticket ID - [x] I have run tests locally and they pass - [x] I have added or updated tests where applicable - [x] I have updated relevant documentation in the operations repository - [x] I have considered and documented risks above - [ ] All Paperclip CI gates are green - [ ] Greptile is 5/5 with no open findings - [x] I will address all Greptile and reviewer comments before requesting merge |
||
|
|
c594811f3c |
ci: activate stacked merge validation (#12458)
## Thinking Path
> - Paperclip is the open source app people use to manage AI agents for
work.
> - Pull request checks protect the application and its contributors.
> - The trusted CI gate must validate both direct and stacked GitHub
merge shapes.
> - Pull request #12457 added that validation at an immutable master
SHA.
> - The active caller still pins the prior workflow version.
> - This pull request pins the caller to the newly authorized SHA.
> - The benefit is safe automatic AWS routing for trusted stacked pull
requests.
## Linked Issues or Issue Description
Refs #12457
**What existing behavior does this improve?**
The active caller uses a gate that fails closed on GitHub synthetic
stacked merge parents.
**Subsystem affected**
GitHub Actions pull request routing.
**Current behavior**
Trusted stacked pull requests run on GitHub-hosted runners after the
merge-parent check rejects the synthetic base merge.
**Proposed behavior**
The caller uses the authorized workflow SHA
|
||
|
|
7b199fcafa |
fix(ci): validate stacked PR merge refs (#12457)
## Thinking Path > - Paperclip is the open source app people use to manage AI agents for work. > - Pull request checks protect the application and its contributors. > - The trusted CI gate verifies signed event data against live GitHub state. > - GitHub gives a stacked pull request a synthetic merge commit for its base stack. > - The current validator expects the raw base SHA as the first merge parent. > - That assumption sends safe stacked pull requests to GitHub-hosted runners. > - This pull request validates the synthetic base merge and its ancestry explicitly. > - The benefit is safe automatic AWS routing for approved stacked pull requests. ## Linked Issues or Issue Description Refs #12455 Refs #12456 **What existing behavior does this improve?** The trusted runner gate validates merge commits for master-based pull requests but rejects GitHub synthetic base merges for stacked pull requests. **Subsystem affected** GitHub Actions pull request identity and merge-state validation. **Current behavior** A trusted stacked pull request passes all numeric identity checks. The gate fails closed because the first event merge parent is a GitHub synthetic base merge instead of the raw base snapshot SHA. **Proposed behavior** The gate verifies the current base-ref tip, base-snapshot ancestry, identical event and live merge parents, the child head parent, the synthetic base merge parents, and identical event and live merge trees. **Reason and benefit** The change preserves fail-closed live-state validation while allowing approved stacked pull requests to use the isolated AWS Fleet. **Breaking changes** None for untrusted contributors. Trusted stacked pull requests can select AWS after the caller pins this workflow version. **Additional context** GitHub builds a stacked test merge in two steps. It first merges the stack base into its own current base. It then uses that synthetic commit as the first parent of the child test merge. ## What Changed - Fetch and validate the current base branch ref. - Require the event base snapshot to remain an ancestor of that ref. - Validate direct and synthetic base merge parent shapes. - Preserve the existing child-head, live-state, merge-tree, repository, and actor checks. ## Verification - Ran actionlint on the trusted workflow. - Ran the external routing suite. - Added positive coverage for the GitHub stacked merge shape. - Added fail-closed coverage for replaced base ancestry and a synthetic merge that omits the current base ref. - Replayed the checks against the live merge shape for pull request #12340. ## Risks The gate has more GitHub API reads. Its five-minute timeout and fail-closed behavior limit the effect of API errors. The accepted synthetic commit must be the same in the event and live merge, must include the current base branch as a direct parent, and must produce the same merge tree. > For core feature work, check ROADMAP.md first and discuss it in #dev before opening the PR. Feature PRs that overlap with planned core work may need to be redirected — check the roadmap first. See CONTRIBUTING.md. ## Model Used OpenAI Codex on GPT-5. The exact deployment ID and context-window size are not exposed. The model used reasoning, tool use, GitHub API access, and local code execution. ## Checklist - [x] I have included a thinking path that traces from project context to this change - [x] I have specified the model used with version and capability details - [x] I have checked ROADMAP.md and confirmed this PR does not duplicate planned core work - [x] I have searched GitHub for duplicate or related PRs and linked them above - [x] I have linked existing public items and described the issue in-PR - [x] I have not referenced internal or instance-local Paperclip issues or links - [x] My branch name describes the change and contains no internal Paperclip ticket id - [x] I have run tests locally and they pass - [x] I have added or updated tests where applicable - [x] I have updated relevant documentation to reflect my changes - [x] I have considered and documented any risks above - [ ] All Paperclip CI gates are green - [ ] Greptile is 5/5 with no open P2s, recommendations, or follow-ups - [x] I will address all Greptile and reviewer comments before requesting merge |
||
|
|
e48e0bd3c2 |
ci: activate trusted stacked PR routing (#12456)
## Thinking Path
> - Paperclip is the open source app people use to manage AI agents for
work.
> - Pull request checks protect the application and its contributors.
> - The trusted CI workflow sends approved contributors to isolated AWS
runners.
> - Pull request #12455 added safe support for non-master base branches.
> - The active caller still filters for master and uses the previous
immutable workflow SHA.
> - This pull request removes the base-branch trigger filter and pins
the caller to the authorized stack-aware SHA.
> - The benefit is that trusted stacked pull requests can use the AWS
fleet automatically.
## Linked Issues or Issue Description
Refs #12455
**What existing behavior does this improve?**
The active pull request caller only triggers for master and selects the
master-only trusted workflow version.
**Subsystem affected**
GitHub Actions pull request routing.
**Current behavior**
Trusted stacked pull requests either do not trigger the default caller
or use a branch-local older caller. Their heavy jobs remain in the
GitHub-hosted queue.
**Proposed behavior**
The caller triggers for every pull request base branch. It uses the
authorized stack-aware workflow at full SHA
|
||
|
|
d6b33d6c16 |
fix(ci): route trusted stacked PRs to AWS (#12455)
## Thinking Path > - Paperclip is the open source app people use to manage AI agents for work. > - Pull request checks protect the application and its contributors. > - The trusted CI workflow sends approved contributors to isolated AWS runners. > - The workflow currently limits AWS routing to pull requests that target master. > - Stacked pull requests target another branch and stay in the GitHub queue. > - This pull request keeps the identity checks and accepts a live nonempty base branch in the Paperclip repository. > - The benefit is that trusted stacked pull requests can use the AWS fleet automatically. ## Linked Issues or Issue Description **What existing behavior does this improve?** The trusted pull request runner gate currently sends only master-based pull requests to AWS. **Subsystem affected** GitHub Actions pull request routing. **Current behavior** A trusted contributor can pass all numeric identity checks. The gate still selects GitHub-hosted runners when the pull request targets another branch in a stack. **Proposed behavior** The gate accepts any nonempty base branch in the Paperclip base repository. It still verifies the live base ref, base SHA, head SHA, merge SHA, author ID, sender ID, and triggering actor ID. **Reason and benefit** Large pull request stacks currently add all heavy jobs to the limited GitHub-hosted queue. This change lets approved contributors use the isolated AWS fleet for those jobs. **Breaking changes** Trusted pull requests that target a non-master branch now use AWS instead of GitHub-hosted runners. Untrusted pull requests keep the current GitHub-hosted route. **Additional context** Pull request #12339 is the master-based first item in a stack. Its child pull requests show this queue pattern. ## What Changed - Replace the master-only route check with a nonempty base-ref check. Keep the existing base-repository and live-state checks. ## Verification - Ran actionlint on .github/workflows/pr-trusted.yml. - Ran the external routing test suite. It passed the trusted stacked-base case and all fail-closed identity cases. ## Risks The AWS trust boundary now includes code from a non-master base branch when the current pull request author, sender, and triggering actor are all approved numeric GitHub IDs. An approved account can already submit arbitrary head code. The runner remains isolated and has no production access or repository secrets. > For core feature work, check ROADMAP.md first and discuss it in #dev before opening the PR. Feature PRs that overlap with planned core work may need to be redirected — check the roadmap first. See CONTRIBUTING.md. ## Model Used OpenAI Codex on GPT-5. The exact deployment ID and context-window size are not exposed. The model used reasoning, tool use, GitHub API access, and local code execution. ## Checklist - [x] I have included a thinking path that traces from project context to this change - [x] I have specified the model used (with version and capability details) - [x] I have checked ROADMAP.md and confirmed this PR does not duplicate planned core work - [x] I have searched GitHub for duplicate or related PRs and linked them above - [x] I have either (a) linked existing issues with Fixes: # / Closes # / Refs # OR (b) described the issue in-PR following the relevant issue template - [x] I have not referenced internal/instance-local Paperclip issues or links - [x] My branch name describes the change and contains no internal Paperclip ticket id - [x] I have run tests locally and they pass - [x] I have added or updated tests where applicable - [x] I have updated relevant documentation to reflect my changes - [x] I have considered and documented any risks above - [ ] All Paperclip CI gates are green - [ ] Greptile is 5/5 with no open P2s, recommendations, or follow-ups - [x] I will address all Greptile and reviewer comments before requesting merge |
||
|
|
66e1c0df8b |
ci: pin PR base snapshot validation (#12450)
## Summary - rotate the thin caller from `5ac66b3fdd5dc22c0c4e5fdb234ac063cf1d9ff8` to `c119c4bee6ebb9c81791d7a6994f1be06d7cc22b` - keep both exact SHAs authorized during rotation - keep AWS routing disabled until verification completes ## Validation - actionlint passes - workflow-contract tests pass - internal trust-routing harness passes |
||
|
|
c119c4bee6 |
fix(ci): validate the PR base snapshot (#12449)
## Summary - validate the event base ref/SHA against the live PR state instead of requiring the moving `master` branch tip to remain unchanged while a hosted gate queues - retain exact event/live merge parent and tree validation, plus author/sender/rerun checks ## Canary finding A seven-minute hosted-gate queue allowed `master` to advance. Requiring the live branch tip to equal the event base snapshot would route otherwise valid trusted runs back to GitHub-hosted indefinitely on a busy repository. ## Validation - actionlint and workflow-contract tests pass - internal routing harness passes - replaced PR base snapshot, stale head, changed merge parent/tree, and untrusted actors all remain fail-closed - AWS routing remains disabled during rotation |
||
|
|
5a9c06ab66 |
ci: pin workflow merge ref validation (#12448)
## Summary
- rotate the thin caller from `b88fadb0390d2113933d5d155f16b07cbd5dafee`
to `5ac66b3fdd5dc22c0c4e5fdb234ac063cf1d9ff8`
- keep both exact SHAs authorized during rotation
- keep AWS routing disabled until verification completes
## Validation
- actionlint passes
- e2e workflow-contract tests pass
- internal routing harness validates a single output and `${{ github.sha
}}` merge-ref source
|
||
|
|
5ac66b3fdd |
fix(ci): validate the workflow merge ref (#12447)
## Summary
- use `${{ github.sha }}` as the event merge commit validated by the
trusted gate
- retain exact base/head parent and identical-tree comparison against
the current live merge ref
## Canary finding
GitHub leaves `pull_request.merge_commit_sha` empty on some `opened`
payloads even though the workflow runs against a valid merge ref. The
gate safely fell back to GitHub-hosted and no EC2 instance launched.
## Validation
- `actionlint .github/workflows/pr-trusted.yml .github/workflows/pr.yml`
- `node --test ./scripts/__tests__/e2e-shard.test.mjs`
- internal routing harness passes and asserts `EVENT_MERGE_SHA` is
sourced from `${{ github.sha }}`
- AWS routing remains disabled during rotation
|
||
|
|
c75507fd3f |
ci: pin single runner route output (#12445)
## Summary - rotate the thin PR caller from `3b295b05dc8c8dd82c12e4a9c6f721446c5cb2e8` to `b88fadb0390d2113933d5d155f16b07cbd5dafee` - keep both exact SHAs authorized during the rotation - keep AWS routing disabled until the caller and boundary verify ## Validation - `actionlint .github/workflows/pr.yml .github/workflows/pr-trusted.yml` - `node --test ./scripts/__tests__/e2e-shard.test.mjs` - internal routing harness requires exactly one runner output per gate execution |
||
|
|
b88fadb039 |
fix(ci): emit one runner route (#12444)
## Summary - emit exactly one `runner` job output from the trusted gate - write `ubuntu-latest` only inside fail-closed paths - write the Fleet label only after every identity, PR-state, merge-equivalence, and rerun-actor check passes ## Canary finding The live gate reached the trusted success notice, but GitHub retained the first of two duplicate `runner=` outputs, so policy still requested `ubuntu-latest`. No EC2 instance launched. Routing was disabled immediately. ## Validation - `actionlint .github/workflows/pr-trusted.yml .github/workflows/pr.yml` - `node --test ./scripts/__tests__/e2e-shard.test.mjs` - internal routing harness passes and now requires exactly one runner output in all cases - AWS routing remains disabled during rotation |
||
|
|
de00d78854 |
ci: pin equivalent merge validation (#12442)
## Summary - rotate the thin PR caller from `d9fc93d8383ece6fba721881a7aba638867f4996` to `3b295b05dc8c8dd82c12e4a9c6f721446c5cb2e8` - keep both exact workflow SHAs authorized in the runner group during the rotation - keep `AWS_CI_ENABLED=false` until this caller is merged and verified ## Validation - `actionlint .github/workflows/pr.yml .github/workflows/pr-trusted.yml` - `node --test ./scripts/__tests__/e2e-shard.test.mjs` - full AWS/GitHub boundary verification passes with zero active runners |
||
|
|
3b295b05dc |
fix(ci): validate equivalent PR merge refs (#12441)
## Summary - validate the live master ref and event base SHA before AWS routing - accept GitHub synthetic merge commits only when the event and live commits have the exact expected base/head parents and identical tree - preserve fail-closed routing for malformed, stale, replaced, or untrusted events ## Canary finding A trusted reopened PR produced two synthetic merge SHAs with different timestamps but identical current base/head parents and tree. The former exact-SHA comparison safely fell back to GitHub-hosted runners, but could not route a valid event to AWS. ## Validation - `actionlint .github/workflows/pr-trusted.yml .github/workflows/pr.yml` - `node --test ./scripts/__tests__/e2e-shard.test.mjs` - real-event gate simulation selects the Fleet label for equivalent merge commits - negative simulations keep an untrusted sender and replaced head on `ubuntu-latest` - AWS routing remains disabled during rotation |
||
|
|
c916af0cc0 |
ci: call trusted PR workflow (#12439)
## Thinking Path > - Paperclip uses pull request CI to validate each proposed change > - The existing workflow defines every heavy job in a PR-controlled file > - A trusted reusable workflow now contains the synchronized CI definition > - The caller must use an immutable default-branch SHA > - This pull request replaces the duplicate job list with that pinned caller > - The benefit is automatic secure runner selection without workflow drift ## Linked Issues or Issue Description Refs #12436 Refs #12438 **What existing behavior does this improve?** This improves how the pull request workflow selects trusted CI capacity. **Subsystem affected** Cross-cutting CI automation. **Current behavior** The active workflow contains a duplicate list of all heavy jobs. It cannot use the administrator-controlled runner gate. **Proposed behavior** The active workflow calls the synchronized trusted workflow at an immutable SHA. The trusted workflow selects GitHub-hosted or isolated AWS capacity from the validated contributor identity. **Reason and benefit** The thin caller prevents pull request changes from replacing the external-runner security gate. It also keeps runner selection automatic. **Breaking changes** The check names gain the reusable workflow job prefix. AWS routing remains disabled until the canary starts. ## What Changed - Replaced the duplicated heavy CI job list with one reusable-workflow call. - Pinned the call to the reviewed default-branch commit. - Limited the caller token to actions, contents, and pull request read access. ## Verification - actionlint on both workflow files - Trusted-routing tests - Confirmed the pinned SHA contains the workflow and is an ancestor of master - Full AWS and GitHub runner-boundary verification with routing disabled ## Risks The check context names change when GitHub expands the reusable workflow. The rollout verifies the new aggregate contexts before branch rules change. The repository kill switch remains off during this pull request. ## Model Used OpenAI Codex with GPT-5, tool use, and code execution. ## Checklist - [x] I have included a thinking path that traces from project context to this change - [x] I have specified the model used (with version and capability details) - [x] I have checked ROADMAP.md and confirmed this PR does not duplicate planned core work - [x] I have searched GitHub for duplicate or related PRs and linked them above - [x] I have either linked a related public PR or described the issue with the matching template fields - [x] I have not referenced internal or instance-local Paperclip issues or links - [x] My branch name describes the change and contains no internal Paperclip ticket id - [x] I have run tests locally and they pass - [x] I have added or updated tests where applicable - [x] I have updated relevant documentation to reflect my changes - [x] I have considered and documented any risks above - [ ] All Paperclip CI gates are green - [ ] Greptile is 5/5 with no open P2s, recommendations, or follow-ups - [ ] I will address all Greptile and reviewer comments before requesting merge |
||
|
|
d9fc93d838 |
ci: synchronize trusted PR policy (#12438)
## Thinking Path > - Paperclip uses pull request CI to protect changes before merge > - The trusted reusable workflow will select isolated AWS capacity > - The active workflow changed while the reusable workflow waited for merge > - The reusable policy must contain every current CI policy step before activation > - This pull request synchronizes the migration-order check and shell validation > - The benefit is one reviewed workflow version with verified job parity ## Linked Issues or Issue Description Refs #12436 **What existing behavior does this improve?** This improves the pull request CI workflow synchronization before AWS runner activation. **Subsystem affected** Cross-cutting CI automation. **Current behavior** The active workflow validates migration order. The new reusable workflow does not yet contain that check. **Proposed behavior** Both workflow definitions contain the same heavy jobs and policy steps before the active workflow becomes a thin caller. **Reason and benefit** The synchronization prevents policy drift during the two-step secure rollout. **Breaking changes** None. AWS routing remains disabled. ## What Changed - Added the current migration-order validation to the trusted workflow. - Added the existing shellcheck intent annotation to the active workflow. - Verified normalized heavy-job parity between both definitions. ## Verification - actionlint on both workflow files - Local trusted-routing and normalized workflow-parity tests - git diff --check ## Risks Low risk. The migration check already runs in active CI. This change copies it into the inactive trusted definition. AWS routing stays disabled. ## Model Used OpenAI Codex with GPT-5, tool use, and code execution. ## Checklist - [x] I have included a thinking path that traces from project context to this change - [x] I have specified the model used (with version and capability details) - [x] I have checked ROADMAP.md and confirmed this PR does not duplicate planned core work - [x] I have searched GitHub for duplicate or related PRs and linked them above - [x] I have either linked a related public PR or described the issue with the matching template fields - [x] I have not referenced internal or instance-local Paperclip issues or links - [x] My branch name describes the change and contains no internal Paperclip ticket id - [x] I have run tests locally and they pass - [x] I have added or updated tests where applicable - [x] I have updated relevant documentation to reflect my changes - [x] I have considered and documented any risks above - [ ] All Paperclip CI gates are green - [ ] Greptile is 5/5 with no open P2s, recommendations, or follow-ups - [ ] I will address all Greptile and reviewer comments before requesting merge |
||
|
|
07b6816829 |
ci: add trusted reusable PR workflow (#12436)
## Thinking Path > - Paperclip is the open source app people use to manage AI agents for work > - Pull request checks protect the quality of the control plane > - The current checks depend only on the shared GitHub-hosted runner limit > - Busy periods leave many pull request jobs queued even when external capacity is available > - Public pull request code must not select or directly access private runner infrastructure > - This pull request adds an inactive reusable workflow with a fail-closed identity gate > - A later pull request can pin this workflow by its full master commit SHA > - The benefit is automatic, controlled access to isolated runner capacity without changing current CI during bootstrap ## Linked Issues or Issue Description **What existing behavior does this improve?** This improves the pull request CI workflow. It prepares the existing checks to use an administrator-controlled runner selection. **Subsystem affected** Cross-cutting GitHub Actions CI configuration. **Current behavior** Every pull request job uses `ubuntu-latest`. Jobs wait when the GitHub-hosted concurrency limit is full. **Proposed behavior** Add a reusable copy of the current PR workflow. A GitHub-hosted gate validates durable numeric user IDs and current GitHub API state. The gate emits one runner label. The default and every validation failure use `ubuntu-latest`. The AWS label is possible only when an administrator enables it and every identity check passes. This bootstrap pull request does not change the active `.github/workflows/pr.yml` caller. A follow-up change will call this workflow by the full master commit SHA. **Reason and benefit** The split bootstrap creates an immutable trust boundary before external runners are reachable. It also keeps CI automatic for contributors. Contributors do not select a runner. **Breaking changes** None in this bootstrap pull request. The active PR workflow does not change. ## What Changed - Added an inactive `workflow_call` copy of the current PR checks. - Added a GitHub-hosted routing gate that checks the repository ID, pull request author ID, event sender ID, rerun actor ID, base branch, head SHA, merge SHA, and current pull request state. - Made every validation failure select `ubuntu-latest`. - Pinned every third-party action to a full commit SHA. - Disabled persistent checkout credentials for all jobs. - Limited the workflow token to Actions read, contents read, and pull request read access. ## Verification - `actionlint .github/workflows/pr-trusted.yml` - Ran the dedicated workflow routing test harness against `.github/workflows/pr-trusted.yml`. - Compared the job keys with `.github/workflows/pr.yml`. The new workflow contains every existing job plus the gate. - Verified each pinned action commit against its current GitHub major-version tag. ## Risks The gate could route a trusted pull request to the wrong runner if an identity check is incomplete. The gate checks durable numeric IDs from the event and current GitHub API state. It checks the rerun actor separately. It defaults to GitHub-hosted capacity before any validation runs. This file is inactive in this pull request. The follow-up caller and runner-group restriction must use the exact commit that reaches `master`. > For core feature work, check [`ROADMAP.md`](ROADMAP.md) first and discuss it in `#dev` before opening the PR. Feature PRs that overlap with planned core work may need to be redirected — check the roadmap first. See `CONTRIBUTING.md`. ## Model Used OpenAI Codex based on GPT-5. The exact serving model ID and context-window size are not exposed in this environment. The model used high-reasoning, terminal, GitHub API, browser, and web-research capabilities. ## Checklist - [x] I have included a thinking path that traces from project context to this change - [x] I have specified the model used (with version and capability details) - [x] I have checked ROADMAP.md and confirmed this PR does not duplicate planned core work - [x] I have searched GitHub for duplicate or related PRs and linked them above - [x] I have either (a) linked existing issues with `Fixes: #` / `Closes #` / `Refs #` OR (b) described the issue in-PR following the relevant issue template - [x] I have not referenced internal/instance-local Paperclip issues or links (only public GitHub `#NNN` / `github.com/paperclipai/paperclip` URLs) - [x] My branch name describes the change (e.g. `docs/...`, `fix/...`) and contains no internal Paperclip ticket id or instance-derived details - [x] I have run tests locally and they pass - [x] I have added or updated tests where applicable - [x] I have updated relevant documentation to reflect my changes - [x] I have considered and documented any risks above - [ ] All Paperclip CI gates are green - [ ] Greptile is 5/5 with no open P2s, recommendations, or follow-ups - [x] I will address all Greptile and reviewer comments before requesting merge |
||
|
|
dbf052577d |
Follow the current onboarding arc in the release smoke (#12423)
## Thinking Path
> - Paperclip is the open source app people use to manage AI agents for
work
> - A release is gated by the release smoke: it installs the published
`paperclipai` artifact into a Docker container and drives the sign-in →
onboarding → first-agent path with Playwright
> - That suite runs only from the release pipeline, never on a pull
request, so it sees the UI only after the UI has already changed
> - The onboarding wizard was rebuilt into the agent arc. The "Name your
organization" step, the "Start Onboarding" launcher, and the agent role
picker are all gone
> - The spec still waited for those, so it failed on its first assertion
and blocked every nightly and beta release
> - The failure was also hard to read. The workflow uploaded no
container logs, because it learned the container's name only after the
harness succeeded, and the harness ran the container with `--rm` and
deleted it before anything read it
> - This pull request rewrites the spec to follow the current arc, and
repairs the log capture at both ends
> - The benefit is that nightly and beta releases are unblocked, and the
next failure arrives with the logs attached
## Linked Issues or Issue Description
No existing issue. Describing it inline, following
`.github/ISSUE_TEMPLATE/bug_report.yml`.
Refs #12274 (removed the company-naming step from the wizard).
Refs #12135 (the previous alignment of this spec, before #12274).
Refs #12316 (open; also edits `scripts/docker-onboard-smoke.sh`, in the
bootstrap helpers rather than the container lifecycle, so the two
changes do
not overlap. Whichever lands second should rebase and re-run).
**What happened?**
The release smoke fails.
`tests/release-smoke/docker-auth-onboarding.spec.ts`
never gets past its first wait:
```
✘ tests/release-smoke/docker-auth-onboarding.spec.ts:43:3 › Docker authenticated onboarding smoke › logs in, completes onboarding, and hires the lead agent
Error: expect(locator).toBeVisible() failed — element(s) not found (timeout 20000ms)
> 33 | await expect(wizardHeading.or(startButton)).toBeVisible({ timeout: 20_000 });
```
The spec waits for an `h3` reading "Name your organization" or a
"Start Onboarding" button. Neither exists. #12274 removed the
company-naming
step; the string now survives only in a code comment and in
`ui/src/components/OnboardingWizard.step.test.tsx`, which asserts it is
*absent*. The steps after the first wait are stale too: the CTA on step
1 is
"Continue" and not "Next", the organization input's placeholder changed,
and
the agent step's `#onboarding-agent-role` picker is gone, so every
onboarding
hire is filed under the neutral `general` role.
The suite runs only from the release pipeline, so nothing on a pull
request
saw the drift. Both `smoke_nightly` and `smoke_beta` call the same
reusable
workflow, so every nightly and every beta was blocked.
The failure also arrived without diagnostics. The job's "Capture Docker
logs"
step is `if: always()`, but it is guarded on `SMOKE_CONTAINER_NAME`,
which the
"Launch Docker smoke harness" step writes to `$GITHUB_ENV` only *after*
the
harness returns. On any failure before that the guard is false, the step
does
nothing, and the upload reports "No files were found". Below that,
`scripts/docker-onboard-smoke.sh` starts the container with
`docker run -d --rm`, so the `docker stop` in its EXIT trap deletes the
container and its logs together — and a container that crashes on its
own is
removed the instant its process exits.
**Expected behavior**
The spec walks the onboarding arc the app actually presents, and proves
the
company is created, the lead agent is hired, and the first task is
seeded and
dispatched. When the smoke fails, the run's artifact carries the
container's
logs.
**Steps to reproduce**
1. Run the Release Smoke workflow against a published artifact that
carries
#12274, or run it locally:
`PAPERCLIPAI_VERSION=2026.828.0-canary.3 SMOKE_DETACH=true
./scripts/docker-onboard-smoke.sh`
2. Run `pnpm run test:release-smoke` against that container.
3. The single spec fails at `openOnboarding()` after 20 seconds.
4. In CI, open the run's `release-smoke` artifact. It has no
`docker-onboard-smoke.log`.
**Paperclip version or commit**
`2026.828.0-canary.3` (commit
|
||
|
|
7b73b08250 |
ci: enforce migration order against PR target (#12433)
## Thinking Path > - Paperclip is the open source app that people use to manage AI agents for work. > - Paperclip applies database migrations in numeric order. > - Two branches can create the same migration number before either branch merges. > - The existing repository check can find duplicates only after both histories are present in one checkout. > - A pull request must compare its new migrations with the target branch before merge. > - This pull request adds that comparison to the existing PR policy job. > - The benefit is an early failure with exact renumbering instructions. ## Linked Issues or Issue Description **What existing behavior does this improve?** The PR policy check for files in `packages/db/src/migrations`. **Current behavior** A stale branch can add the same migration number as the target branch. The existing check does not compare PR additions with the target branch migration tip. **Proposed behavior** The policy job fails when a new PR migration number is not greater than every migration on the target branch. The error names the conflict, the next safe number, and the related files to update. **Reason and benefit** This prevents duplicate or out-of-order migration numbers from reaching `master`. It also gives contributors and agents a direct repair procedure. **Breaking changes** None. The change rejects migration numbering that is already unsafe. ## What Changed - Added a dependency-free check that compares new PR migration files with the target branch tip. - Added the check to the existing PR policy job. - Added tests for no-op, valid, duplicate, and lower-number cases. ## Verification - `node --test '.github/scripts/tests/*.test.mjs'` passed 133 tests. - `pnpm -r typecheck` passed. - `pnpm build` passed. - `pnpm test:run` passed 4,889 tests and failed 24 unrelated macOS path and wildcard-listener tests that also affect the current `master` checkout. ## Risks - Low risk. The check reads Git history and does not modify migrations. - The check permits gaps. It only requires each new migration number to follow the target branch tip. - The existing migration check continues to validate duplicate numbers, snapshots, and journal entries inside the PR. ## Model Used OpenAI Codex, GPT-5. The exact serving model ID and context-window size are not exposed in this session. Reasoning, tool use, web access, and code execution were enabled. ## Checklist - [x] I have included a thinking path that traces from project context to this change - [x] I have specified the model used (with version and capability details) - [x] I have checked ROADMAP.md and confirmed this PR does not duplicate planned core work - [x] I have searched GitHub for duplicate or related PRs and linked them above - [x] I have either (a) linked existing issues with `Fixes: #` / `Closes #` / `Refs #` OR (b) described the issue in-PR following the relevant issue template - [x] I have not referenced internal/instance-local Paperclip issues or links (only public GitHub `#NNN` / `github.com/paperclipai/paperclip` URLs) - [x] My branch name describes the change (e.g. `docs/...`, `fix/...`) and contains no internal Paperclip ticket id or instance-derived details - [x] I have run tests locally and they pass - [x] I have added or updated tests where applicable - [x] I have updated relevant documentation to reflect my changes - [x] I have considered and documented any risks above - [ ] All Paperclip CI gates are green - [x] Greptile is 5/5 with no open P2s, recommendations, or follow-ups - [x] I will address all Greptile and reviewer comments before requesting merge Co-authored-by: Paperclip <noreply@paperclip.ing> |
||
|
|
7895f7f2b0 |
Install the declared Sentry server package into the hosted image (#12330)
## Thinking Path > - Paperclip is the open source app people use to manage AI agents for work. > - Paperclip supports opt-in Sentry error monitoring for server and browser errors. > - The hosted image must include the server package when an operator sets SENTRY_DSN. > - The server package is an optional peer in the source tree, so the image did not include it. > - This pull request installs the declared server package in the hosted image and checks the result. > - The benefit is a hosted tenant can send server errors without a manual package install. ## Linked Issues or Issue Description No public issue exists for this change. **What happened?** The hosted image did not include the declared @sentry/node server package. A hosted tenant could set SENTRY_DSN, but the server could not load the package from the image. **Expected behavior** The hosted image must include the exact @sentry/node version from server/package.json. The self-hosted image must remain without this optional package. **Steps to reproduce** 1. Build or pull the hosted image. 2. Resolve @sentry/node from the server package path. 3. Compare its version with server/package.json. 4. Confirm that the tsx loader path still resolves. **Paperclip version or commit** Commit b6ff556a33ebdbe764b7f495951cd59009776608. **Deployment mode** Docker hosted image. ## What Changed - Add a cloud-server-deps Docker stage that installs the declared @sentry/node version in isolation. - Copy the isolated package into the cloud image without changing the production image. - Add a probe that checks the tsx loader and the resolved Sentry version. - Run the probe after the hosted image push in the Docker workflow. - Add server tests and update the observability documentation. ## Verification - Run `pnpm exec vitest run --project @paperclipai/server server/src/__tests__/cloud-image-sentry.test.ts`. - Confirm that the changed test passes in CI. - Confirm that all pull request checks pass. - Note that the Docker workflow does not run for pull requests. It runs after a push to master, for configured tags, or after manual dispatch. ## Risks - Low risk. The production image body stays unchanged. - The cloud image adds the declared Sentry package and a small dependency tree. - The workflow probe fails if the image loses the tsx loader or resolves a different Sentry version. ## Model Used OpenAI GPT-5; exact model version supplied by the execution service; tool use and code execution; context window not specified. ## Checklist - [x] I have included a thinking path that traces from project context to this change - [x] I have specified the model used (with version and capability details) - [x] I have checked ROADMAP.md and confirmed this PR does not duplicate planned core work - [x] I have searched GitHub for duplicate or related PRs and linked them above - [x] I have either (a) linked existing issues with `Fixes: #` / `Closes: #` / `Refs: #` OR (b) described the issue in-PR following the relevant issue template - [x] I have not referenced internal/instance-local Paperclip issues or links (only public GitHub `#NNN` / `github.com/paperclipai/paperclip` URLs) - [x] My branch name describes the change (e.g. `docs/...`, `fix/...`) and contains no internal Paperclip ticket id or instance-derived details - [x] I have run tests locally and they pass - [x] I have added or updated tests where applicable - [x] I have updated relevant documentation to reflect my changes - [x] I have considered and documented any risks above - [x] All Paperclip CI gates are green - [x] Greptile is 5/5 with no open P2s, recommendations, or follow-ups - [x] I will address all Greptile and reviewer comments before requesting merge --------- Co-authored-by: Paperclip <noreply@paperclip.ing> |
||
|
|
1de105c475 |
fix(observability): pin the Sentry browser SDK and gate the optional Sentry server peer on the exact version (#12270)
## Thinking Path
> - Paperclip is the open source app people use to manage AI agents for
work.
> - Paperclip uses separate server and browser packages for runtime
services and the board.
> - Sentry integrations need an exact SDK version and safe optional
loading.
> - A version range can select an SDK that the privacy tests did not
audit.
> - Missing peer metadata does not describe the optional server SDK
contract.
> - This pull request pins the browser SDK and gates the optional server
SDK on its exact version.
> - The benefit is a clear SDK contract with fail-open startup behavior.
## Linked Issues or Issue Description
**What happened?**
The browser package used the range ^10.71.0, so a lockfile refresh could
select a newer SDK. The server loaded @sentry/node dynamically but did
not declare its optional peer contract.
**Expected behavior**
The browser package must use the audited 10.71.0 version. The server
must load @sentry/node only when the installed peer matches 10.71.0. The
server must start when the optional peer is absent.
**Steps to reproduce**
1. Install the project dependencies.
2. Inspect the browser Sentry version and the server package metadata.
3. Start the server without installing @sentry/node.
4. Confirm that the server starts and that the dynamic Sentry bootstrap
does not load an unsupported peer version.
**Paperclip version or commit**
|
||
|
|
06cd21ed0f |
fix(observability): declare the optional OpenTelemetry peer dependencies (#12249)
## Thinking Path > - Paperclip manages AI agents for work. > - Paperclip includes an observability path that operators can enable for tracing. > - The server loads several OpenTelemetry packages only when tracing is enabled. > - The documentation calls these packages optional peer dependencies, but the server manifest does not declare them. > - This gap hides supported versions and stops Dependabot from maintaining the packages. > - This pull request aligns package metadata, runtime checks, and documentation with the opt-in tracing design. > - The change gives operators clear installation behavior and keeps the no-op default. ## Linked Issues or Issue Description This pull request fixes a package metadata and installation defect. Related observability work appears in [#8476](https://github.com/paperclipai/paperclip/pull/8476) and [#9672](https://github.com/paperclipai/paperclip/pull/9672). The server documentation described optional OpenTelemetry peer dependencies, but `server/package.json` did not declare them. Package managers and Dependabot could not see the supported version ranges. The UI and Claude local adapter also relied on automatic peer installation for `yjs` and `@anthropic-ai/sdk`. The package manifests now declare the optional runtime packages. A default install does not install optional tracing peers. The server keeps its no-op behavior when tracing is disabled or a peer is absent. ## What Changed - Add seven optional OpenTelemetry packages to `server/package.json` and mark each package as optional. - Keep `@opentelemetry/api` as a normal dependency for the no-op interface. - Disable automatic peer installation in `.npmrc`. - Declare `yjs` for the UI package and `@anthropic-ai/sdk` for the Claude local adapter. - Check declared peer versions before the server loads a dynamic OpenTelemetry import. - Keep the endpoint gate, dynamic imports, and fail-open behavior unchanged. - Update the observability and README documentation. - Tell Dependabot that its npm parser does not read `peerDependencies`. ## Verification - Targeted server tests pass: 34 passed and 2 skipped. - The skipped tests require the real OpenTelemetry SDK and remain pre-existing. - The pull request workflow regenerates the lockfile because manifest files and `.npmrc` changed. - The policy job confirms that the pull request does not include `pnpm-lock.yaml`. - GitHub checks pass except `security/snyk (cryppadotta)`, which remains pending after its authorized wait cap. - Greptile Review reports 5/5 with no open findings. - Server typecheck passes. ## Risks - Optional peers can produce a diagnostic when the installed version does not match the declared range. - A missing optional peer does not stop the server. - Disabling automatic peer installation can expose undeclared package use in other workspaces. - This pull request declares the affected packages and adds tests for the changed behavior. - This pull request makes no database or API changes. ## Model Used OpenAI Codex, GPT-5, with repository inspection and pull request preparation. ## Checklist - [x] I have included a thinking path that traces from project context to this change - [x] I have specified the model used (with version and capability details) - [x] I have checked ROADMAP.md and confirmed this PR does not duplicate planned core work - [x] I have searched GitHub for duplicate or related PRs and linked them above - [x] I have either (a) linked existing issues with Fixes / Closes / Refs OR (b) described the issue in-PR following the relevant issue template - [x] I have not referenced internal/instance-local Paperclip issues or links - [x] My branch name describes the change and contains no internal Paperclip ticket id - [x] I have run tests locally and they pass - [x] I have added or updated tests where applicable - [x] I have updated relevant documentation to reflect my changes - [x] I have considered and documented any risks above - [x] All Paperclip CI gates are green - [x] Greptile is 5/5 with no open P2s, recommendations, or follow-ups - [x] I will address all Greptile and reviewer comments before requesting merge --------- Co-authored-by: Paperclip <noreply@paperclip.ing> |
||
|
|
5db8ce3c44 |
fix(docker): make tini PID 1 in the server image so adopted orphans are reaped (#12137)
## Thinking Path
> - Paperclip is the open source app people use to manage AI agents for
work
> - Agent runs execute inside the server container, and they spawn many
short-lived descendants: git, the adapter CLI, esbuild, sh
> - The server image sets `ENTRYPOINT ["docker-entrypoint.sh"]`, and
that entrypoint ends in `exec`, so node becomes PID 1
> - Node reaps only the children it spawned itself. It installs no
`SIGCHLD`/`waitpid` handler for orphans that the kernel re-parents onto
PID 1, so those orphans stay as zombies forever
> - Zombies accumulate monotonically. When the cgroup pid limit is
reached, every `fork()` in the container fails and the instance is dead
> - This pull request installs `tini` and makes it PID 1 in front of the
existing entrypoint, adds a behavioural test that proves reaping, and
adds a `pids_limit` backstop to both compose files
> - The benefit is that a long-running container no longer degrades into
total fork failure, and a future regression is caught by CI instead of
by an outage
Depends-on: none — this change is self-contained in the image build and
its tests, and it touches no other in-flight branch
## Linked Issues or Issue Description
No public GitHub issue exists for this defect. It was found on a live
long-running instance. Description follows the bug report template.
**What happened?**
The server container ran for 22 hours and reached 2039 of 2048 pids in
its cgroup. Of 1760 processes, 1731 were zombies, and all 1731 had PID 1
as their parent. PID 1 was `node --import
./server/node_modules/tsx/dist/loader.mjs server/dist/index.js`. Zombies
accrued at about 79 per hour and were never reaped. The oldest zombie
was 20.8 hours old against a container uptime of 22.0 hours, so nothing
had been reaped since boot. Once the pid limit was reached, `git` and
`gh` failed with `pthread_create failed: Resource temporarily
unavailable`.
**Expected behavior**
PID 1 reaps orphaned processes that the kernel re-parents onto it. The
pid count of a long-running container stays flat instead of growing
without bound.
**Steps to reproduce**
1. Start the server image without `docker run --init` and without `init:
true`.
2. Run agent work that spawns descendants which outlive their immediate
parent.
3. Read `/sys/fs/cgroup/pids.current` and count processes in `Z` state
over several hours.
4. The zombie count grows monotonically and every zombie has PPID 1.
**Relevant logs or output**
```
cgroup pids.current / pids.max : 2039 / 2048
total processes : 1760
zombies : 1731 (98.4%)
parent of every zombie : PID 1 (1731/1731)
PID 1 cmdline : node --import .../tsx/dist/loader.mjs server/dist/index.js
container uptime : 22.0 h
oldest zombie : 20.8 h median: 14.4 h
zombie names : git 717, claude 280, MainThread 167, sleep 141,
esbuild 138, postgres 76, sh 65, sccache 50
```
**Additional context**
The fix pattern is already in this repository.
`docker/agent-runtime/Dockerfile.base` installs `tini` and sets
`ENTRYPOINT ["/usr/bin/tini", "--"]`. It was never applied to the server
image.
## What Changed
- `Dockerfile`: install `tini` in the `base` stage and set `ENTRYPOINT
["/usr/bin/tini", "--", "docker-entrypoint.sh"]`. The entrypoint stays
in the exec chain, so UID/GID remapping, `gosu`, and graceful shutdown
are unchanged.
- `scripts/assert-orphan-reaping.sh` (new): a behavioural probe. It
spawns a leader that forks a grandchild, exits the leader, and asserts
that the orphaned grandchild leaves `Z` state instead of persisting. It
fails closed if the grandchild is not re-parented onto PID 1, so a pass
cannot mean the check ran too early.
- `.github/workflows/docker.yml`: run that probe against the pushed
image after the publish step. The publish step is multi-arch with `push:
true`, so nothing is loaded into the runner daemon and the pushed tag is
the only thing to test. The cloud variant is `FROM production` and
inherits the same `ENTRYPOINT`.
- `scripts/docker-build-test.sh`: run the same probe against a local
build.
- `docker/docker-compose.yml` and
`docker/docker-compose.quickstart.yml`: add `pids_limit: 2048` as a
backstop, so a future leak dies visibly at its own ceiling instead of
starving the host of pids.
- `server/src/__tests__/container-init-reaping.test.ts` (new): 13
assertions that guard the configuration the probe depends on.
No per-orchestrator init lever was added. The image owning PID 1 covers
compose, plain `docker run`, the quadlet units, and the ECS task
definition in one place. Adding `init: true` in compose or
`initProcessEnabled` on the ECS task would nest a second init around
`tini`, and `tini` then warns on every boot that it is not PID 1. The
new test asserts the absence of both levers across all three manifests,
so the decision survives the next edit.
## Verification
| Check | Result |
|---|---|
| `scripts/assert-orphan-reaping.sh` against a real init | Grandchild
re-parented to PPID 1, then reaped. Exit 0. |
| Same probe forced against a genuine zombie | Reports `Z` and fails.
The failure branch is not vacuous. |
| Config guard against the pre-fix files | Exactly the 3 relevant
assertions turn red. |
| Config guard with `tini` removed from `apt-get` but the comments kept
| Red. It checks the install, not a mention of the name. |
| `cd server && npx vitest run
src/__tests__/container-init-reaping.test.ts` | 13 passed |
| `npx tsc --noEmit -p server` | Clean |
| `node scripts/check-docker-deps-stage.mjs` | PASS |
| `node --test scripts/release-verify-workflow.test.mjs` | 8 passed |
Not verified locally: no container runtime is available in the authoring
environment, so the probe has not run against a build of this image. The
new `docker.yml` step runs it against the pushed image on this PR.
## Risks
Low risk, but it is an image and entrypoint change, so it affects
deployments.
- `tini` adds one small package to the `base` stage.
`docker/agent-runtime/Dockerfile.base` already installs it from the same
Debian archive.
- Signal handling changes shape: `tini` receives `SIGTERM` and forwards
it to the entrypoint, which `exec`s node. `tini` forwards signals to its
direct child by default, and the exec chain keeps node as that child, so
graceful shutdown is preserved. A reviewer should confirm this on a real
stop.
- `pids_limit: 2048` is new for compose users. A deployment that
legitimately needs more than 2048 processes would now hit the ceiling.
The measured steady state on a busy instance was under 400.
- If a deployment already passes `--init` or `init: true`, `tini` runs
under another init and prints a warning that it is not PID 1. Reaping
still works because the outer init handles it. The compose files in this
repository do not set `init: true`.
## Model Used
Claude Opus 5 (`claude-opus-5`), extended thinking, with tool use and
code execution in an agent harness.
## Checklist
- [x] I have included a thinking path that traces from project context
to this change
- [x] I have specified the model used (with version and capability
details)
- [x] I have checked ROADMAP.md and confirmed this PR does not duplicate
planned core work
- [x] I have searched GitHub for duplicate or related PRs and linked
them above
- [x] I have either (a) linked existing issues with `Fixes: #` / `Closes
#` / `Refs #` OR (b) described the issue in-PR following the relevant
issue template
- [x] I have not referenced internal/instance-local issues or links
- [x] My branch name describes the change and contains no internal
ticket id or instance-derived details
- [x] I have run tests locally and they pass
- [x] I have added or updated tests where applicable
- [x] I have updated relevant documentation to reflect my changes
- [x] I have considered and documented any risks above
- [x] All CI gates are green
- [x] Greptile is 5/5 with no open P2s, recommendations, or follow-ups
- [x] I will address all Greptile and reviewer comments before
requesting merge
---------
Co-authored-by: zannis <1011451+zannis@users.noreply.github.com>
|
||
|
|
ffff1fe6e3 |
feat(runner): define package API and verification boundary (#12129)
## Thinking Path > - Paperclip is the open source app people use to manage AI agents for work. > - The runner package now has protocol, transport, provider, catalog, and authorization foundations. > - Its first upstream package boundary should expose only the implemented runtime and test-helper surfaces. > - Rust correctness belongs in the repository existing build verification, without introducing a parallel release process. > - Direct package creation must build the files declared by the package manifest. > - This pull request defines the minimal package API and verifies the optimized runner binaries in the existing PR and release Build jobs. > - The benefit is a production-ready runner package boundary with minimal build-process change. ## Linked Issues or Issue Description Refs #11962 This pull request replaces one bounded part of the archived large runner change. It follows the package-local authorization change in #12126. ## What Changed - Export only `@paperclipai/paperclip-runner` and `@paperclipai/paperclip-runner/testing`. - Keep Node-only fixture loading and semantic conformance helpers out of the runtime root. - Add a provider-neutral semantic conformance kit with stable JSON comparison and fail-closed input checks. - Keep deferred SDK, eval, browser, React, lab, and command surfaces private. - Pin the runner Rust toolchain to 1.97.1 with the minimal profile and `rustfmt`. - Run the Rust workspace tests in release mode. - Launch the optimized `paperclip-runnerd` and fake-harness binaries in process-level integration coverage. - Add one `pnpm --filter @paperclipai/paperclip-runner check:all` step to each existing PR and release Build job. - Make the existing server `prepack` lifecycle run its existing build after it prepares UI assets. - Document that no production adapter starts runnerd yet. This revision adds no standalone GitHub Actions job. It adds no server runner dependency or runner vendoring. It adds no Docker bootstrap or clean-consumer harness. It does not change `pnpm-lock.yaml`. ## Verification - `pnpm --filter @paperclipai/paperclip-runner check:all` - 66 TypeScript tests - 8 protocol contract tests - 56 Rust unit and integration tests - Release-mode integration coverage launches the optimized runnerd and fake-harness binaries. - `pnpm --filter @paperclipai/server exec vitest run src/__tests__/server-package-build-script.test.ts` (2 tests) - Clean `pnpm pack` from `server/` rebuilt the server and produced both `package/dist/index.js` and `package/dist/index.d.ts`. - `node --test scripts/__tests__/release-verify-workflow.test.mjs` (8 tests) - `pnpm -r typecheck` - `pnpm build` - `pnpm check:token-gates` - `git diff --check` - No `pnpm-lock.yaml` diff. - The diff changes 12 files. ## Risks The runner adds Rust work to the existing Build jobs. These jobs can take longer on a cold cache. The pinned toolchain makes contributor and CI behavior reproducible. Cargo tests use `--release` to verify optimized executables. The server prepack lifecycle now performs the build that its published entry points require. This can make direct server packing slower. This pull request does not wire runnerd into the server. It does not select runnerd for any adapter. Existing application execution and finalization paths remain unchanged. ## Model Used OpenAI Codex with GPT-5. Agentic coding mode used repository tools, code execution, and automated tests. ## Checklist - [x] I have included a thinking path that traces from project context to this change - [x] I have specified the model used (with version and capability details) - [x] I have checked ROADMAP.md and confirmed this PR does not duplicate planned core work - [x] I have searched GitHub for duplicate or related PRs and linked them above - [x] I have either (a) linked existing issues with `Fixes: #` / `Closes #` / `Refs #` OR (b) described the issue in-PR following the relevant issue template - [x] I have not referenced internal/instance-local Paperclip issues or links (only public GitHub `#NNN` / `github.com/paperclipai/paperclip` URLs) - [x] My branch name describes the change (e.g. `docs/...`, `fix/...`) and contains no internal Paperclip ticket id or instance-derived details - [x] I have run tests locally and they pass - [x] I have added or updated tests where applicable - [x] I have updated relevant documentation to reflect my changes - [x] I have considered and documented any risks above - [x] All Paperclip CI gates are green - [x] Greptile is 5/5 with no open P2s, recommendations, or follow-ups - [x] I will address all Greptile and reviewer comments before requesting merge Co-authored-by: Paperclip <noreply@paperclip.ing> |
||
|
|
0a01444514 |
test(release-smoke): cover the background-service leg of onboarding (#12151)
## Thinking Path > - Paperclip is the open source app people use to manage AI agents for work > - The release pipeline gates each nightly and beta on a smoke suite that onboards the published npm artifact and drives the golden path > - That smoke runs onboarding inside a Docker container, and containers have no service manager, so the background-service leg of onboarding has zero automated coverage > - v2026.824.0 shipped a service install that crash-looped on a missing shim, and every smoke check stayed green (#12148 fixed the defect itself) > - This pull request adds a `smoke_service` job that runs the same published artifact directly on the runner VM's systemd and requires the installed service to end up serving > - The benefit is that a release with a broken service install can no longer pass the release smoke suite ## Linked Issues or Issue Description Refs #12148 — the fix for the defect this coverage gap let through. The gap: the release smoke runs `onboard` with `--yes` inside Docker, which both skips the service prompt and lacks systemd, so no CI job ever executed `manager.install()` against a real service manager. ## What Changed - New `scripts/service-onboard-smoke.sh`: onboards the published artifact with `--yes --install-service` on a systemd host, then fails unless the managed shim exists and is executable, `paperclipai.service` is active, and `/api/health` answers. A health response while the unit is not active also fails, because that is the signature of something other than the service serving. The script refuses to run over an existing managed install unless `SMOKE_FORCE=true`, and cleans up after itself by default so it is safe to run locally. - New `smoke_service` job in `.github/workflows/release-smoke.yml`: starts a user systemd session on the hosted runner (`loginctl enable-linger` + exported `XDG_RUNTIME_DIR`/`DBUS_SESSION_BUS_ADDRESS`), runs the script against `inputs.paperclip_version`, and uploads `systemctl status` + journal output as diagnostics. - No `release.yml` changes needed: `smoke_nightly` and `smoke_beta` call this reusable workflow, and a `workflow_call` result aggregates all jobs, so the new job gates nightly promotion automatically. ## Verification - `bash -n scripts/service-onboard-smoke.sh` passes and the workflow YAML parses. - End-to-end: dispatched this branch's Release Smoke workflow against the published canary that contains #12148; the `smoke_service` job onboards, installs the service, and verifies the service serves health. (Run link in PR comments.) - Negative case: the same assertions fail against v2026.824.0 — reproduced in a systemd container during the #12148 investigation: shim missing, unit in a 203/EXEC restart loop. ## Risks - Low risk to the product: no application code changes. - Pipeline risk: a flaky user-session setup on the hosted runner would block nightly promotion. Mitigated by validating the job end-to-end from this branch before merge, a 30-minute job timeout, and diagnostics uploaded on every run. - The service leg only covers systemd. launchd (macOS) still has no CI coverage; a macOS runner job is a possible follow-up. ## Model Used - Claude Fable 5 (Anthropic, model ID `claude-fable-5`), extended thinking, agentic tool use via Claude Code. ## Checklist - [x] I have included a thinking path that traces from project context to this change - [x] I have specified the model used (with version and capability details) - [x] I have checked ROADMAP.md and confirmed this PR does not duplicate planned core work - [x] I have searched GitHub for duplicate or related PRs and linked them above - [x] I have either (a) linked existing issues with `Fixes: #` / `Closes #` / `Refs #` OR (b) described the issue in-PR following the relevant issue template - [x] I have not referenced internal/instance-local Paperclip issues or links (only public GitHub `#NNN` / `github.com/paperclipai/paperclip` URLs) - [x] My branch name describes the change (e.g. `docs/...`, `fix/...`) and contains no internal Paperclip ticket id or instance-derived details - [x] I have run tests locally and they pass - [x] I have added or updated tests where applicable - [x] I have updated relevant documentation to reflect my changes - [x] I have considered and documented any risks above - [ ] All Paperclip CI gates are green - [ ] Greptile is 5/5 with no open P2s, recommendations, or follow-ups - [x] I will address all Greptile and reviewer comments before requesting merge |
||
|
|
890ab9acfe |
feat(release): thorough notes skeletons — nest each PR's summary at creation (#12124)
## Thinking Path > - Paperclip is the open source app people use to manage AI agents for work > - The release workflow drafts the upcoming stable's notes skeleton the moment a beta publishes > - That skeleton was a bare list of commit subjects, so the notes only reached the shipped stable's depth after a later authoring pass during the soak > - Stable release notes are consistently verbose and thorough; the initial draft should start that way too > - This pull request nests each referenced PR's own summary under its subject line at creation time, and states the density bar in the authoring skill > - The benefit is a thorough raw document from day one of the soak, with no LLM tokens in Actions ## Linked Issues or Issue Description **What existing behavior does this improve?** The `draft_stable_notes` skeleton generated at beta publish (`scripts/draft-stable-notes.sh`). **Current behavior** The skeleton groups bare commit subjects by conventional-commit type. All substance arrives later, when a maintainer or agent rewrites it — reviewed maintainer feedback: stable notes are a lot more verbose, and the initial beta notes should be consistent with that. **Proposed behavior** Each subject that references a PR carries that PR's own summary nested beneath it — the PR template's "What Changed" bullets, else the first prose lines — fetched best-effort via `gh` and skipped silently when unavailable. The release-changelog skill now states the density bar explicitly: the beta-keyed draft ships verbatim as the stable's notes and is written at the previous stable's depth from the first pass. **Reason and benefit** The notes author starts from a thorough raw document instead of a commit list, and beta-time notes match the verbosity the stable will ship with. ## What Changed - `scripts/draft-stable-notes.sh`: `enrich_pr` nests PR summaries under subjects; best-effort (`gh` failure or `DRAFT_NOTES_SKIP_PR_ENRICHMENT=1` degrades to today's output); pipefail-safe when a "What Changed" section has no bullets. - `.github/workflows/release.yml`: the `draft_stable_notes` step gets `GH_TOKEN` so `gh` can read PR bodies. - `.agents/skills/release-changelog/SKILL.md`: "write at full stable depth from the first pass" guideline. - `scripts/draft-stable-notes.test.mjs`: three new tests — enrichment rendering via a fake `gh`, silent degradation without one, and the sparse-body case that previously killed the script under `set -o pipefail`. ## Verification - `node --test scripts/draft-stable-notes.test.mjs` — 11 pass. - Live run against the real repository for the current beta (`2026.818.0-beta.1`, 172 commits): exit 0, 439 nested summary lines; spot-checked entries carry the correct PRs' What Changed bullets. - `bash -n` on the script; `release.yml` re-parsed as YAML. ## Risks - Low: the publish path is untouched; enrichment is read-only `gh` calls in the post-publish draft job and degrades to the current skeleton on any failure. Roughly one API call per commit in the range (~170 today) — well inside the token's rate budget, adds a couple of minutes to a job with a 10-minute timeout. ## Model Used Claude Fable 5 (Claude Code) ## Pre-submission checklist - [x] I have included a thinking path that traces from project context to this change - [x] I have specified the model used (with version and capability details) - [x] I have checked ROADMAP.md and confirmed this PR does not duplicate planned core work - [x] I have searched GitHub for duplicate or related PRs and linked them above - [x] I have either (a) linked existing issues with `Fixes: #` / `Closes #` / `Refs #` OR (b) described the issue in-PR following the relevant issue template |
||
|
|
24913064ff |
feat(commitperclip): surface the Co-Authored-By trailers a squash merge needs (#11498)
## Thinking Path > - Paperclip is the open source app people use to manage AI agents for work, and it takes contributions from outside the core team > - Those contributions arrive as PRs, and this repository squash-merges every one of them > - A squash collapses the whole branch into a single commit authored by whoever pressed the button > - So when a maintainer rebases and lands a contributor's stale PR, the contributor's name survives only if the squash message carries a `Co-Authored-By` trailer > - Nothing prompts for that trailer, and the PR page keeps showing the original author either way, so losing it is invisible at the moment it happens > - This pull request has commitperclip detect the situation and print the exact trailers to paste > - The benefit is that keeping an outside contributor's name is a default rather than something a maintainer has to remember ## Linked Issues or Issue Description No public issue exists. The problem follows, and it is not hypothetical. **What happened?** #11370, #11371 and #11379 landed @stubbi's work yesterday. Each of those PRs carries a comment from me telling them their authorship would be preserved. All three squash commits went in without a `Co-Authored-By` trailer, so `git log` credits none of them: | commit | landed from | credited | | --- | --- | --- | | `66515582e` | #9900 | Claude only | | `bc0b5a164` | #9501 | Claude only | | `35a9b9873` | #8982 | Claude only | | `6542ad1f4` | #11259 | ✅ Jannes Stubbemann + Claude | The last one has the trailer because that message was written by hand with the contributor in mind. The only difference between the two outcomes was memory. Master history cannot be rewritten, so those three are now credited by comment on the original PRs — which is a worse record than a commit trailer, and the reason to make this automatic. **Expected behavior** When a branch carries commits by someone other than the PR author, the merger is told what trailers the squash needs. **Paperclip version or commit** `master` at `92047cac4`. ## What Changed - `.github/scripts/check-pr-coauthors.mjs` — new gate. - `.github/scripts/run-quality-gates.mjs` — fetches the PR's commits and runs it. - `.github/scripts/tests/check-pr-coauthors.test.mjs` — 12 cases. - `.github/workflows/pr.yml` — runs `.github/scripts/tests/`. ### Informational, not a failure The squash message does not exist while the PR is open. This can neither be verified there nor fixed there, so failing a PR on it would block work on something its author cannot satisfy. The gate notices that the situation applies and prints the lines to paste. Run against #11370's actual commits it produces exactly what was missing: ``` This branch carries commits by stubbi. Squash-merging drops that authorship unless the squash message carries their trailers, and nothing else will notice if it does not. Add to the squash body when merging: Co-Authored-By: Jannes Stubbemann <stubbi@users.noreply.github.com> ``` ### Edge cases it handles Bots skipped; the PR author's own commits skipped; logins compared case-insensitively (`PR_AUTHOR` does not always arrive in the same case as the commit author login); each contributor listed once however many commits they wrote; and a commit GitHub could not match to an account falls back to its raw git author — that identity being the one most likely to be lost, not least likely. Paging stops at the API's own 250-commit ceiling rather than spinning on full pages of nothing new. ### The test directory was not running `.github/scripts/tests/` held ten test files covering the existing gates, and no workflow ran any of them. Adding an eleventh would have meant adding a test that never executes, so `pr.yml` now runs the directory. All **149** pass, including the 137 that were already there and previously unverified in CI. ## Verification - 149 tests pass via `node --test '.github/scripts/tests/*.test.mjs'` — the exact command CI now runs. - The gate was run against the real commit shape from #11370 and produces the missing trailer verbatim. This PR is its own negative control: the branch carries only my commits, so the new gate should stay silent on it. If commitperclip prints a co-author note below, the gate is wrong. ## Risks Low. Informational output only — it cannot fail a PR, and `allPassed` is unchanged. It adds one API call per gate run (`/pulls/{n}/commits`), fetched in the same `Promise.all` as the existing PR and files calls. Enabling the previously-unrun test directory could in principle surface a pre-existing failure; all 149 pass locally, so it does not. Revert the commit to restore. ## Model Used Claude Opus 5 (`claude-opus-5`), through Claude Code. Extended thinking enabled. Tool use enabled: file read and edit, shell for test runs. ## Checklist - [x] I have included a thinking path that traces from project context to this change - [x] I have specified the model used (with version and capability details) - [x] I have checked ROADMAP.md and confirmed this PR does not duplicate planned core work - [x] I have searched GitHub for duplicate or related PRs and linked them above - [x] I have either (a) linked existing issues with `Fixes: #` / `Closes #` / `Refs #` OR (b) described the issue in-PR following the relevant issue template - [x] I have not referenced internal/instance-local Paperclip issues or links - [x] My branch name describes the change and contains no internal ticket id - [x] I have run tests locally and they pass - [x] I have added or updated tests where applicable - [x] I have updated relevant documentation to reflect my changes - [x] I have considered and documented any risks above - [x] All Paperclip CI gates are green - [x] Greptile is 5/5 with no open P2s, recommendations, or follow-ups - [x] I will address all Greptile and reviewer comments before requesting merge --------- Co-authored-by: Claude Opus 5 <noreply@anthropic.com> |
||
|
|
38d8f37172 |
fix(build): enforce Node 24 across Paperclip (#11792)
## Thinking Path > - Paperclip is the open source app people use to manage AI agents for work. > - Paperclip runs across the CLI, server, adapters, plugins, CI, and container images. > - These surfaces declared different Node.js versions from 20 through 24. > - A newer `@types/node` major can expose APIs that the supported runtime does not provide. > - Node.js 20 is no longer a suitable project baseline, and Node.js 24 is the current LTS line. > - This pull request sets Node.js 24.11.0 as one repository-wide baseline, adds a drift check, and gives users actionable startup guidance when their runtime is too old. > - The benefit is one clear runtime contract for development, release, installation, and published packages. ## Linked Issues or Issue Description Refs #2734 Refs #11727 Refs #739 ## What Changed - Require Node.js 24.11.0 or newer in all 42 package manifests and runtime checks. - Use Node.js 24 in GitHub Actions, Docker images, smoke images, sandbox setup, portable installs, and esbuild targets. - Align every direct `@types/node` declaration on `^24.0.0`. - Prevent Dependabot from opening major `@types/node` upgrades without a matching runtime decision. - Add `.nvmrc` and a CI policy check for Node version drift. - Update ACP version gates, tests, and user documentation for the new minimum. - Print a non-blocking warning on CLI and server startup when Node is unsupported, with remediation through a version manager or the documented downloaded `install.sh` workflow. - Deduplicate that warning when `paperclipai run` boots the CLI and server in the same process. ## Verification - `node scripts/check-node-version-policy.mjs` - `node --check scripts/check-node-version-policy.mjs` - `node --check cli/esbuild.config.mjs` - `node --check scripts/generate-npm-package-json.mjs` - `bash -n scripts/install.sh scripts/test-install-sh-docker.sh scripts/e2e-install-lifecycle.sh` - Parsed all 42 package manifests and confirmed `engines.node` is `>=24.11.0`. - `git diff --check` - `vitest run packages/adapter-utils/src/sandbox-install-command.test.ts` passed with 3 tests. - `vitest run cli/src/node-version.test.ts` passed with 4 tests. - Directly exercised the shared warning helper for unsupported-version messaging and same-process deduplication. - The focused exe.dev suite could not resolve the locally unbuilt plugin SDK from this isolated worktree. A full offline workspace install was also blocked because the package-manager signature verifier requires registry access. The full suite was not run locally; draft CI performs a clean install and evaluates the wider impact. ## Risks - This is a breaking runtime change for users, plugins, and deployments that still use Node.js 20 or 22. - Published workspace packages will now produce an engine warning or failure in strict package managers on older Node.js releases. - Node.js 24 can reveal dependency, native module, Playwright, or agent CLI compatibility issues in CI. - The bootstrap installer now installs Node.js 24 when the current runtime is older than 24.11.0. - The portable sandbox fallback is pinned to Node.js 24.11.0 and depends on that upstream tarball remaining available. - Unsupported runtimes continue booting after a warning, so a later incompatibility can still fail at its point of use. - The CLI and server share the warning policy through the published `@paperclipai/shared` package; packaging checks must keep that subpath export available. - This PR does not commit `pnpm-lock.yaml` because repository policy assigns lockfile generation to CI. > For core feature work, check [`ROADMAP.md`](ROADMAP.md) first and discuss it in `#dev` before opening the PR. Feature PRs that overlap with planned core work may need to be redirected — check the roadmap first. See `CONTRIBUTING.md`. ## Model Used - OpenAI Codex based on GPT-5. The exact deployment ID and context window are not exposed in this session. Reasoning, repository tools, shell execution, and GitHub tools were enabled. ## Checklist - [x] I have included a thinking path that traces from project context to this change - [x] I have specified the model used (with version and capability details) - [x] I have checked ROADMAP.md and confirmed this PR does not duplicate planned core work - [x] I have searched GitHub for duplicate or related PRs and linked them above - [x] I have either (a) linked existing issues with `Fixes: #` / `Closes #` / `Refs #` OR (b) described the issue in-PR following the relevant issue template - [x] I have not referenced internal/instance-local Paperclip issues or links (only public GitHub `#NNN` / `github.com/paperclipai/paperclip` URLs) - [x] My branch name describes the change (e.g. `docs/...`, `fix/...`) and contains no internal Paperclip ticket id or instance-derived details - [x] I have run tests locally and they pass - [x] I have added or updated tests where applicable - [x] I have updated relevant documentation to reflect my changes - [x] I have considered and documented any risks above - [x] All Paperclip CI gates are green - [x] Greptile is 5/5 with no open P2s, recommendations, or follow-ups - [x] I will address all Greptile and reviewer comments before requesting merge --------- Co-authored-by: Paperclip <noreply@paperclip.ing> |
||
|
|
599ad7016c |
ci(release): raise npm publish visibility budget to 10 minutes per package (#11835)
## Thinking Path > - Paperclip is the open source app people use to manage AI agents for work > - The release workflow publishes every public package to npm and polls each version's registry visibility before continuing > - #11834 raised the poll budget from 60 seconds to 5 minutes after npm CDN propagation lag failed four canary runs > - The very next canary run missed by ten seconds: `adapter-opencode-local@2026.821.0-canary.2` was accepted at 07:02:27 UTC and became visible at 07:07:40, just past the final poll > - This pull request doubles the per-package budget to 10 minutes > - The benefit is a release train that survives the one consistently slow package; the 90-minute publish job timeout from #11834 already absorbs it ## Linked Issues or Issue Description Follow-up to #11834. Evidence in the `Release` run for `16149a75f`: every package's publish became visible within seconds except `adapter-opencode-local`, which has lagged 3-5+ minutes on all of today's runs and exceeded the 5-minute budget by ten seconds on the latest. ## What Changed - `NPM_PUBLISH_VERIFY_ATTEMPTS` 30 → 60 (with `NPM_PUBLISH_VERIFY_DELAY_SECONDS: "10"`, a 10-minute per-package budget), plus the comment documenting the observed near-miss. ## Verification - Same env-override plumbing verified in #11834; only the numeric budget changes. The next master push (this merge) exercises the canary path. ## Risks - Low risk: a genuinely failed publish reports in up to 10 minutes; healthy publishes exit the poll on first visibility. ## Model Used Claude Fable 5 (Anthropic, `claude-fable-5`) with extended thinking and agentic tool use via the Claude Code CLI. ## Checklist - [x] I have included a thinking path that traces from project context to this change - [x] I have specified the model used (with version and capability details) - [x] I have checked ROADMAP.md and confirmed this PR does not duplicate planned core work - [x] I have searched GitHub for duplicate or related PRs and linked them above - [x] I have either (a) linked existing issues with `Fixes: #` / `Closes #` / `Refs #` OR (b) described the issue in-PR following the relevant issue template - [x] I have not referenced internal/instance-local Paperclip issues or links (only public GitHub `#NNN` / `github.com/paperclipai/paperclip` URLs) - [x] My branch name describes the change (e.g. `docs/...`, `fix/...`) and contains no internal Paperclip ticket id or instance-derived details - [x] I have run tests locally and they pass - [x] I have added or updated tests where applicable (not applicable: numeric workflow env tuning) - [x] I have updated relevant documentation to reflect my changes (workflow comment updated) - [x] I have considered and documented any risks above - [ ] All Paperclip CI gates are green - [ ] Greptile is 5/5 with no open P2s, recommendations, or follow-ups - [x] I will address all Greptile and reviewer comments before requesting merge |
||
|
|
16149a75fd |
ci(release): give npm publish visibility polling a 10-minute budget (#11834)
## Thinking Path
> - Paperclip is the open source app people use to manage AI agents for
work
> - The release workflow publishes every public package to npm per
master push (canary) and per promotion channel
> - `release.sh` polls the registry after each publish and aborts the
whole release when a version is not visible within 60 seconds
> - npm accepts publishes immediately, but its CDN can lag packument
propagation by several minutes; on 2026-08-21 this failed four
consecutive canary runs mid-loop even though every publish succeeded
> - This pull request sets the script's existing visibility-budget env
overrides at the workflow level to 10 minutes
> - The benefit is a release train that tolerates registry propagation
lag; a healthy publish still exits the poll on its first visible check
## Linked Issues or Issue Description
Not applicable for a `ci:` workflow tuning change. Evidence: four
consecutive `Release` runs on master failed in `publish_canary` with
"npm did not publish and expose <package>@<version>", while the raw
registry packument shows each of those versions present minutes later
(`2026.821.0-canary.0` accepted 01:36 UTC, visible 01:40;
`2026.821.0-canary.1` accepted 05:54, visible 05:57).
## What Changed
- Set `NPM_PUBLISH_VERIFY_ATTEMPTS: "30"` and
`NPM_PUBLISH_VERIFY_DELAY_SECONDS: "10"` in the `Release` workflow's
top-level `env`, raising `release.sh`'s post-publish visibility poll
from 60 seconds to 5 minutes per package for every channel. Both
variables are existing overrides read by the script
(`scripts/release.sh` lines 311-312); no script change.
- Raised the four publish jobs' `timeout-minutes` from 45 to 90 so
several laggard packages fit inside the job without exhausting it before
the tag push / Docker / release steps.
## Verification
- `release.sh` reads the two env overrides with defaults
(`${NPM_PUBLISH_VERIFY_ATTEMPTS:-12}` /
`${NPM_PUBLISH_VERIFY_DELAY_SECONDS:-5}`), so workflow-level env reaches
`publish_package_to_npm_and_wait` unchanged.
- Not run: a live release (needs the npm-canary environment). The next
master push exercises the canary path with the new budget.
## Risks
- Low risk: a genuinely failed publish now takes up to 5 minutes to
report instead of 1, and a pathological batch where most packages lag
the full budget still fails inside the 90-minute job — that pattern
means a real registry incident. The poll exits early on success, so
healthy releases are unaffected.
## Model Used
Claude Fable 5 (Anthropic, `claude-fable-5`) with extended thinking and
agentic tool use via the Claude Code CLI (release log forensics against
raw registry packument timestamps).
## Checklist
- [x] I have included a thinking path that traces from project context
to this change
- [x] I have specified the model used (with version and capability
details)
- [x] I have checked ROADMAP.md and confirmed this PR does not duplicate
planned core work
- [x] I have searched GitHub for duplicate or related PRs and linked
them above
- [x] I have either (a) linked existing issues with `Fixes: #` / `Closes
#` / `Refs #` OR (b) described the issue in-PR following the relevant
issue template
- [x] I have not referenced internal/instance-local Paperclip issues or
links (only public GitHub `#NNN` / `github.com/paperclipai/paperclip`
URLs)
- [x] My branch name describes the change (e.g. `docs/...`, `fix/...`)
and contains no internal Paperclip ticket id or instance-derived details
- [x] I have run tests locally and they pass
- [x] I have added or updated tests where applicable (not applicable:
workflow env tuning)
- [x] I have updated relevant documentation to reflect my changes
(comment in the workflow documents the budget rationale)
- [x] I have considered and documented any risks above
- [ ] All Paperclip CI gates are green
- [ ] Greptile is 5/5 with no open P2s, recommendations, or follow-ups
- [x] I will address all Greptile and reviewer comments before
requesting merge
|
||
|
|
fd106c6fa6 |
ci(commitperclip): remove the security gate that filed a draft advisory per PR (#11828)
## Thinking Path > - Paperclip's `commitperclip-review` workflow runs `check-pr-security.mjs` on every PR and files a **draft security advisory** whenever one of its heuristics fires (#6469). > - The heuristics fire on most ordinary PRs: any change under `server/src/routes/agents.ts` / `companies.ts` / `approvals.ts` / `authz.ts` / `MarkdownBody.tsx`, any test file containing `fetch(` / `exec(` / `process.env.X`, any `key: "<20+ chars>"` string (it flagged `pluginKey: "paperclipai.plugin-llm-wiki"`), any touch of `.github/workflows/`. > - The repository now holds **1,566 commitperclip-authored draft advisories** against ~99 human-reported ones, burying the reports that matter under the 🔒 Security tab. > - Nothing consumes them: no code reads the drafts, nothing reads the `security-review` check run the script also posts, and `master` has no required status checks. The "Review and dismiss if not a real concern" footer assumed a human triage loop that never existed. > - A second bug made it worse: the advisories endpoint is cursor-paginated and ignores `page=`, so `findExistingDraftAdvisory` only ever saw the newest 100 drafts and re-flagged PRs got a second draft (1,566 drafts for 1,386 distinct PRs; 136 PRs have 2+). > - Removing the gate stops the flood at the source; the quality gates and Dependency Review carry on unchanged. ## Linked Issues or Issue Description **Problem:** `check-pr-security.mjs` files a draft security advisory for nearly every PR, flooding the repository's advisory list with bot-authored noise that no one reads. Human-reported advisories in `triage` state are buried among ~1,560 `🚨 Security flag — PR #NNNN` drafts. **Expected:** the advisory list contains only real vulnerability reports. Heuristic PR checks, if wanted at all, do not create disclosure records. ## What Changed - Deleted `.github/scripts/check-pr-security.mjs` and `.github/scripts/tests/check-pr-security.test.mjs`. - Removed the `Run security gates` step from `.github/workflows/commitperclip-review.yml`, and the `security-events: write` permission that only it used. - No other script imports from the removed module (`resolveBaseRef` lives in `check-pr-dependencies.mjs` and stays). ## Verification - `node --test .github/scripts/tests/*.test.mjs` → 114 pass, 0 fail. - `grep -rn check-pr-security .github` → no remaining references. - The 1,563 existing bot drafts are being closed out-of-band via the API (there is no delete endpoint for advisories). ## Risks - Low. The only behaviour removed is the draft-advisory filing and the informational `security-review` check run, neither of which is consumed by code or branch protection. - Recommended follow-up for an org admin: drop `security_advisories: write` from the commitperclip App's permissions so no workflow can recreate this. ## Model Used Claude Fable 5 (claude-fable-5) via Claude Code, with tool use: GitHub API reads, file edits, local test runs. ## Checklist - [x] I have included a thinking path that traces from project context to this change - [x] I have specified the model used (with version and capability details) - [x] I have checked ROADMAP.md and confirmed this PR does not duplicate planned core work - [x] I have searched GitHub for duplicate or related PRs and linked them above - [x] I have either (a) linked existing issues with `Fixes: #` / `Closes #` / `Refs #` OR (b) described the issue in-PR following the relevant issue template - [x] I have run tests locally and they pass - [x] I have considered and documented any risks above 🤖 Generated with [Claude Code](https://claude.com/claude-code) https://claude.ai/code/session_016HitAcRu3NW5YDeBxXxePi --------- Co-authored-by: Claude Fable 5 <noreply@anthropic.com> |
||
|
|
b5a3a863c3 |
feat(release): bootstrap new npm packages with a placeholder publish (#11757)
## Thinking Path > - Paperclip is the open source app people use to manage AI agents for work > - Its release pipeline publishes a set of npm packages from CI with npm trusted publishing (GitHub OIDC), gated by `scripts/release-package-manifest.json` > - A brand-new package name cannot be published by CI directly: the PR bootstrap gate requires the name to resolve on npm, and a trusted-publisher rule can only be configured after the package page exists > - The current bootstrap helper closes that gap by building the package locally and publishing its real output from a maintainer machine — before the PR that adds the package has passed CI or review > - This pull request replaces that flow: the helper now publishes a minimal deprecated placeholder at version `0.0.0` that only reserves the name, so every real version ships from CI > - The benefit is that unreviewed build output never reaches npm, and the bootstrap runs from any checkout (including `master`, before the new package's PR merges) with no local build ## Linked Issues or Issue Description **What existing behavior does this improve?** The one-time npm bootstrap for a brand-new release package (`pnpm run release:bootstrap-package`). **Current behavior** The helper builds the target package locally and publishes the real build output from a maintainer machine. That content has not passed repository CI or review at publish time. The helper also requires the new package to exist in the local workspace, so it must run from the (unmerged) PR branch that adds the package. **Proposed behavior** The helper publishes a three-file placeholder at version `0.0.0` (manifest, README, and an `index.js` that throws a descriptive error), waits for the registry to show the package, then deprecates it. The PR bootstrap gate (`scripts/check-release-package-bootstrap.mjs`) only requires the name to resolve on the registry, so the placeholder satisfies it. The first real calver release from CI supersedes the placeholder, and a stable release moves `latest` off it — the same `latest` window that existed under the old flow, but containing an explicit inert stub instead of unreviewed code. **Reason and benefit** Real package content only ever reaches npm from CI, after review and merge. The bootstrap becomes safer (scope guard refuses names outside `@paperclipai/`, already-published names are rejected) and simpler (no local build, no workspace state, runs from any checkout). **Breaking changes** None at runtime. The helper's CLI surface changes: it now takes a package name only (no directory selector) and drops `--skip-build`. `doc/PUBLISHING.md` is updated to match. ## What Changed - `scripts/bootstrap-npm-package.mjs`: replaced the build-and-publish flow with a placeholder publish — stages `package.json` + `README.md` + throwing `index.js` at version `0.0.0` in a temp directory, previews with `npm publish --dry-run`, and publishes only with `--publish`. One-time passwords are prompted interactively (never passed as arguments, since they are single-use and would land in shell history), with re-prompt on a rejected or expired code. After publishing, the helper polls the registry until the package is visible (a first publish can lag by minutes; verified live at ~5 minutes), requiring two consecutive sightings before prompting for a second code and deprecating the placeholder so accidental installs warn loudly; on timeout or failure it prints the exact manual `npm deprecate` command. Added an `@paperclipai/`-scope guard and a fail-fast error when `--publish` runs without an interactive terminal. Removed the workspace-plan dependency so it runs from any checkout. - `scripts/bootstrap-npm-package.test.mjs`: rewrote for the new interface — argument parsing, scope validation, the generated placeholder files (manifest shape, throwing entry point, README), the OTP re-prompt loop, and the registry poll (consecutive-sighting requirement, timeout, transient-error tolerance) via injected fakes. - `doc/PUBLISHING.md`: rewrote the "One-time bootstrap sequence for a new package" section for the placeholder flow, including the `latest` dist-tag window and the trusted-publishing setup ordering (placeholder publish → trusted publisher rule → `"publishFromCi": true`). - `.github/scripts/check-pr-release-bootstrap.mjs` (+ test, + wiring in `run-quality-gates.mjs`): new informational commitperclip notice on PRs that need this bootstrap. It fires when the PR newly release-enables a package that is missing from npm, or adds an unpublished `publishFromCi: false` package that published packages declare a `workspace:*` dependency on, and names the exact maintainer command — so contributors know the red `policy` check is not theirs to fix. It never fails the gate (the `policy` job remains the enforcer), only looks up scope-validated names on the registry, and stays quiet on registry errors. ## Verification - `node --test scripts/bootstrap-npm-package.test.mjs`: 13/13 pass - `node --test .github/scripts/tests/*.test.mjs`: 147/147 pass (10 new for the PR notice) - `pnpm run test:release-registry`: 82/82 pass - Replayed the new PR notice against a real historical PR's live API data (files, manifest at base and head refs): with the registry in its pre-bootstrap state it produces the exact maintainer instruction; with the package bootstrapped it stays silent - Full live end-to-end run: the flow bootstrapped `@paperclipai/adapter-kimi-local` for real — dry-run preview (634-byte, 3-file tarball), publish, registry visibility after ~5 minutes of propagation lag, deprecation confirmed via `npm view ... deprecated` - Guards verified live: an already-published name is rejected, an out-of-scope name (`left-pad`) is rejected, unknown options (including the removed `--otp`) are rejected, and `--publish` in a non-interactive shell fails fast before any network call ## Risks - The `latest` dist-tag points at the deprecated `0.0.0` placeholder until the first stable release supersedes it. This window also existed under the old flow (which parked `latest` at a locally built version); internal consumers are unaffected because release version rewrites pin exact calver versions. - The registry poll caps at ~10 minutes. If propagation is slower than that, the helper prints the exact `npm deprecate ... --otp <code>` command to run manually once `npm view` resolves. - The helper no longer validates the name against the workspace release plan, so a typo within the `@paperclipai/` scope would reserve a wrong name. The dry-run preview shows the exact name before any publish. ## Model Used - Anthropic, **Claude Fable 5** (`claude-fable-5`) via Claude Code, with repository, shell, and Git tooling. It analyzed the existing bootstrap flow and the release scripts (`release-package-map.mjs`, `check-release-package-bootstrap.mjs`, `release.sh` dist-tag handling), wrote the replacement script and tests, updated the documentation, and ran the verification above. ## Checklist - [x] I have included a thinking path that traces from project context to this change - [x] I have specified the model used (with version and capability details) - [x] I have checked ROADMAP.md and confirmed this PR does not duplicate planned core work - [x] I have searched GitHub for duplicate or related PRs and linked them above - [x] I have either (a) linked existing issues with `Fixes: #` / `Closes #` / `Refs #` OR (b) described the issue in-PR following the relevant issue template - [x] I have not referenced internal/instance-local Paperclip issues or links (only public GitHub `#NNN` / `github.com/paperclipai/paperclip` URLs) - [x] My branch name describes the change (e.g. `docs/...`, `fix/...`) and contains no internal Paperclip ticket id or instance-derived details - [x] I have run tests locally and they pass - [x] I have added or updated tests where applicable - [x] I have updated relevant documentation to reflect my changes - [x] I have considered and documented any risks above - [ ] All Paperclip CI gates are green - [ ] Greptile is 5/5 with no open P2s, recommendations, or follow-ups - [x] I will address all Greptile and reviewer comments before requesting merge |
||
|
|
8b2dbd9d87 |
chore(deps): open one dependabot PR per major update (#11709)
## Thinking Path
> - Paperclip is the open source app people use to manage AI agents for
work.
> - Dependabot keeps the project dependencies current.
> - The npm update rule groups all major updates into one pull request.
> - One blocked major update can stop that grouped pull request.
> - This pull request gives each major update its own pull request.
> - The higher limit keeps the initial major updates and normal updates
visible.
## Linked Issues or Issue Description
**What happened?**
Dependabot grouped all npm major updates into one weekly pull request. A
blocked upgrade stopped the grouped pull request and hid other ready
updates.
**Expected behavior**
Dependabot should open one pull request for each npm major update.
**Steps to reproduce**
1. Read the npm entry in `.github/dependabot.yml`.
2. Run the weekly Dependabot update.
3. Inspect the pull requests for major npm updates.
**Paperclip version or commit**
`master` at the base commit for this pull request.
**Deployment mode**
Not applicable. This change affects repository configuration.
**Installation method**
Not applicable. This change affects repository configuration.
**Agent adapter(s) involved**
Not adapter-specific (repository configuration).
**Database mode**
Not database-related.
**Additional context**
The grouped major update included a blocked `js-yaml` upgrade. Separate
pull requests let other major updates proceed independently.
## What Changed
- Remove the `major-updates` group from the npm Dependabot entry.
- Raise the npm `open-pull-requests-limit` from 10 to 20.
- Keep the GitHub Actions Dependabot entry unchanged.
## Verification
- Run `python3 -c "import yaml;
yaml.safe_load(open('.github/dependabot.yml'))"`.
- Confirm the diff changes only `.github/dependabot.yml`.
- Confirm CI passes on this pull request.
## Risks
This change can open more Dependabot pull requests. The limit of 20
bounds the number of open npm update pull requests. No application code
changes.
## Model Used
OpenAI GPT-5. Tool use and code repository inspection assisted this
change.
## Checklist
- [x] I have included a thinking path that traces from project context
to this change
- [x] I have specified the model used (with version and capability
details)
- [x] I have checked ROADMAP.md and confirmed this PR does not duplicate
planned core work
- [x] I have searched GitHub for duplicate or related PRs and linked
them above
- [x] I have either (a) linked existing issues with `Fixes: #` /
`Closes: #` / `Refs #` OR (b) described the issue in-PR following the
relevant issue template
- [x] I have not referenced internal/instance-local Paperclip issues or
links (only public GitHub `#NNN` / `github.com/paperclipai/paperclip`
URLs)
- [x] My branch name describes the change (e.g. `docs/...`, `fix/...`)
and contains no internal Paperclip ticket id or instance-derived details
- [x] I have run tests locally and they pass
- [x] I have added or updated tests where applicable
- [x] I have updated relevant documentation to reflect my changes
- [x] I have considered and documented any risks above
- [x] All Paperclip CI gates are green
- [x] Greptile is 5/5 with no open P2s, recommendations, or follow-ups
- [x] I will address all Greptile and reviewer comments before
requesting merge
Co-authored-by: Paperclip <noreply@paperclip.ing>
|
||
|
|
664052f8ea |
feat(release): draft stable notes at beta publish, read them from master at promotion (#11567)
## Thinking Path > - Paperclip is the open source app people use to manage AI agents for work > - The release channel system promotes builds canary → nightly → beta → stable, and stable releases publish a GitHub Release from `releases/vYYYY.MDD.P.md` > - The stable lane requires that notes file to exist inside the promoted source commit, but the file is named for the promotion date, which is unknown when the source commit is created > - A promoted beta can therefore never pass the notes check: every happy-path stable is forced through the candidate-branch fix path, with a soak-gate justification, for a notes-only change > - This pull request drafts the notes automatically when the beta is published and lets the stable promotion read them from `master` > - The benefit is a walkable stable happy path: the soak gate stays exact, notes get a real review window during the soak, and the justification path returns to its real purpose (cherry-picked fixes) ## Linked Issues or Issue Description **What existing behavior does this improve?** The stable promotion path in the release channel system (`release.yml`, `scripts/release.sh`). **Current behavior** `release.sh stable` requires `releases/vYYYY.MDD.P.md` in the checked-out source tree, and `publish_stable` checks out the exact promoted SHA. The soak gate requires a `beta/v*` tag to point at that same SHA. No commit can satisfy both for a promoted beta, so a stable promotion must cut a candidate branch with a notes-only commit and bypass the soak gate with a written justification. Release notes are also written at promotion time, under time pressure, with no review window. **Proposed behavior** When a beta publishes, a `draft_stable_notes` job generates a grouped notes skeleton at `releases/beta/v<beta-version>.md` and pushes it to a machine-owned branch; a human opens the PR and edits it during the 3-day soak. The stable preflight resolves notes before the `npm-stable` approval gate: source-tree notes first (the candidate fix path, unchanged), then the merged beta-keyed file on `master`; it fails early with the missing path named when neither exists. After the stable ships, a canonicalization job pushes a branch that moves the file to `releases/vYYYY.MDD.P.md`. Related (not duplicates): #11006 and #11008 introduced the nightly and beta lanes this builds on; older changelog PRs (for example #10669) authored notes manually at promotion time, which is the flow this replaces. **Reason and benefit** The happy path becomes: promote the exact soaked SHA, no justification, notes reviewed during the soak instead of written at the gate. The `releases/vYYYY.MDD.P.md` invariant still holds durably via the canonicalization PR. ## What Changed - `scripts/release.sh`: new `--notes-file PATH` (stable only) overrides where the pre-publish notes check looks, so notes can live outside the source checkout without dirtying the worktree. - `scripts/create-github-release.sh`: same `--notes-file` override for the GitHub Release body. - `scripts/draft-stable-notes.sh` (new): deterministic skeleton generator — commit subjects from the newest stable tag (falling back to the previous beta, then full history) to the beta's source commit, grouped into Features / Fixes / Other. - `.github/workflows/release.yml`: - `draft_stable_notes` job after `publish_beta`: runs the generator and force-pushes `release-notes/v<beta-version>`; the job summary links the compare page. It recreates the beta tag locally if the tag push was rejected (the known workflows-permission case), so drafting is not blocked on manual tag recovery. - `preflight_stable`: computes the target stable version (`release.sh stable --print-version`) and resolves the notes source (`source_tree` → `master_beta` → fail early / warn on dry run); new outputs. - `publish_stable`: materializes `master`-side notes into `RUNNER_TEMP` and passes `--notes-file` to both scripts; outputs the published stable version. - `canonicalize_stable_notes` job: pushes the `git mv` branch after a stable that used `master`-side notes. - `doc/RELEASING.md`, `doc/RELEASE-CHECKLIST.md`: document the drafted-notes flow, the preflight resolution order, and the canonicalization step; the LLM changelog flow now targets the draft branch during the soak. - `.agents/skills/release-changelog/SKILL.md`, `.agents/skills/release-changelog-discord-message/SKILL.md`: the notes-authoring skills now describe this flow — range ends at the beta source commit (not `HEAD`), the file is beta-keyed on the `release-notes/v<beta-version>` branch (seeded with `scripts/draft-stable-notes.sh` for betas that predate the automation), and the canonicalization link caveat is called out for announcements. ## Verification - `node --test scripts/draft-stable-notes.test.mjs` — 6 tests, temp git-repo fixtures: grouping, stable-tag range, previous-beta and full-history fallbacks, default output path, malformed version, missing tag. - `node --test scripts/release-lib.test.mjs` — unchanged suite still green. - `bash -n` on both changed shell scripts; `release.yml` re-parsed as YAML. - `./scripts/release.sh stable --print-version` unchanged (prints the next stable version); `--notes-file` on a non-stable channel fails with a clear error. - Not exercised end-to-end: the new workflow jobs need a real beta publish to run. The first beta after merge is the live test; the draft job is additive and cannot affect the publish result (it runs after `publish_beta` completes). ## Risks - Low risk to publishing itself: `--notes-file` defaults preserve today's behavior everywhere; the draft and canonicalization jobs are additive and run after the publishes succeed. - The preflight now fails a real stable run when no notes are found. That is the intended fail-early behavior (it previously failed later, inside `publish_stable`, after the `npm-stable` approval). - `draft_stable_notes` force-pushes only the machine-owned `release-notes/v<beta-version>` branch; a beta re-cut regenerates it cleanly. - The stable version computed at preflight could differ from the published one if a run crosses UTC midnight between the two jobs; the materialized notes are passed by path, so the publish still succeeds, and the canonicalization job uses the actually-published version. ## Model Used Claude Fable 5 (Claude Code) ## Pre-submission checklist - [x] I have included a thinking path that traces from project context to this change - [x] I have specified the model used (with version and capability details) - [x] I have checked ROADMAP.md and confirmed this PR does not duplicate planned core work - [x] I have searched GitHub for duplicate or related PRs and linked them above - [x] I have either (a) linked existing issues with `Fixes: #` / `Closes #` / `Refs #` OR (b) described the issue in-PR following the relevant issue template |
||
|
|
49217aadf0 |
refactor: balance serialized server shards by recorded suite duration (#11528)
<!-- Write all pull request text in Simplified Technical English (ASD-STE100). --> ## Thinking Path > - Paperclip is the open source app people use to manage AI agents for work > - The PR verify workflow gates every pull request; its wall-clock time sets the feedback loop for all contributors > - In a recent successful PR run (actions run 32012408876), the slowest check was "Verify serialized server suites (1/5)" at 337s, while its four sibling shards finished in 212-238s > - The serialized lane assigns suites to shards round-robin over an alphabetical list, so the heavy heartbeat and issues suites cluster on one runner > - The general-server lane already solves this with a duration-aware LPT partition backed by a recorded manifest > - This pull request reuses that partitioner for the serialized lane with a fresh per-suite duration manifest > - The benefit is a balanced serialized matrix: the measured 968s suite total levels to about 194s per shard, which removes about 80-100s from the run's slowest check ## Linked Issues or Issue Description **What existing behavior does this improve?** The `Verify serialized server suites` shard matrix in `.github/workflows/pr.yml` distributes route/authz test suites across five runners. **Subsystem affected** CI / test infrastructure (`scripts/run-vitest-stable.mjs`). **Current behavior** `selectSerializedSuites` assigns suites round-robin (`index % shardCount`) over the alphabetically sorted file list. The heavy suites cluster on shard 1/5. In actions run 32012408876, shard 1/5 spent 291s in its test step while the other shards spent 170-201s, which made that job (337s total) the slowest check of the whole PR run. **Proposed behavior** Partition the serialized suites with the same duration-aware LPT algorithm the general-server lane already uses (`scripts/general-server-shard.mjs`), backed by a new per-suite duration manifest. All five shards then carry about 194s of measured test time. **Reason and benefit** The slowest check bounds PR feedback time. Balancing the serialized matrix removes about 80-100s from that bound without adding runners. **Breaking changes** None. The partition remains deterministic, complete, and non-overlapping; suites missing from the manifest get the median weight. ## What Changed - Added `scripts/serialized-shard-durations.json`: per-suite wall-clock durations (ms) for all 134 serialized suites, sampled from actions run 32012408876 by diffing consecutive per-suite label timestamps in the shard logs (captures vitest spawn overhead, not just reported test time) - `scripts/run-vitest-stable.mjs`: `selectSerializedSuites` now uses the existing LPT partitioner (`selectGeneralServerShard`) with the new manifest instead of round-robin - `scripts/__tests__/run-vitest-stable-shard.test.mjs`: added a manifest-freshness test and a shard-balance test for the serialized lane, mirroring the general-server ones - `.github/workflows/pr.yml`: updated the serialized matrix comment with the new measurement and mechanism ## Verification - `node --test ./scripts/__tests__/run-vitest-stable-shard.test.mjs` passes (13 tests), including the existing test that the serialized shards form a complete, non-overlapping partition - Dry-run of all five shards shows estimated totals of 194/194/194/194/193s (round-robin was 276/175/160/172/187s): `node scripts/run-vitest-stable.mjs --mode serialized --shard-index N --shard-count 5 --dry-run` - The `Verify serialized server suites` jobs on this PR run the real partition end to end ## Risks - Low risk. Selection logic only; the vitest invocation per suite is unchanged - A stale manifest degrades gracefully: unknown suites get the median weight, and a dedicated test fails if fewer than half the current suites have recorded durations ## Model Used - Claude (Anthropic), model ID `claude-fable-5`, agentic coding session with tool use (Claude Code / Claude Agent SDK); no extended-thinking mode ## Checklist - [x] I have included a thinking path that traces from project context to this change - [x] I have specified the model used (with version and capability details) - [x] I have checked ROADMAP.md and confirmed this PR does not duplicate planned core work - [x] I have searched GitHub for duplicate or related PRs and linked them above - [x] I have either (a) linked existing issues with `Fixes: #` / `Closes #` / `Refs #` OR (b) described the issue in-PR following the relevant issue template - [x] I have not referenced internal/instance-local Paperclip issues or links (only public GitHub `#NNN` / `github.com/paperclipai/paperclip` URLs) - [x] My branch name describes the change (e.g. `docs/...`, `fix/...`) and contains no internal Paperclip ticket id or instance-derived details - [x] I have run tests locally and they pass - [x] I have added or updated tests where applicable - [x] I have updated relevant documentation to reflect my changes - [x] I have considered and documented any risks above - [x] All Paperclip CI gates are green - [x] Greptile is 5/5 with no open P2s, recommendations, or follow-ups - [x] I will address all Greptile and reviewer comments before requesting merge Related prior work: #10923 (split serialized tests into five shards), #10925 (general-server duration manifest), #11156 (workspaces-a native shards). Co-authored-by: Claude <noreply@anthropic.com> Co-authored-by: Paperclip <noreply@paperclip.ing> |
||
|
|
2ec984502a |
fix(release): stop smoke_beta silently skipping on promote-mode betas (#11582)
## Thinking Path > - Paperclip is the open source app people use to manage AI agents for work > - The release channel system re-smokes every published beta as post-publish verification (`smoke_beta`) > - The candidate-branch beta lane (#11209) added `verify_beta_candidate` to `publish_beta`'s needs; that job is skipped on every normal promote-mode beta > - `smoke_beta`'s condition has no status-check function, so GitHub attaches an implicit `success()` that evaluates the needs chain transitively — a skipped ancestor makes it false > - This pull request makes the condition explicit so promote-mode betas smoke again, and pins the shape in the workflow wiring test > - The benefit is that the post-publish beta gate actually runs instead of silently skipping ## Linked Issues or Issue Description **What happened?** Beta `2026.818.0-beta.0` (run 32082007439) published successfully, but its post-publish `smoke_beta` job was skipped. No configuration or input asked for that: the run was a plain `channel: beta` dispatch with `dry_run` at its default `false`, and the same expression `!inputs.dry_run` evaluated true inside `publish_beta`'s own steps (the Docker dispatch step ran). **Expected behavior** Every non-dry-run beta publish is followed by the release smoke suite against the exact published version, as documented in `doc/RELEASING.md` and `doc/RELEASE-CHECKLIST.md`. **Steps to reproduce** Dispatch `release.yml` with `channel: beta` promoting a nightly (promote mode). `verify_beta_candidate` is skipped by design; `publish_beta` runs through its explicit `!cancelled()` condition; `smoke_beta` then skips because its implicit `success()` sees the skipped ancestor in the transitive needs chain (actions/runner#2205 semantics). The beta published on 2026-08-11 predated #11209, so this never surfaced before. **Paperclip version or commit** master at `43ab441f0` (workflow file, current head). Related (not duplicates): #11209 introduced the candidate lane whose skipped job triggers this; #11208 covers the adjacent tag-push failure playbooks. ## What Changed - `smoke_beta`'s condition becomes `!cancelled() && needs.publish_beta.result == 'success' && !inputs.dry_run` — an explicit status-check function suppresses the implicit `success()`, and the result check keeps the dependency on a successful publish. - A comment above the job records why the explicit form is load-bearing. - `scripts/__tests__/release-verify-workflow.test.mjs` pins the new shape so the implicit form cannot silently return. ## Verification - `node --test scripts/__tests__/release-verify-workflow.test.mjs` — 8 pass, including the new assertion. - `release.yml` re-parsed as YAML. - The exact skip is visible on run 32082007439 (`smoke_beta: skipped` after `publish_beta: success`); the coverage gap for that beta was closed manually by dispatching `release-smoke.yml` with `paperclip_version: beta` (run 32084880767). - Not exercised end-to-end: the corrected condition needs the next real promote-mode beta to demonstrate; the expression change is minimal and the semantics are the documented actions/runner behavior. ## Risks - Low risk: condition-only change on one job plus a test. Dry runs still skip the smoke (`!inputs.dry_run` retained). Candidate-mode betas, where `verify_beta_candidate` actually runs, behave as before. ## Model Used Claude Fable 5 (Claude Code) ## Pre-submission checklist - [x] I have included a thinking path that traces from project context to this change - [x] I have specified the model used (with version and capability details) - [x] I have checked ROADMAP.md and confirmed this PR does not duplicate planned core work - [x] I have searched GitHub for duplicate or related PRs and linked them above - [x] I have either (a) linked existing issues with `Fixes: #` / `Closes #` / `Refs #` OR (b) described the issue in-PR following the relevant issue template |
||
|
|
d24a79f741 |
ci(dependabot): surface major npm updates as one grouped weekly PR (#11307)
## Thinking Path > - Paperclip is the open source app people use to manage AI agents for work > - Dependabot keeps the npm dependency tree and the GitHub Actions workflows current with weekly update PRs > - The npm config ignores every major version bump with a wildcard `ignore` rule, and no other process reports pending majors > - Major-version debt grows silently, and ignore rules also suppress Dependabot security updates when the fix ships only in a newer major > - Individual major PRs are not a good replacement: the board decided in #7560 to keep the PR list mergeable, and a flood of breaking bumps works against that > - This pull request removes the blanket ignore and groups all pending majors into one weekly PR, while minors and patches keep one PR per bump > - The benefit is a standing, visible signal of pending major updates, at a cost of at most one extra PR per week ## Linked Issues or Issue Description **What existing behavior does this improve?** The Dependabot npm update flow configured in `.github/dependabot.yml`. **Current behavior** Dependabot opens weekly PRs for minor and patch npm updates. A wildcard `ignore` rule suppresses every major version update. No report or reminder replaces the suppressed PRs — the comment says "review those manually", but nothing triggers that review. Ignore rules also apply to Dependabot security updates, so a security fix that ships only in a newer major is suppressed as well. **Proposed behavior** Dependabot opens one grouped weekly PR that contains every pending major npm update. Minor and patch updates keep their current one-PR-per-bump flow. A deliberate hold on a specific major can use a targeted per-dependency `ignore` entry instead of the wildcard. **Reason and benefit** Silent major-version drift compounds: each skipped major makes the eventual upgrade jump larger and riskier, especially across peer-dependency families. A single grouped PR makes the backlog visible in the PR list without flooding it. When the grouped PR is green, it merges cheaply. When it is red, it is a visible standing task instead of invisible debt. **Breaking changes** None. This changes repository automation only. Runtime behavior, response shapes, and outputs are unchanged. **Additional context** Related history: #7483 grouped patch/minor updates by dependency type, and #7560 reverted that grouping because the resulting 26-package PR was hard to merge. This PR does not touch the patch/minor flow. It only groups majors, which currently produce no PRs at all — it adds a signal that does not exist today rather than replacing individually mergeable PRs. ## What Changed - Removed the wildcard `ignore` rule for `version-update:semver-major` from the npm ecosystem in `.github/dependabot.yml`. - Added a `major-updates` group (`applies-to: version-updates`, `update-types: ["major"]`, `patterns: ["*"]`) so all pending majors land in one weekly grouped PR. - Left the schedule, labels, PR limits, and the github-actions ecosystem unchanged. ## Verification - `npx js-yaml .github/dependabot.yml` parses cleanly and the `groups` stanza follows the Dependabot v2 schema (`applies-to`, `update-types`, `patterns`). - After merge: check Insights → Dependency graph → Dependabot for config errors. The next weekly run (Monday 06:00) opens a single `major-updates` grouped PR that lists the pending majors. - No code changed, so the test suite is unaffected. ## Risks - Low risk. This is CI/automation configuration only. - The first grouped PR may be large, and red if several majors break the build. That is the intended visibility mechanism, and it does not block other work. A noisy or deliberately held-back dependency can be excluded from the group with `exclude-patterns` or a targeted per-dependency `ignore` entry. - This does not regroup minors or patches, so it does not reintroduce what #7560 reverted. ## Model Used - Claude Fable 5 (Anthropic), model ID `claude-fable-5`, via Claude Code CLI, extended thinking and tool use enabled. ## Checklist - [x] I have included a thinking path that traces from project context to this change - [x] I have specified the model used (with version and capability details) - [x] I have checked ROADMAP.md and confirmed this PR does not duplicate planned core work - [x] I have searched GitHub for duplicate or related PRs and linked them above - [x] I have either (a) linked existing issues with `Fixes: #` / `Closes #` / `Refs #` OR (b) described the issue in-PR following the relevant issue template - [x] I have not referenced internal/instance-local Paperclip issues or links (only public GitHub `#NNN` / `github.com/paperclipai/paperclip` URLs) - [x] My branch name describes the change (e.g. `docs/...`, `fix/...`) and contains no internal Paperclip ticket id or instance-derived details - [ ] I have run tests locally and they pass — N/A, YAML-only CI config change; validated with `js-yaml` - [ ] I have added or updated tests where applicable — N/A, no code changed - [x] I have updated relevant documentation to reflect my changes — none reference the Dependabot config - [x] I have considered and documented any risks above - [x] All Paperclip CI gates are green — one e2e shard flaked on an unrelated MCP UI spec and passed on re-run with identical code - [x] Greptile is 5/5 with no open P2s, recommendations, or follow-ups - [x] I will address all Greptile and reviewer comments before requesting merge |
||
|
|
71e9d6bb0b |
feat(release): candidate-branch beta builds and the release checklist (#11209)
> Follow-up to #11208 (merged): rebased onto master and ready for review. ## Thinking Path > - Paperclip is the open source app people use to manage AI agents for work > - The release channels promote artifacts along canary → nightly → beta → stable, with the happy path being promotion of an existing build > - When one or two targeted fixes are needed before a beta or stable, the only options today are waiting for the next nightly or absorbing a whole day of unrelated master changes > - The channel model was designed with an escape hatch for exactly this: short-lived candidate branches carrying only cherry-picked fixes > - This pull request implements candidate-branch beta builds with full verification, documents the stable fix path through the soak-justification gate, and adds the release captain's checklist > - The benefit is that a surgical fix can ship forward without either delay or blast radius, with its provenance recorded ## Linked Issues or Issue Description Refs #11008 — completes the fix-path half of the channel model introduced there. **Subsystem affected** Release automation: `scripts/release.sh`, `.github/workflows/release.yml`, `doc/RELEASING.md`, new `doc/RELEASE-CHECKLIST.md`, tests. **Problem or motivation** Beta promotion only accepts commits that already shipped as a nightly, and stable promotion expects a soaked beta. There is no supported way to ship one or two cherry-picked fixes between lanes: an urgent fix must wait for the nightly cycle or pull in every unrelated master change from the day. The original channel design called for candidate branches to cover this, and they were deferred from the initial implementation. **Proposed solution** Candidate-branch beta builds: cut `candidate/beta-<target>` from a nightly's source commit, cherry-pick the fixes, and dispatch `channel: beta` with the new `candidate_branch` input. Selection enforces the naming convention, rejects heads that already shipped as a beta or predate the candidate tooling, and records the cherry-picked commits in the job summary. Because candidate heads never went through a canary or nightly, publication is gated on a full `release-verify` run (promoted nightlies keep skipping re-verification). The stable fix path (`candidate/release-<target>` as `source_ref`) works through the existing soak gate: the justification requirement is the deliberate, recorded trade-off for shipping unsoaked bits, and is now documented as such. ## What Changed - `scripts/release.sh`: `--from-candidate` flag (beta only) waives the shipped-a-nightly requirement while keeping the duplicate-beta guard - `.github/workflows/release.yml`: `candidate_branch` dispatch input; candidate mode in `select_beta` (naming validation, duplicate and tooling-era rejection, cherry-pick recording); new `verify_beta_candidate` job gating candidate publishes on full verification - `doc/RELEASING.md`: beta fix-path and stable fix-path sections - `doc/RELEASE-CHECKLIST.md` (new): the release captain's checklist for all four lanes as built - Tests: dry-run fixture coverage for `--from-candidate` (waives the nightly guard, keeps the duplicate guard, rejected outside beta) and wiring tests for candidate validation plus the verification gate ## Verification - `node --test` on the four affected suites: 42 pass in total (17 + 25 across the two runs), including the 5 new tests - `bash -n` on `release.sh`; YAML parse of the workflow - After merge: exercise the path end to end the first time a real cherry-picked beta is needed — dispatch with a `candidate/beta-*` branch and confirm the summary records the picks and verification runs ## Risks - Candidate builds bypass the smoke-tested-nightly provenance by design; the compensating controls are full verification before publish, the post-publish beta smoke, the human `npm-beta` gate, and recorded cherry-picks - The stable fix path rides the existing justification mechanism rather than adding a second bypass — one recorded escape hatch, not two ## Model Used Claude Fable 5 (`claude-fable-5`, Anthropic) in Claude Code, with extended thinking and full tool use. All changes model-authored under human direction. ## Checklist - [x] I have included a thinking path that traces from project context to this change - [x] I have specified the model used (with version and capability details) - [x] I have checked ROADMAP.md and confirmed this PR does not duplicate planned core work - [x] I have searched GitHub for duplicate or related PRs and linked them above - [x] I have either (a) linked existing issues with `Fixes: #` / `Closes #` / `Refs #` OR (b) described the issue in-PR following the relevant issue template - [x] I have not referenced internal/instance-local Paperclip issues or links (only public GitHub `#NNN` / `github.com/paperclipai/paperclip` URLs) - [x] My branch name describes the change (e.g. `docs/...`, `fix/...`) and contains no internal Paperclip ticket id or instance-derived details - [x] I have run tests locally and they pass - [x] I have added or updated tests where applicable - [x] I have updated relevant documentation to reflect my changes - [x] I have considered and documented any risks above - [ ] All Paperclip CI gates are green (pending — will confirm before merge) - [ ] Greptile is 5/5 with no open P2s, recommendations, or follow-ups (pending — will confirm before merge) - [x] I will address all Greptile and reviewer comments before requesting merge |
||
|
|
2da6a248c3 |
fix(release): surface recovery commands when a lane tag push is rejected (#11208)
## Thinking Path > - Paperclip is the open source app people use to manage AI agents for work > - The release subsystem's promotion lanes publish to npm, then push a lane tag and dispatch the Docker image build at that tag > - The first nightly of the beta-tooling merge published to npm and then died at the tag push: GITHUB_TOKEN may not create refs pointing at workflow-modifying commits from dispatch or scheduled runs > - The failure was a bare `remote rejected` with no guidance, leaving the release half-finished (npm live, no tag, no images) until an operator reverse-engineered the recovery > - This pull request makes every lane's tag push degrade into exact recovery instructions in the job summary > - The benefit is that a rare platform-permission rejection becomes a two-minute runbook operation instead of a forensic exercise ## Linked Issues or Issue Description Refs #11008 — the incident occurred promoting that change's own merge commit, the first workflow-modifying commit to flow through the lanes it introduced. **Subsystem affected** Release automation: `.github/workflows/release.yml`, `doc/RELEASING.md`, workflow wiring tests. **Problem or motivation** Run 31445344811 published `2026.811.0-nightly.0` to npm, then failed pushing `nightly/v2026.811.0-nightly.0`: `refusing to allow a GitHub App to create or update workflow .github/workflows/release.yml without workflows permission`. The tagged commit modifies workflow files, and GITHUB_TOKEN may not create refs pointing at such commits from dispatch or scheduled runs (push-event runs are exempt, which is why the canary tag on the same commit succeeded). The job failed with no explanation and the Docker dispatch never ran. **Proposed solution** Wrap the nightly, beta, and stable tag pushes: on rejection, write the exact recovery commands into the job summary — create and push the tag with maintainer credentials, dispatch `docker.yml` at the tag, and for stable also run `create-github-release.sh` — then fail the job. Document the cause and recovery in the failure playbooks and pin the three recovery blocks with a wiring test. ## What Changed - `.github/workflows/release.yml`: recovery-summary wrappers on the nightly, beta, and stable tag-push steps - `doc/RELEASING.md`: failure-playbook entry for the workflows-permission rejection - `scripts/__tests__/release-verify-workflow.test.mjs`: wiring test asserting all three lanes carry the recovery summary ## Verification - Wiring tests: 6 pass; YAML parse of the workflow - The recovery commands are exactly the ones used to resolve the real incident (tag push + `docker.yml` dispatch for `nightly/v2026.811.0-nightly.0`) ## Risks - Low. The happy path is unchanged (a successful push skips the wrapper); the failure path trades a bare error for actionable output and still fails the job, since the release state is genuinely incomplete ## Model Used Claude Fable 5 (`claude-fable-5`, Anthropic) in Claude Code, with extended thinking and full tool use. All changes model-authored under human direction. ## Checklist - [x] I have included a thinking path that traces from project context to this change - [x] I have specified the model used (with version and capability details) - [x] I have checked ROADMAP.md and confirmed this PR does not duplicate planned core work - [x] I have searched GitHub for duplicate or related PRs and linked them above - [x] I have either (a) linked existing issues with `Fixes: #` / `Closes #` / `Refs #` OR (b) described the issue in-PR following the relevant issue template - [x] I have not referenced internal/instance-local Paperclip issues or links (only public GitHub `#NNN` / `github.com/paperclipai/paperclip` URLs) - [x] My branch name describes the change (e.g. `docs/...`, `fix/...`) and contains no internal Paperclip ticket id or instance-derived details - [x] I have run tests locally and they pass - [x] I have added or updated tests where applicable - [x] I have updated relevant documentation to reflect my changes - [x] I have considered and documented any risks above - [ ] All Paperclip CI gates are green (pending — will confirm before merge) - [ ] Greptile is 5/5 with no open P2s, recommendations, or follow-ups (pending — will confirm before merge) - [x] I will address all Greptile and reviewer comments before requesting merge |
||
|
|
d648becb90 |
refactor(ci): split workspaces-a into two Vitest native shards
Split the slow workspaces-a CI lane into two Vitest native shards and keep release verification in parity. Co-Authored-By: Paperclip <noreply@paperclip.ing> |
||
|
|
6601014898 |
fix(release): reject promotion sources that predate their channel tooling (#11197)
## Thinking Path > - Paperclip is the open source app people use to manage AI agents for work > - The release subsystem promotes builds along canary → nightly → beta → stable, and each publish job checks out the promotion's source commit and runs that tree's release tooling > - The first beta dispatch failed with `unexpected argument: beta`: the selected nightly's source predated the beta channel, so its `release.sh` did not know the argument > - The failure was clean (argument parsing, nothing published) but cryptic, and the same trap waits for any promotion of a source older than its target channel's tooling > - This pull request makes the selection jobs reject such sources with an actionable error and documents the property > - The benefit is that a bootstrapping or old-source promotion fails in seconds with instructions, instead of mid-publish with a parser error ## Linked Issues or Issue Description Refs #11008 — the guard hardens the beta promotion flow introduced there, after its first dispatch surfaced the gap described below. **Subsystem affected** Release automation: `.github/workflows/release.yml`, `doc/RELEASING.md`, workflow wiring tests. **Problem or motivation** Run 31444045044 (first beta dispatch) failed in `publish_beta` with `unexpected argument: beta`. Promotions deliberately build from the pinned source commit, which means they also run that commit's `scripts/release.sh` — and a source that predates the target channel's introduction cannot publish it. Nothing guards this today; the error surfaces deep in the publish job with no explanation. **Proposed solution** Guard at selection time: `select_nightly` requires the source canary's `release.sh` to know the nightly channel, and `select_beta` requires the source nightly's `release.sh` to know the beta channel. Each guard literally matches the channel case arm and fails closed with a clear message naming the remedy (promote a newer source). Document the tooling-era property in `RELEASING.md` and pin the guards with a wiring test. ## What Changed - `.github/workflows/release.yml`: tooling-era guards in `select_nightly` and `select_beta` - `doc/RELEASING.md`: documents that promotions run the source commit's release tooling - `scripts/__tests__/release-verify-workflow.test.mjs`: wiring test pinning both guards ## Verification - Wiring tests: 5 pass - Guard expressions exercised against real commits: accepts the beta-capable merge commit of the beta-channel change, rejects a pre-beta commit - YAML parse of the workflow - After merge: the next beta dispatch selects a beta-capable nightly and passes the guard ## Risks - Low. Selection-time check only; the guards match the channel case arm literally and fail closed (with the same actionable message) if that line is ever reformatted ## Model Used Claude Fable 5 (`claude-fable-5`, Anthropic) in Claude Code, with extended thinking and full tool use. All changes model-authored under human direction. ## Checklist - [x] I have included a thinking path that traces from project context to this change - [x] I have specified the model used (with version and capability details) - [x] I have checked ROADMAP.md and confirmed this PR does not duplicate planned core work - [x] I have searched GitHub for duplicate or related PRs and linked them above - [x] I have either (a) linked existing issues with `Fixes: #` / `Closes #` / `Refs #` OR (b) described the issue in-PR following the relevant issue template - [x] I have not referenced internal/instance-local Paperclip issues or links (only public GitHub `#NNN` / `github.com/paperclipai/paperclip` URLs) - [x] My branch name describes the change (e.g. `docs/...`, `fix/...`) and contains no internal Paperclip ticket id or instance-derived details - [x] I have run tests locally and they pass - [x] I have added or updated tests where applicable - [x] I have updated relevant documentation to reflect my changes - [x] I have considered and documented any risks above - [ ] All Paperclip CI gates are green (pending — will confirm before merge) - [ ] Greptile is 5/5 with no open P2s, recommendations, or follow-ups (pending — will confirm before merge) - [x] I will address all Greptile and reviewer comments before requesting merge |
||
|
|
8f7b8b3fda |
feat(release): add human-gated beta channel with stable soak enforcement (#11008)
> Follow-up to #11006 (merged): rebased onto master and ready for review. ## Thinking Path > - Paperclip is the open source app people use to manage AI agents for work > - The release subsystem now publishes canary (every master push), nightly (scheduled, smoke-gated, added in #11006), and stable (manual) > - There is still no human-approved release-candidate lane between nightly and stable, and nothing enforces that a stable actually soaked anywhere before shipping > - Betas need a real approval gate, and stables need a soak policy that is data, not prose > - This pull request adds the beta channel: a manual promotion of a chosen nightly behind the `npm-beta` environment gate, re-smoked after publish, plus a stable preflight that enforces a 3-day beta soak with a written-justification bypass > - The benefit is a complete canary → nightly → beta → stable train where every stable shipped as a beta first, and emergencies leave a written trace ## Linked Issues or Issue Description **Subsystem affected** Release automation: `scripts/release.sh`, `scripts/release-lib.sh`, `.github/workflows/release.yml`, `.github/workflows/docker.yml`, `.github/workflows/release-smoke.yml`. **Problem or motivation** After #11006 the project has canary and nightly prerelease lanes, but no release-candidate lane. Stable promotion has no enforced soak: any ref can ship as stable directly. There is no approval boundary for a broader-audience prerelease, and no structured way to record why an emergency release skipped validation. **Proposed solution** Add a `beta` channel: a manual dispatch that promotes a chosen nightly's source commit, publishes behind the `npm-beta` GitHub environment (required reviewers are the gate), re-smokes the published beta, and tags `beta/vX`. Enforce in the stable path that the source commit shipped as a beta at least 3 days earlier (measured from the beta's npm publish time), with a `skip_soak_justification` input as the recorded emergency bypass. **Alternatives considered** Codifying the soak policy in docs only. Rejected: an unenforced policy decays; the preflight makes the policy executable while the justification input keeps the emergency path usable and auditable. ## What Changed - `scripts/release.sh` + `scripts/release-lib.sh`: `beta` channel — requires HEAD to carry a `nightly/v*` tag, publishes the package set as `YYYY.MDD.P-beta.N` under dist-tag `beta`, tags `beta/vYYYY.MDD.P-beta.N` - `.github/workflows/release.yml`: - `channel: beta` dispatch path: `select_beta` resolves the newest (or an explicit `source_version`) nightly and fails loudly on selection problems; `publish_beta` runs behind the `npm-beta` environment, pushes the tag, and dispatches `docker.yml`; `smoke_beta` re-runs the release smoke suite against the exact published beta version - stable path: new `preflight_stable` job enforces the 3-day beta soak from the beta's npm publish time; `skip_soak_justification` bypasses with the reason echoed into the job summary; dry runs report without blocking - `.github/workflows/docker.yml`: `beta/v*` tags publish `:beta` on both images, with exact version stamping - `.github/workflows/release-smoke.yml`: `beta` added to the dispatch choice list - Docs: `CHANNELS.md` beta entries; `RELEASING.md` beta lane, soak gate, and failure playbook; `RELEASE-AUTOMATION-SETUP.md` `npm-beta` environment setup, including the warning to create the environment before the first beta dispatch (GitHub auto-creates unprotected environments on first reference) - Tests: beta version-counting coverage in `scripts/release-registry-versions.test.mjs`; beta identity and nightly-tag guard coverage in `scripts/__tests__/release-dry-run-notes.test.mjs` ## Verification - `node --test` on the two touched suites: 17 pass, including the 3 new beta tests - `bash -n` on both shell scripts and YAML parse of all three workflows - After merge, in order: create the `npm-beta` environment, dispatch `channel: beta` with `dry_run: true` to preview, then a real promotion of a published nightly through the approval gate, then a stable dry-run against a young beta to see the soak gate report ## Risks - If the `npm-beta` environment does not exist when the first beta dispatch runs, GitHub creates it with no protection rules and the beta publishes without approval. Mitigated by documentation and by creating the environment before merge (operator step) - Until the first beta exists, every stable dispatch requires `skip_soak_justification`. This is deliberate — the first beta ships immediately after this merges — but it is a behavior change to the stable dispatch - The soak clock reads the beta's npm publish time from the registry; a registry outage makes the preflight fall back to requiring justification (fail-closed) ## Model Used Claude Fable 5 (`claude-fable-5`, Anthropic) in Claude Code, with extended thinking and full tool use (repository exploration, local test execution, live registry and git verification). All code, tests, and docs in this PR were model-authored under human direction. ## Checklist - [x] I have included a thinking path that traces from project context to this change - [x] I have specified the model used (with version and capability details) - [x] I have checked ROADMAP.md and confirmed this PR does not duplicate planned core work - [x] I have searched GitHub for duplicate or related PRs and linked them above - [x] I have either (a) linked existing issues with `Fixes: #` / `Closes #` / `Refs #` OR (b) described the issue in-PR following the relevant issue template - [x] I have not referenced internal/instance-local Paperclip issues or links (only public GitHub `#NNN` / `github.com/paperclipai/paperclip` URLs) - [x] My branch name describes the change (e.g. `docs/...`, `fix/...`) and contains no internal Paperclip ticket id or instance-derived details - [x] I have run tests locally and they pass - [x] I have added or updated tests where applicable - [x] I have updated relevant documentation to reflect my changes - [x] I have considered and documented any risks above - [ ] All Paperclip CI gates are green (pending — will confirm before merge) - [ ] Greptile is 5/5 with no open P2s, recommendations, or follow-ups (pending — will confirm before merge) - [x] I will address all Greptile and reviewer comments before requesting merge |
||
|
|
30f6999cbe |
fix(release-smoke): configurable readiness timeout and diagnostics for slow containers (#11187)
## Thinking Path > - Paperclip is the open source app people use to manage AI agents for work > - The release subsystem's nightly lane (#11006) gates every nightly publish on the release smoke suite, which boots the published artifact in a Docker container > - The suite's first CI execution failed at the health readiness check: the harness hard-codes a 90 second budget, but a CI container cold-installs paperclipai from npm and initializes embedded postgres with no warm caches > - When the timeout expired with the container still running, the harness printed no container logs, so the failure gave no diagnostics > - This pull request makes the readiness budget configurable, raises it for CI, and dumps container logs on timeout > - The benefit is that the nightly gate measures the artifact, not the runner's cold caches, and a red smoke run is diagnosable from its logs ## Linked Issues or Issue Description **Subsystem affected** Release smoke testing: `scripts/docker-onboard-smoke.sh`, `.github/workflows/release-smoke.yml`. **Problem or motivation** Run 31426044332 (first forced nightly after #11006) failed in `smoke_nightly` with `server did not become ready at http://localhost:3232/api/health` after exactly 90 seconds. The harness's readiness window is hard-coded to 90 attempts at 1 second. Locally that works because the npm cache is warm; in CI the container downloads the full package set and embedded postgres first. The timeout path also printed no container logs when the container was still running, so there was no way to see how far boot had progressed. **Proposed solution** Make the readiness budget an environment variable (`SMOKE_READY_TIMEOUT_SECONDS`, default unchanged at 90 for local use), set it to 420 in the CI workflow, and dump the last 150 container log lines when the readiness check times out on a still-running container. ## What Changed - `scripts/docker-onboard-smoke.sh`: `SMOKE_READY_TIMEOUT_SECONDS` env var (default 90) replaces the hard-coded readiness budget; timeout with a still-running container now prints the tail of `docker logs` - `.github/workflows/release-smoke.yml`: sets `SMOKE_READY_TIMEOUT_SECONDS=420` for CI runs ## Verification - `bash -n` on the harness and YAML parse of the workflow - The real proof is the next `channel: nightly` dispatch of `release.yml`, which re-runs this suite in CI with the new budget ## Risks - Low. The local default is unchanged; CI runs simply wait longer before declaring failure, and a genuinely broken artifact still fails (with logs now) ## Model Used Claude Fable 5 (`claude-fable-5`, Anthropic) in Claude Code, with extended thinking and full tool use. Diagnosis from CI run logs; patch model-authored under human direction. ## Checklist - [x] I have included a thinking path that traces from project context to this change - [x] I have specified the model used (with version and capability details) - [x] I have checked ROADMAP.md and confirmed this PR does not duplicate planned core work - [x] I have searched GitHub for duplicate or related PRs and linked them above - [x] I have either (a) linked existing issues with `Fixes: #` / `Closes #` / `Refs #` OR (b) described the issue in-PR following the relevant issue template - [x] I have not referenced internal/instance-local Paperclip issues or links (only public GitHub `#NNN` / `github.com/paperclipai/paperclip` URLs) - [x] My branch name describes the change (e.g. `docs/...`, `fix/...`) and contains no internal Paperclip ticket id or instance-derived details - [x] I have run tests locally and they pass - [x] I have added or updated tests where applicable - [x] I have updated relevant documentation to reflect my changes - [x] I have considered and documented any risks above - [ ] All Paperclip CI gates are green (pending — will confirm before merge) - [ ] Greptile is 5/5 with no open P2s, recommendations, or follow-ups (pending — will confirm before merge) - [x] I will address all Greptile and reviewer comments before requesting merge |