mirror of
https://github.com/paperclipai/paperclip.git
synced 2026-10-22 00:30:19 +02:00
eefd3f22ea3038964a0eeb5f472fc6df7e5e11ff
2
Commits
| Author | SHA1 | Message | Date | |
|---|---|---|---|---|
|
|
933749e01f |
test(server): deflake postgres teardown and pinned exposure port (#11667)
## Thinking Path > - Paperclip is the open source app people use to manage AI agents for work. > - The server test suite gates every merge and every release cut. > - Three server tests each failed exactly once on markdown-only or unrelated diffs, then passed on rerun. > - One of the three (the git-operation-scheduler owner/joiner race) was fixed on master independently by [#11671](https://github.com/paperclipai/paperclip/pull/11671) while this PR was open, so after rebasing this pull request carries the remaining two. > - A flaky gate makes release operators rerun CI and stop trusting red results. > - Each remaining flake has a real nondeterminism: a teardown race and a hard-coded host port. > - This pull request removes the nondeterminism from the two tests without weakening what they prove. > - The benefit is a test gate that fails only when the product is broken. ## Linked Issues or Issue Description - [x] I searched open and closed issues and pull requests for these test files and for these failures. I found no duplicate report or fix. **What happened?** Three one-off CI failures occurred during release operations, each on a diff that could not have caused it, and each passed on rerun: 1. Run [32086355930](https://github.com/paperclipai/paperclip/actions/runs/32086355930): `server/src/__tests__/interaction-resolution-cross-issue-cap-postgres.test.ts` — all 7 tests passed, but vitest recorded an Unhandled Error and failed the run: `TypeError: Cannot read properties of null (reading 'write')` at `postgres@3.4.9/src/connection.js:255 Immediate.nextWrite`. 2. Run [32096743814](https://github.com/paperclipai/paperclip/actions/runs/32096743814): `server/src/services/workspace-git-operation-scheduler.test.ts` — the test "coalesces the same canonical key and cleans single-flight state after success and failure" failed with an AssertionError: the two concurrent calls came back with the `singleFlightJoined` values swapped. *(Fixed on master by [#11671](https://github.com/paperclipai/paperclip/pull/11671) with an equivalent single-flight barrier while this PR was open; the fix was dropped from this PR on rebase and the file is no longer touched here.)* 3. Run [32196201529](https://github.com/paperclipai/paperclip/actions/runs/32196201529): `server/src/services/workspace-runtime-exposure.test.ts` — the test "keeps an existing runtime port that is already inside the dedicated range" failed once out of 610 recorded runs because the runtime came back on a relocated port instead of the pinned 42500. **Expected behavior** The tests pass on every run when the code under test is correct. A red result means a product defect, not scheduling luck on the CI host. **Steps to reproduce** Each flake is a low-probability race, but both remaining mechanisms reproduce deterministically: 1. Postgres teardown: the suite never ends the postgres.js pool behind `createDb`; `afterAll` only stops the embedded server. postgres.js batches small writes and flushes them with `setImmediate` (`connection.js` `nextWrite`), and `close()` nulls the socket. Stop the server while the pool is open and a pending flush can run after the socket is gone. 2. Exposure pinned port: hold any loopback socket on 42500 or 52500 (both are inside the default Linux ephemeral port range, 32768–60999) and run the test. The allocator correctly relocates, and the assertion fails with `expected 42000 to be 42500`. The client side of any loopback connection on the CI host can land on those ports. **Paperclip version or commit** Branched from `master` at `4b968d8c0`; rebased onto `5a1ce7aed`. **Privacy checklist** I reviewed this description and removed private instance URLs, internal task identifiers, credentials, and user paths. ## What Changed Both fixes are test-side. I found no product race. - `interaction-resolution-cross-issue-cap-postgres.test.ts`: `afterAll` now ends the drizzle/postgres.js pool (`db.$client.end()`) before it stops the embedded Postgres server. `end()` waits for in-flight queries, including a fire-and-forget wake that lands just after a response, and closes the sockets from the client side first. Sibling suites (for example `heartbeat-plugin-environment.test.ts`) already use this order; this suite had skipped the pool shutdown. - `workspace-runtime-exposure.test.ts`: the pinned-port test no longer hard-codes 42500. It scans the dedicated range with the suite's real loopback probe, finds the lowest free app/HMR pair, then pins the next free pair strictly above it. If the keep-preferred-port path broke, the ascending fallback scan would return the lower pair, so the assertion keeps its discriminating power while no longer betting on one fixed host port staying free. - *(Dropped on rebase: the `workspace-git-operation-scheduler.test.ts` coalescing fix, superseded by the equivalent barrier merged in [#11671](https://github.com/paperclipai/paperclip/pull/11671).)* ## Verification - Reproduced the exposure flake exactly: with a listener held on `127.0.0.1:52500`, the pre-fix test fails with `expected 42000 to be 42500`; the fixed test passes with the port still held. - The postgres flake is a probabilistic teardown race and I could not trigger it on demand. The mechanism is established from `postgres@3.4.9` source (`setImmediate`-batched `nextWrite` versus `close()` nulling the socket) and the fix removes the whole class by closing the pool before the server. - Repeat runs after the fix: the pinned-port exposure test 20/20 green while the Postgres suite looped concurrently for loopback churn; `interaction-resolution-cross-issue-cap-postgres.test.ts` 15/15 green with no unhandled errors. - Re-verified after rebasing onto `5a1ce7aed`: both changed test files pass and `tsc --noEmit` passes in `server/`. - Environment note: three unrelated tests in `workspace-runtime-exposure.test.ts` (the wildcard-bind diagnosis tests) fail on macOS before and after this change because they read `/proc`; they are untouched and pass on Linux CI. ## Risks - Low risk: both changes are test-only; no product code changed. - The pinned-port test keeps a tiny time-of-check/time-of-use window between its own probe and the runtime's bind. The window shrinks from "one fixed port must stay free across the whole CI fleet" to milliseconds on a pair just verified free. > 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 Claude Fable 5 (Claude Code) — model ID `claude-fable-5`, with repository tools and local code execution for reproduction and repeat-run verification. ## 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 |
||
|
|
10d0555189 |
fix(interactions): authorize resolvers consistently (#11376)
## Thinking Path > - Paperclip is the open source app people use to manage AI agents for work. > - Issue interactions give agents and people a structured decision record. > - Resolver routes used different authorization rules. > - Some routes blocked valid agents, including task watchdogs with normal issue access. > - The API did not show who could resolve a pending interaction. > - This pull request gives every interaction kind one resolver policy evaluator. > - The benefit is a clear decision path with consistent governance and company isolation. ## Linked Issues or Issue Description Fixes: #8087 Refs: #7403 Related PR: #11082 proposes board-only confirmation rules. This change keeps human-only review as an explicit policy. **What happened?** Agents could create issue interactions. Some resolver routes still required board access. This left valid agent confirmations pending. Task watchdogs could see the same problem without board identity. **Expected behavior** Every interaction kind must use one resolver policy contract. The contract must support `anyone`, `not_creator`, and `human_only`. It must also apply all normal governance controls. **Steps to reproduce** 1. Create a `request_confirmation` interaction as an agent. 2. Resolve it with another authorized agent. 3. Observe the board-only denial. **Paperclip version or commit** The problem exists on `master` before this change. **Deployment mode** Local development with `pnpm dev`. ## What Changed - Add canonical policies for `anyone`, `not_creator`, and `human_only`. - Use one server evaluator for every interaction kind. - Apply named addressees, company limits, review rules, and task watchdog scope. - Charge cross-issue resolutions to the existing per-run action limit. - Return the effective resolver audience in attention and interaction data. - Show the audience, governance choices, and denial reasons in the board UI. - Add telemetry, API documents, product documents, and regression fixtures. - Add migration provenance for safe legacy behavior. - Make migration `0218` safe for complete replays and partial prior runs. ## Product Rules - An interaction records a response. It does not grant authority for the next action. - `anyone` lets any authorized issue participant respond. - `not_creator` requires a responder other than the interaction creator. - `human_only` requires an authorized person. - A named addressee, company policy, or governed action can narrow the audience. - These controls cannot widen the audience. - A task watchdog uses the same rules as an ordinary agent. - A task watchdog does not receive board authority. - An agent resolution on another issue uses the shared cross-issue action limit. - Legacy pending interactions keep their earlier restrictions. - The UI shows the effective audience and a permanent denial reason. ## Verification - `pnpm --filter @paperclipai/db check:migrations` - `pnpm --filter @paperclipai/db typecheck` - `pnpm exec vitest run packages/db/src/issue-thread-interaction-resolver-policy-migration.test.ts` - The focused PostgreSQL test applies migration `0218` twice. - The test also completes a partial prior run and preserves existing provenance. - The latest GitHub head has 29 successful checks. - The opt-in Storybook visual check skipped as expected. - Greptile reports 5/5 with no open comments. ## Risks - New interaction writes use `anyone` by default. - Callers must select `not_creator` or `human_only` when they need stricter review. - Legacy pending interactions keep the old creator and human restrictions. - Migration `0218` fills only missing provenance fields during recovery. - Cross-issue resolutions can reach the existing action limit. - The shared evaluator affects every interaction kind. - Route, service, database, shared contract, and UI tests cover these rules. > This work matches the Agent Reviews and Approvals direction in `ROADMAP.md`. It does not duplicate a planned item. ## Model Used OpenAI Codex, GPT-5. The runtime does not expose the exact deployment ID or context window. The agent used reasoning, repository tools, shell commands, and test 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 public issues or described the issue with the required labels - [x] I have not referenced internal 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 - [x] I have considered and documented the risks - [x] All Paperclip CI gates are green - [x] Greptile is 5/5 with no open comments - [x] I will address all Greptile and reviewer comments before requesting merge --------- Co-authored-by: Paperclip <noreply@paperclip.ing> |