mirror of
https://github.com/paperclipai/paperclip.git
synced 2026-10-21 16:27:18 +02:00
12c8aa2d19c76464badde09a4dc5d3e2fd6e9b4b
2974
Commits
| Author | SHA1 | Message | Date | |
|---|---|---|---|---|
|
|
12c8aa2d19 |
docs: add CHANGING-THE-UI.md — teammate guide for working with the design system
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com> |
||
|
|
8189a0082b |
test: update Secrets grid assertion to tokenized grid-cols form
Batch 4 extracted the raw minmax template into --gtc-54; the render test still asserted the literal. Lockstep per the token-extraction test policy. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com> |
||
|
|
d3308602ee |
docs: move design-process artifacts to doc/design/
DESIGN.md stays at root (AGENTS.md links it); audit reports, decision sheet, prior art, and run prompts move out of the repo root. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com> |
||
|
|
8d034ae509 |
docs: close the tune session in DECISION-SHEET
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com> |
||
|
|
a483416a0d |
test: re-baseline 296 snapshots — new design language is the official baseline
Closes the preset-tune session: user approved via gallery v4 and the :3300 test-drive instance. Includes upstream-merge rendering deltas. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com> |
||
|
|
35c8bfb364 |
Merge remote-tracking branch 'origin/master' into design/token-extraction
# Conflicts: # ui/src/components/IssueThreadInteractionCard.tsx |
||
|
|
295294d7ce |
Add read-only issue blocker diagnostics endpoint (#9114)
## Thinking Path > - Paperclip is the open source app people use to manage AI agents for work > - Agents block each other with `blockedByIssueIds` relationships to express dependencies > - Users and tooling have no lightweight way to inspect *why* an issue is blocked or whether its blockers are themselves ready to resolve > - A read-only diagnostic endpoint over the existing blocker graph lets callers understand dependency chains without requiring a full issue-tree traversal > - This pull request adds `GET /api/issues/:id/diagnostics/blockers` — a bounded, read-only projection over each blocker's readiness state > - The benefit is that callers can surface blocking-chain diagnosis (e.g. "waiting on N blockers, M of which are themselves blocked") from a single authenticated request, using only data they already have read permission for ## Linked Issues or Issue Description No public GitHub issue exists for this change. Feature description: **Subsystem affected:** `server/` — REST API & orchestration services; `packages/shared` — types, constants, validators, API paths **Problem or motivation** There is no API endpoint to inspect *why* an issue is blocked or to get a per-blocker readiness summary. Clients must walk the issue graph manually or fetch full issue objects, which requires multiple round-trips and is expensive. **Proposed solution** A single `GET /api/issues/:id/diagnostics/blockers` endpoint returns a bounded projection: root issue summary, an ordered blocker list with per-blocker `readiness` state, and a top-level `diagnosis` field summarizing overall blocking status. Authorization mediation omits blockers the caller cannot read, so `diagnosis` only reflects visible data. **Alternatives considered** A general graph-walk query (too broad/expensive for a targeted diagnostic call); enriching the existing `GET /api/issues/:id` response (too coupled to the main response shape and adds weight for callers that do not need blocker detail). **Roadmap alignment** Read-only observability surface over existing data; no database schema changes. This aligns with tooling that helps users understand dependency state without mutating anything. ## What Changed - Added `GET /api/issues/:id/diagnostics/blockers` route to the server - Returns per-blocker `readiness` state and a top-level `diagnosis` field summarizing overall blocking status - Enforces `issue:read` authorization per-blocker: unauthorized blockers are omitted and do not influence `diagnosis` or `readiness` values - Added shared TypeScript response types in `@paperclipai/shared` - Added route-level tests using embedded Postgres - Added API documentation in the `paperclip` skill ## Verification ```sh ./node_modules/.bin/vitest run server/src/__tests__/issue-blocker-diagnostics-routes.test.ts pnpm --filter @paperclipai/shared typecheck pnpm --filter @paperclipai/server typecheck ``` All three commands pass locally. ## Risks - Read-only endpoint over existing relations — no writes, no schema or migration changes — low risk - Authorization mediation intentionally omits unauthorized blockers from both the list and from `diagnosis`/`readiness`; callers with partial access will see a narrower picture than the full blocker graph ## Model Used - Provider: Anthropic - Model: Claude Sonnet 4.6 (`claude-sonnet-4-6`) - Context window: 200k tokens - Mode: Tool use, code generation, extended reasoning ## 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>canary/v2026.707.0-canary.3 |
||
|
|
a9478eecb3 |
docs: record C11 — sidebar agents-section unification queued for Run 3
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com> |
||
|
|
d8ace306d3 |
feat(ui): gallery feedback round 3 — one toggle, canonical agent chips, light-wash text sweep
Four user rulings (intentional visible changes; snapshots NOT
re-baselined):
1+2. Toggle unification: the app's only second switch implementation —
ToggleField's hand-rolled h-5 w-9 pill with a bg-green-600 track in
agent-config-primitives.tsx — now renders the canonical ToggleSwitch
capsule (on = var(--status-task-done)); props/testid preserved. All
other suspects already used ToggleSwitch; every switch now shares
one form and one green.
3. Agent-status chips ('Org snippets and quick scan identity' section,
StatusBadge): statusBadge agent keys route through brandChipBadge —
running=blue, idle=gray (was yellow tint), paused=amber, and
active=green (no canonical agent status; user-ruled mapping to the
brand green family). brandChipBadge moved above statusBadge for
declaration order. Org.tsx status dots route through agentStatusDot.
4. Dark-tuned-text-on-light-wash class of bug: flagged BudgetPolicyCard
banner was already fixed in r2; systematic sweep fixed 58 more sites
in 14 files (50->950, 100->900, 200->800, 300->700 light tiers with
originals behind dark:, opacity suffixes preserved). Safe leftovers
documented (InviteLanding dark page, solid-bg badges).
DECISION-SHEET.md: 'Gallery feedback round 3' section. Gates 3/3 CLEAN,
typecheck green, ui build green.
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
|
||
|
|
22001bbd2f |
feat(db): add migration safety lint
## Thinking Path > - Paperclip is the open source app people use to manage AI agents for work > - The `packages/db` module owns all database migrations via a sequential numbering system already validated at build time > - A recent migration introduced an O(n²) batch backfill over a large, unindexed table — it caused the server's `listen` to block for ~5 minutes on databases with millions of rows > - Nothing in the current CI pipeline catches large-table migration risk patterns (DO-loop mutations, batched LIMIT mutations without support indexes, full-table mutations, non-concurrent index creation) before they land > - This PR wires a new static migration-safety checker (`check-migration-safety.ts`) into the existing `check:migrations` gate in `packages/db/package.json`, so risky patterns fail CI before reaching production > - The checker baselines all historical findings already present in the codebase, so the gate fails only on *new* unbaselined risky patterns > - The benefit is that the specific O(n²) backfill shape (and related patterns) will be caught at author time rather than at incident time ## Linked Issues or Issue Description **Feature — static migration safety lint** **Problem or motivation** Migrations against large tables (millions of rows) have caused production startup blocks. The root pattern is a batched `LIMIT`-based backfill iterating via an unindexed column, making each batch a sequential scan — O(n²) overall. No CI gate exists to flag this class of problem before merge. **Proposed solution** A static SQL-level checker that scans new migration files for known dangerous patterns against known-large tables, producing structured findings that are either baselined (suppressed) or fail the build. Patterns detected: `DO $$ loop` mutations on large tables without a same-migration support index, batched `LIMIT` mutations on large tables missing a same-migration support index, unbounded full-table mutations (no `WHERE` clause), and `CREATE INDEX` without `CONCURRENTLY` on large tables. **Alternatives considered** Runtime instrumentation (only catches issues in production), advisory locking in migrations (doesn't prevent the pattern), per-migration code review (doesn't scale consistently). **Roadmap alignment** Defensive infrastructure / operational reliability — keeps migrations from blocking production startups. Not a user-facing feature. ## What Changed - **`packages/db/package.json`** — extended `check:migrations` script to run `check-migration-safety.ts` after the existing numbering check - **`packages/db/src/check-migration-safety.ts`** — new static checker: SQL pattern matching, rule detection for four dangerous patterns, baseline diffing, and structured exit with findings summary - **`packages/db/src/migration-safety-baseline.ts`** — baseline of all existing historical findings (suppressed from failing the gate); new migrations matching these patterns without a baseline entry will fail - **`packages/db/src/table-size-estimates.ts`** — rough table size estimates from the local dev database; drives `isKnownLargeTable()` used by the safety rules - **`packages/db/src/check-migration-safety.test.ts`** — Vitest coverage for the O(n²) backfill failure mode, suppression via baseline, and each rule type ## Verification ```bash # Run the migration safety checker directly cd packages/db tsx src/check-migration-safety.ts # Run tests cd packages/db npx vitest run src/check-migration-safety.test.ts # Run the full migration check gate (numbering + safety) cd packages/db pnpm run check:migrations ``` - Tests cover the core O(n²) backfill pattern (the motivating incident), baseline suppression, and all four rule types - `check:migrations` now exits non-zero for any new unbaselined large-table migration risk pattern ## Risks - **False positives:** Table-size estimates are from a local dev database snapshot — a table small in dev but large in production would be missed. Best-effort heuristic. - **Baseline drift:** If a baselined finding's SQL changes significantly, the baseline ID (content-hash-based) will no longer match and the finding will re-surface. Intentional but may surprise authors doing incremental fixes. - **SQL parsing limitations:** Regex-based pattern matching rather than a full AST parser — complex SQL may not be detected. Acceptable for an initial gate. - **Low risk to existing behavior:** The gate only fails on *new* findings not present in the baseline. All existing migrations are baselined. ## Model Used - **Provider:** Anthropic - **Model ID:** `claude-sonnet-4-6` - **Context window:** 200K - **Tool use:** yes (file reading, bash, git operations) - **Reasoning mode:** standard (no extended thinking) ## 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 - [ ] 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>canary/v2026.707.0-canary.2 |
||
|
|
3da1bbcc5a |
feat(ui): restyle ToggleSwitch to shadcn capsule form, status-green on-state
Registry radix-luma Switch form (border-2 capsule track, oval thumb, bg-input off-state) on the existing button API — no Radix dep, no call-site changes. On-state uses var(--status-task-done) per user ruling instead of bg-primary; deviation documented in the component. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com> |
||
|
|
e2c6f4b4b7 |
feat(ui): gallery feedback round 2 — incident-card legibility, bar-fill stragglers, cyan liveness sweep
Three user rulings from the tune-session gallery (intentional visible changes; snapshots NOT re-baselined): A. BudgetIncidentCard hard-stop card was unreadable in LIGHT mode (pre-existing: dark-tuned red-50/100/200 text over the light pink gradient, no light variants). Eyebrow/title/description/banner/icon/ validation now use red-600..950 light text with the original dark classes behind dark:; same treatment for sibling BudgetPolicyCard statusTone chips + red banner. B1 gradient tokens untouched. B. Remaining bar-fill stragglers -> canonical status hues: ClaudeSubscriptionPanel fillClass and ProviderQuotaCard quota-window fills (red-400 -> bg-(--status-task-blocked), amber/yellow-400 -> bg-(--status-task-todo), green-400 -> bg-(--status-task-done)). BudgetSidebarMarker is an icon badge, not a bar — left. C. Systematic cyan->status-blue liveness sweep (~50 sites / 20 files): running tones, live dots/pings, Live surfaces (LiveRunWidget, ActiveAgentsPanel Live-now box, AgentDetail live card, IssueDetail Live pill), scheduled-retry family, externalObjectStatus running maps, timeline now-marker #2dd4bf -> #2563eb, and liveness glow shadow token VALUES --shadow-extract-1/11/14 rgba(6,182,212,0.08) -> rgba(37,99,235,0.08) (sites unchanged). Non-liveness cyan left and documented (xterm cursor, on_demand chips, assets chip, import rename text, recovery_required, ledger Advanced/snoozed, UxLab). DECISION-SHEET.md: 'Gallery feedback round 2' section. Gates 3/3 CLEAN, typecheck green, ui build green. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com> |
||
|
|
59e536fc08 |
feat(ui): gallery feedback round 1 — destructive revert, status bar fills, running=blue
Three user rulings from the tune-session gallery review (all intentional visible changes; snapshots NOT re-baselined): 1. Dark-mode --destructive reverted to master's original oklch(0.637 0.237 25.331) (preset's softer red rejected); light untouched. 2. Budget/quota progress-bar FILLS re-pointed at canonical status hues (bar-fill elements only): healthy -> bg-(--status-task-done), warning -> bg-(--status-task-todo), exceeded/hard-stop -> bg-(--status-task-blocked) in BudgetPolicyCard, QuotaBar (covers ProviderQuotaCard/BillerSpendCard surfaces), Costs, and CodexSubscriptionPanel (escalation tiers; healthy stays bg-primary/70 by design — flagged). Left: Org.tsx status dot, chip washes/borders. 3. RUNNING chips/labels cyan -> canonical blue: IssueChatThread running chip now composes brandChipBadge.blue (layout unchanged); RunTranscriptView running label via new runningLabelText export (hexes stay in lib/status-colors.ts, gate-clean); statusBadge.running, agentStatusDot.running, AgentDetail runStatusIcons.running -> blue. Left + flagged: externalObjectStatus* running (open already blue in those maps) and the cyan 'Live' branding family (dedicated decision recommended). DECISION-SHEET.md: 'Gallery feedback round 1' section added. Gates 3/3 CLEAN, typecheck green, ui build green (token bar-fill classes verified in built CSS), vitest 103/103 on touched components. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com> |
||
|
|
46d9a3c0c9 |
feat(ui): collapse type tokens to named ladder via codemod (B3, preset-tune step 3)
VISIBLE CHANGE, contact-sheet review to follow; snapshots intentionally NOT re-baselined. Executes the user-locked DECISION-SHEET.md B3 ladder with the committed, idempotent scripts/codemod-type-ladder.mjs (re-runnable; exact-string site map incl. closing parens so --ls-0_1 / --ls-0_12-style prefixes cannot mis-match; fails loudly on leftovers). Font sizes (730 sites): --fs-9/10 -> --text-nano 10px (249); --fs-11/--fs-0_7rem -> --text-micro 11px (416 + 2 inline var()); --fs-12 -> Tailwind text-xs (24); --fs-13 -> --text-compact 13px (26, 'sm 13' renamed to avoid colliding with text-sm=14px); --fs-14/15 -> Tailwind text-sm (13). Letter-spacing (202 sites): 0.08/0.1em -> --tracking-label (13); 0.12/0.14/0.16em -> --tracking-eyebrow (90); 0.18/0.2/0.22/0.24em -> --tracking-caps (99). All --fs-*/--ls-* definitions deleted; named ladder minted in the non-inline Batch 2 :root block (no @theme entries needed — text-(length:--x)/tracking-(--x) forms verified in built CSS: tokens + font-size/letter-spacing var() rules all emit). Sites moved to text-xs/text-sm additionally pick up the Tailwind scale line-height (text-(length:--x) set font-size only) — part of the reviewable change. 143 tsx files + index.css rewritten; gate-script comment example refreshed; DECISION-SHEET.md B3 -> EXECUTED (pending contact-sheet). Gates 3/3 CLEAN, typecheck green, ui build green, vitest sanity (IssueChatThread/MarkdownBody/CommentThread 135/135). No test files referenced the old forms, so no lockstep test edits were needed. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com> |
||
|
|
8b60395861 |
feat(ui): derive full radius ladder from the --radius knob (B4)
sm/md/lg/xl now calc()-derived (monotonic 3.2/5.2/7.2/11.2px at the preset's 0.45rem), replacing the legacy square-brand lg/xl = 0px. One token edit retunes every corner in the app. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com> |
||
|
|
a25dfa64a2 |
feat(ui): apply shadcn preset b1VlJj4S as token values only
--radius 0 -> 0.45rem, monochrome chart ramp, refined dark surfaces (alpha borders/input, lighter primary, softer destructive, elevated sidebar), derived 2xl/3xl/4xl radii, base-layer outline-ring default. Scaffolding churn reverted: utils.ts gutting, components.json restyle, fontsource/phosphor/shadcn-css/tw-animate deps (local Inter kept). Co-Authored-By: Claude Fable 5 <noreply@anthropic.com> |
||
|
|
ec2d87d353 |
fix(openclaw-gateway): bump adapter PROTOCOL_VERSION to 4 to match gateway (#5984)
## Summary Local OpenClaw gateways since v2026.5.x require `MIN_CLIENT_PROTOCOL_VERSION = 4` (see [openclaw/src/gateway/protocol/version.ts](https://github.com/NousResearch/openclaw/blob/main/src/gateway/protocol/version.ts)). The Paperclip openclaw_gateway adapter at v0.3.1 still sends `PROTOCOL_VERSION = 3`, which produces a WebSocket close (code 1002 \`protocol mismatch\`) before any auth challenge is issued. ## Symptom Every \`openclaw_gateway\` agent run fails with: - \`errorCode: openclaw_gateway_request_failed\` - \`error: protocol mismatch\` OpenClaw gateway journal: \`\`\` [ws] protocol mismatch conn=... remote=127.0.0.1 client=gateway-client backend vpaperclip [ws] closed before connect conn=... peer=...->127.0.0.1:18789 code=1002 reason=protocol mismatch \`\`\` ## Fix One-line bump in [\`packages/adapters/openclaw-gateway/src/server/execute.ts:89\`](packages/adapters/openclaw-gateway/src/server/execute.ts#L89): \`PROTOCOL_VERSION = 3\` → \`PROTOCOL_VERSION = 4\`. No protocol semantics changed — the adapter's existing frames are compatible with v4. ## Test plan - [x] \`pnpm --filter @paperclipai/adapter-openclaw-gateway typecheck\` clean - [x] \`pnpm --filter @paperclipai/adapter-openclaw-gateway build\` clean - [x] Verified locally: openclaw_gateway agent connects + receives challenge + completes auth handshake after the bump ## Related - Same root cause affects every openclaw_gateway-backed agent in the field. Sparkeros companies SparkEros, Inc. and SparkEros AOS Inc. both hit it. 🤖 Generated with [Claude Code](https://claude.com/claude-code) --------- Co-authored-by: Claude Opus 4.7 (1M context) <noreply@anthropic.com>canary/v2026.707.0-canary.1 |
||
|
|
313e174765 |
test: re-baseline the 2 approved ActivityCharts snapshots; close B5
User approved the status-hue alignment on the before/after contact sheet. Suite 510/510 against the updated baseline. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com> |
||
|
|
a371ceec60 |
Fail projectless git-worktree workspaces during heartbeat setup (#9118)
## Thinking Path > - Paperclip is the open source app people use to manage AI agents for work > - Agent work can run in shared, isolated, or operator-branch execution workspaces > - Isolated/operator git-worktree modes require a real git checkout as their base > - A projectless issue can otherwise resolve to the agent fallback workspace directory > - That fallback is not a valid project checkout for git worktree setup > - This pull request adds a setup-time guard before workspace realization starts > - The benefit is that misconfigured work fails with a typed remediation instead of raw git errors or accidental execution from the agent home directory ## Linked Issues or Issue Description No public GitHub issue was found for this specific failure mode. Inline description follows the bug report template: **What happened?** When a Paperclip issue has no associated project (`projectId: null`) and is configured for `isolated_workspace` or operator-branch execution with `strategy: git_worktree`, the heartbeat setup silently fell back to the `agent_home` directory as the base workspace. Because `agent_home` is not a git repository checkout, the subsequent git worktree operations either failed with raw git errors or — in the degraded path — ran in the wrong directory entirely. **Expected behavior** A projectless issue requesting `git_worktree` execution should fail immediately at setup with a typed `workspace_validation_failed` result and a human-readable remediation message explaining that a project workspace or a reusable execution workspace with a valid git base is required. **Steps to reproduce** 1. Create a Paperclip issue with `projectId: null` (no project attached). 2. Assign it to an agent configured for `isolated_workspace` execution with `strategy: git_worktree`. 3. Trigger a heartbeat run. 4. Observe: the heartbeat resolves the base workspace to `agent_home` and either emits raw git errors during worktree setup or silently executes from an incorrect directory. **Paperclip version or commit** `5cdf5103c` (current `master` HEAD at time of fix) **Deployment mode** Local dev (`pnpm dev`) / built from source — reproduces in any mode because the fallback is in core workspace resolution logic. **Agent adapter(s) involved** Not adapter-specific (core bug — affects all adapters that issue heartbeats for projectless tasks) **Database mode** Not database-related **Access context** Agent (bearer API key via `agent_api_keys`) ## What Changed - Added a heartbeat setup guard that validates isolated/operator `git_worktree` base workspaces before realization. - The guard fails projectless `agent_home` fallback cases with a typed `workspace_validation_failed` result and remediation text. - The guard also fails non-git project base directories before raw git worktree operations run. - Added regression coverage for projectless isolated mode, operator-branch mode, non-git bases, valid git bases, and shared-workspace no-op behavior. ## Verification - `pnpm exec vitest run server/src/__tests__/heartbeat-workspace-session.test.ts` - `pnpm exec vitest run server/src/__tests__/workspace-runtime.test.ts` - `pnpm --filter @paperclipai/server typecheck` - `pnpm -r typecheck` - `pnpm test:run` - `pnpm build` ## Risks - Low risk. The new guard only applies to issue-backed isolated/operator execution modes using `git_worktree`; shared workspaces and non-git-worktree strategies are left unchanged. - The intentional behavior shift is that invalid git-worktree bases now fail earlier with a structured remediation instead of reaching lower-level git setup. ## Model Used - OpenAI GPT-5 Codex, coding-agent tool-use mode with local command execution; context window size not exposed by this runtime. ## 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>canary/v2026.707.0-canary.0 |
||
|
|
b1adf5bb18 |
feat(ui): align ActivityCharts status hues with canonical --status-task-* tokens (B5)
VISIBLE CHANGE, staged for contact-sheet review (DECISION-SHEET.md B5, DESIGN.md principle 5 — one status vocabulary everywhere): the per-status chart series in ActivityCharts.tsx re-point at the canonical status system instead of an independent palette — todo #3b82f6 blue -> amber (--status-task-todo #f59e0b), in_progress #8b5cf6 violet -> blue (#2563eb), in_review #a855f7 -> #7c3aed, done #10b981 -> #22c55e, blocked #ef4444 -> #dc2626, cancelled #6b7280 -> #a8aeb2. 'backlog' keeps --project-none per the B5 ruling; priority series, success-rate tints, and the unknown-status fallback are not status hues and are untouched. The three now-orphaned tokens (--hex-3b82f6/8b5cf6/a855f7) are deleted; stale status references scrubbed from surviving token comments. Visual snapshots intentionally NOT updated — diffs exported for user review. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com> |
||
|
|
329652a2dd |
refactor(db): add migration authoring checklist (#9122)
## Thinking Path > - Paperclip is the open source app people use to manage AI agents for work > - Paperclip stores agent work in a PostgreSQL database that evolves via numbered sequential migrations > - Migrations that run large unbounded table scans can block the server's `listen()` call during upgrades, causing multi-minute startup stalls on large databases > - Migration 0126 ran a full sequential scan backfill over `issue_comments` for derived attribution columns — O(n²) due to unindexed `LIMIT`/`OFFSET` batching, pegging CPU for ~5 minutes on a 3–4 M row table > - The safe fix (landed in #9108) replaced 0126 with a new forward-only migration using a partial index + keyset pagination backfill > - But the root cause is the absence of author-time guidance: contributors have no documented rules for writing bounded, indexed migration backfills before they land > - This PR adds a migration authoring checklist to `doc/DATABASE.md` so future contributors have those rules at hand before opening a PR > - The benefit is a durable, discoverable guide that prevents the same class of startup-blocking slowness before it reaches production ## Linked Issues or Issue Description This PR is a documentation follow-on to #9108, which landed the fast 0132 migration fix. It adds author-time guidance that captures the root-cause lesson from that incident. No separate public issue exists for the doc addition; the motivation is described above. Refs #9108 ## What Changed - `doc/DATABASE.md`: Added a **Migration authoring checklist** section with rules for indexed, bounded backfill batches — keyset pagination over `LIMIT`/`OFFSET`, mandatory partial index, idempotent guards, and split-phase schema-vs-data changes. The `check:migrations` CI gate is referenced as the enforcement backstop. ## Verification - `git diff --check -- doc/DATABASE.md` passes (no whitespace errors). - No executable code changed; the checklist is an additive documentation section. ## Risks Low. The change is additive text in `doc/DATABASE.md`. No schema, migration, or code changes. No behavioral diff. ## Model Used Claude claude-sonnet-4-6 (Anthropic, 200 K context, tool use) — used to author the migration authoring checklist and coordinate the PR workflow. ## 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> |
||
|
|
41c0b80941 |
docs: record B1/B4/B5 + C1-C10 rulings; name palette classes in DESIGN.md principle 2
DESIGN.md principle 2 now states Tailwind palette classes are hardcoded values in spirit — in-scope debt for a dedicated Run 4, not currently gated — and notes the B1 first-party-decoration allowlist exception. COMPONENT-INVENTORY.md section 6 items get their decided dispositions (C1 split deliberate, C2/C3 Run 3 prep investigations, C4 keep five, C5 Run 3 swap list, C6 dedicated review excluded from Run 3, C7/C8 deliberate custom/intentional exception, C9 deferred to Run 4 with sonner-facade alternative, agentStatusBadge item marked resolved by A1). DECISION-SHEET.md: B1 APPROVED (middle path, executed), B4 DEFERRED to preset session, B5 APPROVED pending contact-sheet review, C1-C10 set. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com> |
||
|
|
98429ed6bc |
refactor(ui): revert demo-only decoration tokens to inline literals (B1 middle path)
DECISION-SHEET.md B1 user ruling: first-party intentional one-off
decoration on demo/UX-lab surfaces stays inline; production decoration
tokens stay tokens. Reverted 27 singleton tokens whose only consumers
are *UxLab.tsx pages — 19 gradients (--gradient-extract-5,6,8-24) and 8
shadows (--shadow-extract-15,16,17,19-23) — restoring the original
bracket-literal utilities (verified byte-exact against pre-extraction
commit
|
||
|
|
5163208c3c |
Add workspace branch ancestry diagnostics (#9117)
## Thinking Path > - Paperclip is the open source app people use to manage AI agents for work > - Agents run in git worktrees tied to a workspace branch; when the actual branch diverges from the expected one (e.g. a parent feature branch was renamed), Paperclip currently has no structured field to report *why* the branch is incoherent or whether it can be auto-reconciled > - The workspace-incoherence fingerprint already captures SHA mismatches, but there is no evidence field distinguishing "actual branch is a descendant of expected" (safe to fast-forward) from "branches have diverged" (needs human review) or "SHAs are unavailable" (unknown) > - Operators and future recovery flows need a typed verdict to make decisions without re-running git commands themselves > - This pull request adds `ancestryVerdict` and `plainLanguageReason` evidence fields computed via `git merge-base --is-ancestor`, and scaffolds the off-by-default `enableWorkspaceBranchReconcileForward` instance setting with no runtime behavior yet > - The benefit is that future recovery logic can branch on a typed verdict rather than parsing prose, while the fingerprint v1 payload stays stable ## Linked Issues or Issue Description No public GitHub issue pre-exists for this diagnostic addition. **Problem or motivation** When Paperclip detects that an agent's actual workspace branch differs from the recorded expected branch, the current fingerprint carries only raw SHAs. There is no typed field indicating whether the actual branch is a descendant of the expected one (safe reconcile path) vs. a true divergence (requires human intervention) vs. an indeterminate state (missing SHAs or git errors). Downstream recovery logic cannot branch safely without re-running git. **Proposed solution** Add `ancestryVerdict` and `plainLanguageReason` to the workspace incoherence evidence type; compute via `git merge-base --is-ancestor`; scaffold a feature-flag for future forward-reconcile behavior (`enableWorkspaceBranchReconcileForward`, off by default, not yet read by any runtime path). **Alternatives considered** Encoding the verdict in the existing fingerprint string was rejected because the fingerprint is a stable identity hash, not a mutable evidence bag. Changing it would break monitors keyed on the string. **Roadmap alignment** Supports future workspace auto-reconcile work; ROADMAP.md has no conflicting entry for this diagnostic layer. ## What Changed - `packages/shared/src/types/heartbeat.ts` adds `ancestryVerdict` and `plainLanguageReason` fields to `WorkspaceIncoherenceEvidence` - `packages/shared/src/types/instance.ts` adds `enableWorkspaceBranchReconcileForward` boolean (off by default) - `packages/shared/src/validators/instance.ts` exports the new flag from the settings validator - `server/src/services/workspace-runtime.ts` computes `ancestryVerdict` via `git merge-base --is-ancestor`; falls back to `unknown` on missing SHAs or command errors; excludes verdict fields from fingerprint v1 computation - `server/src/services/instance-settings.ts` wires the new setting through to the settings service - Tests updated in `workspace-runtime.test.ts`, `instance-settings-service.test.ts`, `instance-settings-routes.test.ts`, and `instance.test.ts` (104 tests total) ## Verification ```bash pnpm exec vitest run \ server/src/__tests__/workspace-runtime.test.ts \ server/src/__tests__/instance-settings-service.test.ts \ server/src/__tests__/instance-settings-routes.test.ts \ packages/shared/src/validators/instance.test.ts # 104 tests pass pnpm --filter @paperclipai/shared typecheck pnpm --filter @paperclipai/server typecheck # both exit 0 ``` Manual: trigger a workspace incoherence event and confirm the evidence object carries `ancestryVerdict` and `plainLanguageReason`; confirm the fingerprint string stays `workspace_incoherence:v1:sha256:...`. ## Risks **Low risk.** Purely additive. Fingerprint v1 payload is unchanged. The new flag has no runtime effect in this PR. `git merge-base --is-ancestor` exits non-zero for both "not an ancestor" and "command error"; both are handled and collapsed to typed values with a prose reason. ## Model Used Provider: Anthropic, model: Claude Sonnet 4.6 (`claude-sonnet-4-6`), 200k context, 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 - [x] I have run tests locally and they pass - [x] I have added or updated tests where applicable - [ ] 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 --------- Co-authored-by: Paperclip <noreply@paperclip.ing> Co-authored-by: Claude Sonnet 4.6 <noreply@anthropic.com> |
||
|
|
47778b233f |
docs: record Run 2 review outcomes in DECISION-SHEET.md (A1-A6, B2, B3)
A1-A6 set to APPROVED with per-item results (A4 = policy only, no code change; A2 consolidated only the provably byte-identical readable-text pair). B2 set to APPROVED — own Run 4 later; B3 set to APPROVED — ladder locked, lands with preset session. Verified on the final tree: check:token-gates 3/3 CLEAN, typecheck green, test:storybook-visual 510/510 vs the Phase 0 baseline at maxDiffPixels 0. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com> |
||
|
|
b76a7955aa |
refactor(ui): decouple chat liveness blue from status token via --liveness-blue (A6)
IssueChatThread's human-message bubble reused --status-task-in_progress (Batch 1; the shared #2563eb is a semantic coincidence, not a real dependency). Mint --liveness-blue: #2563eb in the extracted-tokens block and re-point the bubble class plus the lockstep negative assertion in IssueChatThread.test.tsx, so a future status-hue change no longer drags the chat bubble along. Same value today — zero rendered-output change. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com> |
||
|
|
7929aabeba |
refactor(ui): mint --paperclip-code-highlight-* vars at their fallback values (A5)
FileViewerSheet's code-line highlight referenced --paperclip-code-highlight-bg / --paperclip-code-highlight-border without either var ever being defined, so rendering always came from the var() fallbacks. Define both in the extracted-tokens :root block at exactly the former fallback values (rgba(250,204,21,0.12) / rgb(234,179,8)) and drop the now-redundant fallbacks from the Batch 4 --code-highlight-*-resolved wrappers. Call sites in FileViewerSheet.tsx unchanged. Nothing anywhere sets these vars at runtime (verified via rg), so pixels are identical. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com> |
||
|
|
7e3e59db26 |
refactor(ui): rename project-fallback tokens to --project-seed / --project-none (A3)
Pure rename, values unchanged (#6366f1 / #64748b): the two Batch 1 --hex-* tokens for project-color fallbacks get semantic names. --project-seed = new-project indigo seed default (ProjectDetail, PipelineSettings x2, IssueProperties x2, NewIssueDialog x2); --project-none = no-project-assigned muted slate (Routines x2, MarkdownEditor, RoutineRunVariablesDialog x2, RoutineList, editable-sections x2, ActivityCharts 'backlog'). 16 call sites + the two index.css definitions. Zero rendered-output change. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com> |
||
|
|
383460bb2e |
refactor(ui): consolidate byte-identical readable-text contrast pair (A2)
Of the three flagged contrast-pair sites, only one pair is provably byte-identical across files: #f8fafc/#111827 (readable light/dark text) duplicated in lib/color-contrast.ts and lib/worktree-branding.ts. Export it once from color-contrast.ts as READABLE_TEXT_LIGHT/READABLE_TEXT_DARK and import it in worktree-branding.ts. Left untouched as semantically distinct (per DECISION-SHEET.md A2 'verify per-pair first'): ThemeContext.tsx's <meta theme-color> pair (#18181b/#ffffff — browser chrome color, not contrast math; and #ffffff != #f8fafc), color-contrast.ts's DARK_BG/LIGHT_BG compositing backgrounds (RGB objects), and worktree-branding.ts's #000000 hex-parse fallback. Zero rendered-output change. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com> |
||
|
|
5ecc0f9e47 |
refactor(ui): collapse dead agentStatusBadge duplicate into brandChipBadge (A1)
agentStatusBadge in lib/status-colors.ts was byte-for-byte identical to brandChipBadge for all 4 of its keys (gray/blue/amber/red) and had zero importing call sites — delete the duplicate map, keep brandChipBadge as the single brand .task-chip style source. AgentBadgeColor remains (used by agentStatusColor/agentStatusCapsule) and is a subset of BrandChipColor. Zero rendered-output change. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com> |
||
|
|
c5d73844a5 |
fix(a11y): add tooltips and aria attributes to agent view toggle (#1937)
## Problem On the Agents page, there are two small icon buttons for switching between list view and org chart view. But these buttons had: - No title attribute, so hovering show nothing - No aria-label, so screen readers just say "button" - No aria-pressed, so no way to know which view is active - No role="group" on the container I was confused the first time I see these buttons because one is a list icon and the other is a git-branch icon, and without hovering or clicking I had no idea what they do. Specially the git-branch icon - is it for branches? Repos? No, it's for org chart view. ## What I changed - Added `title` to each button: "List view" and "Org chart view" - Added `aria-label` matching the title for screen readers - Added `aria-pressed` to indicate which view is currently selected - Added `role="group"` with `aria-label="View mode"` on the container div ## How to test 1. Go to Agents page (must have more than 1 agent for toggle to appear) 2. Hover over the list icon - should see "List view" tooltip 3. Hover over the branch icon - should see "Org chart view" tooltip 4. Use screen reader - should announce "List view, pressed" or "Org chart view, not pressed" 1 file, 7 lines added.canary/v2026.706.0-canary.9 |
||
|
|
e0bbf3c911 |
refactor(ui): extract remaining bracket values, add token gate check (Phase 2 batch 4/4)
Final batch of the design-token extraction: mints tokens for every remaining value-bearing arbitrary Tailwind bracket in ui/src/components/** and ui/src/pages/**, then adds a gate script so the "zero hardcoded value" rule is enforced going forward instead of re-audited by hand each time. Codemod: scripts/codemod-extract-misc.mjs (198 sites, 84 files, 96 new tokens: 58 --gtc-*/3 --gtr-* grid track lists, 19 --tp-* transition-property lists, 6 --z-* z-index values, --s-*/--e-*/--va-*/ --sw-* scale/ease/vertical-align/stroke-width, 2 --blur-*, 1 --drop-shadow-extract-*, 4 *-resolved wrapper tokens resolving FileViewerSheet.tsx's half-migrated var(x, fallback) sites Batch 1 deferred, and 2 --gradient-extract-* continuing Batch 1's counter for 2 hsl(var())/color-mix() gradient sites its color-literal audit didn't catch). Mandatory Step 0 syntax spike confirmed every paren form byte-equivalent via scratch stories + built-CSS grep, and confirmed the tw-animate-css plugin utilities (zoom-in-[0.97] etc.) are currently dead/no-op classes (plugin not installed) — allowlisted, not rewritten, since there's no visual behavior to preserve or change. Gate script: scripts/check-token-gates.mjs (new, wired as `pnpm check:token-gates`) implements the three DONE-WHEN gates (hex/color-literal, arbitrary-bracket-value, raw-font-size) over ui/src/components/** and ui/src/pages/**, parsing a new machine-readable ALLOWLIST block appended to ui/src/index.css that consolidates Batches 1-3's free-form allowlist prose into `* allow <path> — <reason>` lines. Resolved TOKEN-AUDIT.md's open "test file policy" question by allowlisting 43 test-fixture hex-literal sites across 18 *.test.tsx files (mock prop/API-response data, not rendered CSS). Gate exits 0 clean. AGENTS.md's existing Design system section now names the gate command. TOKEN-AUDIT.md gets a Batch 4 log appendix with counts, allowlist rationale, and the remaining out-of-scope debt (36 hex sites in ui/src/lib|context|plugins; the ~3,115-site Tailwind-palette-class scope question is still unresolved and flagged for a human decision). Verify: node scripts/check-token-gates.mjs exit 0 (all 3 gates clean); pnpm build-storybook exit 0; Storybook visual suite 510/510 (Playwright, tests/storybook-visual); pnpm typecheck (ui/) exit 0; codemod idempotent on re-run. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com> |
||
|
|
be63424987 |
refactor(ui): extract size/spacing/radius/shadow values to tokens (Phase 2 batch 3/4)
Batch 3/4 of the design-token extraction (design/token-extraction). Replaces hardcoded Tailwind arbitrary-bracket values for width/height/min/max, padding/margin/gap/inset/translate, radius (incl. directional), ring/outline width, and box-shadow in ui/src/components/** and ui/src/pages/** (including *.test.tsx companions) with references to new CSS custom-property tokens in ui/src/index.css. Zero visual change, proven by the Phase 0 Storybook snapshot baseline. Counts: - 407 sites rewritten across 140 files (127 component/page + 13 test files updated in lockstep with the components they assert against). - 163 new tokens minted: 127 --sz-* (one shared family across width/height/spacing/gap/inset/translate lengths, including 42 --sz-calc-N compound calc()/min()/max()/clamp() expressions and 2 --sz-safe-* env(safe-area-inset-*) wrappers), 8 --rad-* (shared across radius/ring-width/outline-width), 5 --pct-* (incl. --pct-neg-50 kept distinct per the source bracket's own negative sign), 23 --shadow-extract-* (38 sites, deduped by exact value). - 11 var()-only passthrough sites (--radix-*-trigger-width/height, --new-issue-dialog-height) rewritten to the bare paren form with no new token minted, per DESIGN.md's runtime-library-variable special case. - 3 sites resolved Tailwind's build-time calc(theme(spacing.N)-Mpx) into a byte-equivalent runtime calc() (components/IssueRow.tsx), verified via headless-browser computed-style comparison against the pre-change built CSS. - 2 sites skipped/allowlisted: rounded-[inherit] (CSS keyword, not a literal) and drop-shadow-[...] (different utility than this batch's shadow-[...] mandate) — logged as a Needs-human-decision item. Three gotchas found and fixed during verification (all documented in the codemod header and TOKEN-AUDIT.md's Batch 3 log): a boundary regex bug that false-positived inside Tailwind's own slide-out-to-top-[1%] compound utility, a calc()-operator-spacing bug that could corrupt env(safe-area-inset-*) identifiers, and a generated-CSS-comment bug where a literal "*/" substring in prose silently dropped the entire token block from the compiled CSS (root cause of an initial 222-test snapshot failure, fully resolved to 510/510 passing). Verify: rg gates clean, pnpm build-storybook exit 0, Storybook visual snapshot suite 510/510 (509 clean + 1 known-benign flaky retry), pnpm typecheck exit 0, codemod re-run confirmed idempotent. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com> |
||
|
|
5cdf5103c9 |
docs(spec): humans/permissions granularity is V1, not OOS (#6744)
## Thinking Path > - `doc/SPEC-implementation.md` §5.2 (Out of Scope V1) conflates two distinct concerns into a single bullet: _"Multi-board governance or role-based human permission granularity"_. > - Role-based human permission granularity has been V1 for a while — the `humans-and-permissions` plan and the `principal_permission_grants` table shipped, the `PERMISSION_KEYS` set covers `users:invite`, `users:manage_permissions`, `tasks:assign`, `tasks:assign_scope`, `tasks:manage_active_checkouts`, `tasks:view_all`, `agents:view_all`, `joins:approve`, `agents:create`, `environments:manage`. > - The remaining OOS item from that bullet is _multi-board governance_ — running multiple board UIs against one company. That's a deployment-topology concern, separate from permission granularity, and stays V1 OOS. > - This PR splits the bullet so the OOS list reflects reality and contributors don't read the SPEC and conclude that per-user permission scoping is unplanned. ## What Changed Single-file docs edit in `doc/SPEC-implementation.md` §5.2: - Drop the conflated "Multi-board governance or role-based human permission granularity" bullet. - Keep "Multi-board governance (multiple board UIs for a single company)" as OOS — that part is still out of scope. - Add a short paragraph below the OOS list pointing readers to the `humans-and-permissions` plan, `principal_permission_grants`, and the existing `tasks:view_all` + `agents:view_all` opt-out scoping primitives so anyone reading §5.2 finds the V1 surface immediately. ## Verification - N/A — docs-only change, no code/schema/test impact. ## Risks - None. Single bullet rewording. ## Model Used Claude (Anthropic). Model ID: `claude-opus-4-7`. ## Checklist - [x] I have included a thinking path that traces from project context to this change - [x] I have specified the model used - [x] I have checked ROADMAP.md and confirmed this PR does not duplicate planned core work — it documents already-shipped V1 work that the SPEC was lagging on - [x] I have run tests locally and they pass — N/A docs-only - [x] I have added or updated tests where applicable — N/A - [x] If this change affects the UI, I have included before/after screenshots — N/A docs-only - [x] I have updated relevant documentation to reflect my changes — this PR IS the doc update - [x] I have considered and documented any risks above - [x] I will address all Greptile and reviewer comments before requesting merge --------- Co-authored-by: Mike <ms@moar.tools> Co-authored-by: Andrew Aymeloglu <aaymeloglu@gmail.com>canary/v2026.706.0-canary.8 |
||
|
|
d2e3f7dce5 |
fix(db): correct 0130 responsible-user backfill in place (inbox resurface) (#9111)
## Thinking Path > - Paperclip is the open source app people use to manage AI agents for work > - Users triage agent work through the issue inbox, which suppresses archived issues by comparing issue `updated_at` against the archive timestamp > - Migration `0130_run_responsible_user_invariant` backfilled responsible-user columns but also set `updated_at = now()` on every row it touched (companies, issues, routines, routine_runs, heartbeat_runs) > - That blanket timestamp bump made every archived issue look newly updated, resurfacing thousands of archived issues into every user's inbox > - This pull request corrects the 0130 backfill in place so it only fills `NULL` responsible-user columns and never touches timestamps, and adds tests that prevent this class of bug from being reintroduced > - The benefit is that inbox archive suppression stays intact across migrations, and no future migration backfill can silently bump `updated_at` on user-visible tables ## Linked Issues or Issue Description **Bug description (no public issue exists):** - **What happened:** after upgrading a dev instance across migration 0130, every previously archived inbox item resurfaced as unread/new for all users. - **Expected:** data backfills must not alter row modification timestamps; archived issues stay archived unless genuinely updated. - **Root cause:** the 0130 backfill's `UPDATE` statements set `updated_at = now()` alongside the responsible-user columns. ## What Changed - `packages/db/src/migrations/0130_run_responsible_user_invariant.sql`: removed all `updated_at = now()` assignments from the backfill UPDATEs; the migration now only fills `NULL` responsible-user columns. The file is corrected **in place** (no new migration number, journal untouched) because 0130 has never shipped in a published release. - `packages/db/src/client.test.ts`: added a guard test that scans every migration and rejects backfills that bump `updated_at` on user-visible tables (with an explicit allowlist for the pre-existing 0131 repair migration). - `packages/db/src/client.test.ts`: added a replay test that simulates an already-migrated database picking up the corrected file (deletes the 0130 ledger hash, re-applies mid-journal) and asserts issue `updated_at` and inbox-archive suppression ordering are untouched. ### Why an in-place edit is safe - 0130 only exists on master/canary builds; the latest published release (v2026.626.0) predates it. - The migration ledger is content-hash based: databases that already applied the old 0130 keep an orphaned hash row (harmless) and see the corrected file as pending, so they replay the corrected backfill — which is idempotent (fills `NULL`s only, no timestamp writes). - Fresh databases simply run the corrected 0130 in journal order. ## Verification - `pnpm --filter @paperclipai/db run check:migrations` — clean - `cd packages/db && npx vitest run src/client.test.ts` — 11/11 passing against embedded Postgres, including the new guard and mid-journal replay tests ## Risks - Migration safety: the corrected backfill is idempotent and only writes `NULL` columns; replay on already-migrated databases is exercised directly by the new test. No schema changes. - Databases that already ran the old 0130 keep the bumped timestamps from that run; repairing historical damage is intentionally out of scope here (no released build ever contained the bug). ## Model Used - Claude Opus 4.7 (`claude-opus-4-7`, extended thinking, tool use) via Claude Code / Paperclip agent runtime ## 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 (backup health alert work split into #9113; no other related open PRs) - [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 (none needed for a migration content fix) - [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>canary/v2026.706.0-canary.7 |
||
|
|
bded6ac5c7 |
[codex] Polish operator issue workflow UI (#9091)
## Thinking Path > - Paperclip is the open source app people use to manage AI agents for work. > - The board UI is where operators create issues, inspect issue-thread decisions, write markdown, and move between issue workflow surfaces. > - A broad recovered branch mixed these operator workflow polish fixes with unrelated backend, pipeline, plugin, eval, and work-product changes. > - Reviewers need the operator UI workflow fixes in a small PR that can be understood without pulling in the rest of that recovery branch. > - This pull request extracts only the issue workflow UI slice: interaction cards, markdown editing fallback behavior, create-issue work mode shortcuts, file-viewer URL handling, and issue navigation scroll behavior. > - The benefit is a lower-risk review path for operator workflow fixes while keeping unrelated execution-workspace and server work out of this PR. ## Linked Issues or Issue Description - Refs #8866, the closed broad source PR that this focused slice was extracted from. - Related: #8228 is an open UI polish PR, but its file list does not overlap this branch. - Related: #4090 is older merged operator workflow polish context. No public GitHub issue exists for this exact extracted slice. The problem is that several small operator issue-workflow fixes were bundled inside a broad recovery branch, making them hard to review and ship independently. ## What Changed - Removed interaction continuation wake-policy labels from issue-thread interaction card headers and updated the card test/story copy accordingly. - Added a markdown editor error boundary so rich editor render crashes fall back to a raw textarea instead of breaking the compose surface. - Made the create-issue work-mode shortcut accept ctrl-period and iOS hardware-keyboard command-period-as-Escape behavior without dismissing the dialog. - Fixed file-viewer URL navigation to compare against the live browser search string when router state is stale. - Restored scroll reset when navigating from an issue detail route back to the issue index, while preserving browser-history restoration behavior. ## Screenshots Before removing the continuation wake-policy badge from interaction card headers:  After removing the wake-policy badge:  ## Verification - `pnpm exec vitest run ui/src/components/IssueThreadInteractionCard.test.tsx ui/src/components/MarkdownEditor.test.tsx ui/src/components/NewIssueDialog.test.tsx ui/src/context/FileViewerContext.test.ts ui/src/lib/navigation-scroll.test.ts` — 5 files, 102 tests passed. - `pnpm --filter @paperclipai/ui typecheck` — passed. - `git diff --check` — passed. ## Risks Low risk. The PR is limited to UI workflow components/helpers and their tests. Main behavioral risks are keyboard shortcut edge cases across browsers and fallback editor rendering, both covered by focused tests. ## Model Used OpenAI Codex, GPT-5-based coding agent (`gpt-5` family; exact served variant and context window are not exposed in this runtime), with terminal, Git, GitHub, and test execution tools. ## 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> |
||
|
|
ef617bee5c |
[codex] Enforce backend execution release gates (#9089)
## Thinking Path > - Paperclip is the open source control plane people use to manage AI agents for work. > - Backend execution safety is part of the control plane contract: agents must stop at budget hard limits, stale execution paths must not create duplicate live work, and checkout ownership must remain authoritative. > - The recovery branch bundled these release-gate checks with broader unrelated work. > - Reviewers need a narrow PR that isolates only the backend safety behavior and regression coverage. > - This pull request keeps budget incident creation idempotent so repeated evaluation does not duplicate release-gate telemetry or approvals. > - It also adds focused coverage for idle timer skips, stale queued-run behavior, and live checkout conflict preservation. > - The benefit is a smaller, reviewable release-gate slice for budget hard stops, stale execution recovery, and ownership-safe issue mutation. ## Linked Issues or Issue Description Refs #8866 This PR extracts a focused backend safety slice from the closed broad recovery PR. The underlying problem is that release-gate behavior needs direct regression coverage before review: budget hard stops should not duplicate incidents/logging on repeated evaluation, timer wakes should respect the no-actionable-work skip policy, stale queued runs should remain invalidated, and active checkout ownership must survive conflicting checkout attempts without side effects. ## What Changed - Made budget incident creation report whether an incident was newly created, so soft/hard threshold activity logs are emitted once per incident window. - Added embedded Postgres budget release-gate tests covering soft incident idempotency, hard-stop pause/cancel behavior, budget override resume behavior, and telemetry redaction. - Added heartbeat coverage for skipping generic timer wakes when the agent opts into `skipTimerWhenNoActionableWork`, while preserving legacy/proactive timer behavior. - Added stale execution lock route coverage proving a conflicting checkout returns `409` without overwriting live checkout or execution ownership and without writing checkout activity. ## Verification - `./node_modules/.bin/vitest run server/src/__tests__/budgets-service.test.ts server/src/__tests__/heartbeat-process-recovery.test.ts server/src/__tests__/heartbeat-stale-queue-invalidation.test.ts server/src/__tests__/issue-stale-execution-lock-routes.test.ts --no-file-parallelism --maxWorkers=1` - First run: 3 files passed, 98 tests passed; `issue-stale-execution-lock-routes.test.ts` failed during import because the isolated worktree initially lacked dev dependency links for `supertest`. - `CI=true NODE_ENV=development pnpm install --frozen-lockfile --ignore-scripts` - Recreated worktree dev dependency links; emitted unrelated plugin SDK bin warnings because plugin SDK dist files were not built under `--ignore-scripts`. - `./node_modules/.bin/vitest run server/src/__tests__/issue-stale-execution-lock-routes.test.ts --no-file-parallelism --maxWorkers=1` - Passed: 1 file, 7 tests. - `git diff --check` - Passed. ## Risks Low to medium risk. The production code change is intentionally small and only suppresses duplicate threshold activity logging for already-open budget incidents, but it affects budget release-gate observability. The new tests use embedded Postgres and should catch regressions in budget hard stops, timer wake gating, stale queue invalidation, and checkout conflict preservation. > 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, GPT-5 coding agent, 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 - [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> |
||
|
|
dfc256a543 |
[codex] Add heartbeat policy eval coverage (#9087)
## Thinking Path > - Paperclip is the open source control plane people use to manage AI agents for work. > - The relevant subsystem is the agent heartbeat policy surface: the Paperclip skill, default onboarding AGENTS.md, new-agent runtime defaults, and promptfoo eval coverage for agent behavior. > - A broad recovery PR collected several unrelated local-mainline changes, which made review too large and mixed policy/eval updates with server execution and UI work. > - This PR extracts only the heartbeat policy and prompt-eval slice so reviewers can assess the behavior contract independently. > - The eval additions cover scoped wake handling, idle no-op behavior, dependency-blocked comment triage, final disposition, budget hard stops, and Phase 5 memory/control-surface policy expectations. > - The benefit is a narrower review surface plus deterministic follow-up guidance for server/shared tests that should back these prompt-level checks. ## Linked Issues or Issue Description Refs #8866 No public issue was filed for this split. This is a focused extraction from the closed broad recovery PR so heartbeat policy and eval coverage can be reviewed separately from execution behavior, work-product feature work, plugin hardening, pipeline health, and unrelated UI polish. ## What Changed - Added promptfoo release-gate cases for scoped wake payload handling, idle exits, dependency-blocked comment triage, final disposition, and budget hard-stop behavior. - Added Phase 5 memory/control-surface prompt eval cases for provider binding precedence, provenance/audit fields, hook cost/trust handling, and auditable board command surfaces. - Documented how these prompt evals map to deterministic server/shared follow-up coverage. - Updated agent policy guidance so operator-facing engineering outputs such as PRs, branches, commits, previews, and runtime services get matching work products. - Defaulted new agent runtime config to skip timer heartbeats when there is no actionable work, with focused test coverage. ## Verification - `cd evals/promptfoo && npx promptfoo@latest validate -c promptfooconfig.yaml` passes. - `/srv/paperclip/home/paperclipai/paperclip/node_modules/.bin/vitest run ui/src/lib/new-agent-runtime-config.test.ts` passes in an isolated worktree after `pnpm install --ignore-scripts --frozen-lockfile` created workspace links. - A live promptfoo eval was not run because `OPENROUTER_API_KEY`, `OPENAI_API_KEY`, and `ANTHROPIC_API_KEY` were unset in the workspace. ## Risks Low-to-medium risk. The runtime default reduces timer-driven empty heartbeats for newly created agents, so the main behavioral risk is missing an edge case where timer wakes were expected despite no actionable work. The promptfoo additions are deterministic assertion coverage and documentation-only until a live eval is run with provider credentials. > 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 GPT-5-based Codex coding agent in the Paperclip local Codex adapter environment; exact hosted model ID and context window were not exposed to the agent runtime. Tool use included shell, git, promptfoo validation, Vitest, and the GitHub connector/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 - [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>canary/v2026.706.0-canary.6 |
||
|
|
4b3f087d7f |
refactor(ui): extract font-size and letter-spacing to tokens (Phase 2 batch 2/4)
Replaces hardcoded TYPE values in ui/src/components/** and ui/src/pages/** with references to new verbatim CSS custom-property tokens in ui/src/index.css, via a new committed codemod (scripts/codemod-extract-type.mjs). - 932 sites rewritten across 143 files: - 728 arbitrary font-size Tailwind classes (text-[Npx]) - 202 arbitrary letter-spacing classes (tracking-[N em]) - 2 inline-style fontSize string literals - 0 leading-[...] sites found (none existed) - 17 new tokens minted, no normalizing: 8 --fs-* (9/10/11/12/13/14/15px + 0.7rem, kept in its own unit) and 9 --ls-* (0.08-0.24em, 9 distinct values) — the micro type-size and letter-spacing clusters TOKEN-AUDIT.md flagged are now materialized as tokens, still un-collapsed pending a human scale decision. - 2 sites allowlisted (both already-documented functional/third-party fontSize forms: CompanyEnvironments.tsx xterm.js config, CompanySkills.tsx computed Math.round() value) — no new allowlist entries needed since neither is a class-string or literal-fontSize site the codemod targets. - Verified: rg gates clean, pnpm build-storybook exit 0, Storybook visual suite 510/510 passed (first attempt), pnpm typecheck exit 0, codemod re-run confirmed idempotent (0 sites on second pass). Co-Authored-By: Claude Fable 5 <noreply@anthropic.com> |
||
|
|
a9399a4d21 |
refactor(ui): extract color literals to tokens (Phase 2 batch 1/4)
Mechanical, codemod-driven extraction of hardcoded hex/rgb/rgba color
literals in ui/src/components/** and ui/src/pages/** (including their
*.test.tsx companions) into CSS custom-property tokens in
ui/src/index.css, per DESIGN.md's Phase 2 extraction contract. Zero
visual change: verified against the Phase 0 Storybook snapshot
baseline.
- 69 sites rewritten across 31 files (Tailwind bracket hex classes,
inline style={{ backgroundColor/color: ... }} literals, and
bg-[gradient(...)] arbitrary values).
- 41 new tokens minted verbatim in a new non-@theme :root block
(17 --hex-*, 24 --gradient-extract-*), 2 existing-token reuses
(--status-task-in_progress, --status-task-done — exact
case-insensitive match, mode-independent, no .dark override).
- 8 files allowlisted with inline `token-extraction: allowlisted`
comments for functional/third-party literals that must stay
hardcoded (xterm.js theme config, <input type="color"> value,
color-picker seed state persisted to a create payload, a
persisted/compared skill.color palette, a contrast-math fallback,
a runtime-computed canvas fillStyle, and a half-migrated
var(--x, fallback) pattern left for a human decision).
- Codemod script (scripts/codemod-extract-colors.mjs) uses a fixed,
hand-audited site table rather than a blind hex regex, since a
naive regex false-positives on strings like "acme/web#241".
- Bug caught by the visual suite and fixed before commit: gradient
token values initially kept Tailwind's bracket-arbitrary-value
underscore-for-space escaping (e.g. circle_at_top), which is
invalid inside a real CSS custom property; converted back to
literal spaces.
Verify: rg gate clean outside the allowlist; pnpm build-storybook
exit 0; Storybook visual snapshot suite 510/510 passed; pnpm
typecheck exit 0.
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
|
||
|
|
38532283e9 |
docs: Phase 1 audit — TOKEN-AUDIT.md + COMPONENT-INVENTORY.md
Read-only audit of ui/src (token-auditor): - TOKEN-AUDIT.md: every hardcoded color/spacing/radius/type/shadow value, frequencies, locations, near-duplicate clusters, exact-match cross-ref against ui/src/index.css tokens (only 6 exact hex matches, all in lib/status-colors.ts — confirms PRIOR-ART), DESIGN.md conflicts (radius lg/xl pinned to 0px making the scale non-monotonic; no shadow tokens exist), and a Needs-human-decision list (incl. the 3,115 Tailwind palette-class sites scope question). - COMPONENT-INVENTORY.md: 24 primitives (in sync with shadcn registry), 206 feature components, 73 pages, verified duplicate leads, shadcn candidates — all consolidation/swap items recommendations-only. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com> |
||
|
|
1448946b7f |
test: Phase 0 visual snapshot baseline (510 screenshots)
Baseline for the zero-visual-change token extraction: every Storybook story (255) in dark and light themes, captured BEFORE any component change. All 510 pass against this baseline (verified same-build). Co-Authored-By: Claude Fable 5 <noreply@anthropic.com> |
||
|
|
b0a5872ec6 |
test: Storybook visual snapshot suite (Phase 0 tooling)
Playwright-based screenshot suite over the built Storybook: one test per story per theme (dark/light), byte-identical comparison (maxDiffPixels 0), Date frozen via init-script shim (page.clock broke React rendering in several stories), animations disabled, per-story settle map for delayed state flips and a mask for one bimodal ::highlight race. Run with pnpm test:storybook-visual (or :update to re-baseline). No new dependencies: reuses the repo's @playwright/test and a dependency-free static server script. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com> |
||
|
|
29dadead61 |
storybook: primitive coverage stories + deterministic-render fixes
- Add minimal static stories for the 10 ui/ primitives no existing story rendered (alert-dialog, avatar, breadcrumb, collapsible, command, dropdown-menu, radio-card, scroll-area, sheet, skeleton) so the visual snapshot baseline covers every shared primitive. - user-secrets: drop the story-level nested MemoryRouter (preview already provides one; nesting intermittently threw 'Router inside another Router'). - navigation-layout: provide PluginLauncherProvider at the meta level; BoardChromeMatrix mounts the real Sidebar whose PluginLauncherOutlet raced company selection and intermittently threw. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com> |
||
|
|
1aea0c8a7e |
Condense /goal paste block under the 4000-char limit (v3)
/goal rejected the v2 block at 4,648 chars. Block now carries mission + DONE-WHEN + guardrails; full phase spec moved to a section the run reads from disk. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com> |
||
|
|
0b09f72bdf |
Add design-simplification anchor docs and subagents
DESIGN.md v0.3 (token source = ui/src/index.css, scoped Run 1 gates),
GOAL-PROMPT.md v2 (phases 0-2 only, consolidation/rename split out),
PRIOR-ART.md (PAP-280 audit findings), KNOWN-DUPLICATES.md seed,
.claude/agents/{token-auditor,codemod-runner}.md, AGENTS.md link.
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
|
||
|
|
903886bc79 |
[codex] Add starred resource sidebar controls (#9085)
## Thinking Path > - Paperclip is the open source app people use to manage AI agents for work. > - The board UI is the main daily navigation surface for agents, projects, and their related resources. > - Operators need a lightweight way to keep frequently used agents and projects close without changing company-wide ordering or ownership. > - Resource memberships already model per-user relationships to projects and agents, so they are the right place to store user-specific starred state. > - This pull request extends that membership contract with a starred timestamp and exposes star controls in list/detail views. > - The sidebar then uses those starred memberships to show compact, user-specific shortcuts. > - The benefit is faster navigation without introducing a separate favorites system or leaking preferences across users. ## Linked Issues or Issue Description No public GitHub issue exists. Feature request: ## Problem or motivation Users cannot pin frequently used agents or projects into the main sidebar. Returning to important resources requires scanning full project/agent lists or navigating through detail pages, which adds friction to repeated daily workflows. ## Proposed solution Store a per-user `starred_at` timestamp on agent and project memberships, expose API actions to set or clear that state, add star toggle controls to list/detail pages, and render starred projects and agents as compact sidebar shortcuts. ## Alternatives considered A separate favorites table would work, but it would duplicate membership scoping and require another resource relationship model. Keeping starred state on memberships preserves existing company/user boundaries and avoids a second source of truth. ## Roadmap alignment Checked `ROADMAP.md`; no overlapping planned core work for starred resource/sidebar navigation was found. ## Additional context The affected subsystems are `packages/db`, `packages/shared`, `server/`, and `ui/`. The migration is idempotent with `IF NOT EXISTS` guards so environments that saw an earlier local migration name can still apply the final ordered migration safely. ## What Changed - Added idempotent migration `0133_resource_membership_stars` for `starred_at` columns and lookup indexes on agent/project memberships. - Extended shared resource membership types and validators with starred metadata and actions. - Updated server resource membership services/routes to read and mutate starred resource state. - Added reusable star toggle UI and resource membership hook support for starred state. - Added starred projects and agents sidebar rendering, plus star controls on list and detail pages. - Added focused shared, server, and UI coverage for starred membership behavior and sidebar rendering. ## Verification - Rebased and force-with-lease pushed current PR head `a086fc965391c9e50a51b5b83b5b44a797b2a6f4` onto current `paperclipai/paperclip:master`; `gh pr view` reports `MERGEABLE` with no merge conflicts. GitHub checks are green for this fresh head. - `pnpm exec vitest run packages/shared/src/resource-memberships.test.ts server/src/__tests__/resource-memberships-routes.test.ts server/src/__tests__/workspace-runtime.test.ts ui/src/components/Sidebar.test.tsx ui/src/components/SidebarAgents.test.tsx ui/src/components/SidebarStarredProjects.test.tsx ui/src/components/StarToggle.test.tsx ui/src/pages/InstanceExperimentalSettings.test.tsx` passed after the rebase: 8 files, 143 tests. - Greptile re-review is 5/5; the remaining screenshot thread was resolved as non-blocking because this task explicitly requested no screenshots/images in the PR. - `pnpm exec vitest run ui/src/components/SidebarStarredProjects.test.tsx` passed after the mobile pending-spinner fix. - `pnpm exec vitest run packages/shared/src/resource-memberships.test.ts server/src/__tests__/resource-memberships-routes.test.ts ui/src/components/Sidebar.test.tsx ui/src/components/SidebarAgents.test.tsx ui/src/components/SidebarStarredProjects.test.tsx ui/src/components/StarToggle.test.tsx ui/src/pages/InstanceExperimentalSettings.test.tsx` passed: 7 files, 68 tests. - `pnpm --filter @paperclipai/db typecheck && pnpm --filter @paperclipai/shared typecheck && pnpm --filter @paperclipai/server typecheck && pnpm --filter @paperclipai/ui typecheck` passed db/shared/server, then failed in pre-existing UI code outside this PR: `src/pages/CompanyEnvironments.tsx` missing `@xterm/*` type declarations and `previous` possibly null. - Checked that the PR diff does not include `pnpm-lock.yaml` or `.github/workflows` changes. - Checked `ROADMAP.md` and found no overlapping planned core work for starred resource/sidebar navigation. - Searched existing GitHub PRs for duplicate starred-resource/sidebar work and found none. ## Risks - Migration touches membership tables. The SQL uses `IF NOT EXISTS` for columns and indexes so environments that saw an earlier local migration name can still apply this safely. - Sidebar ordering and visibility changes could affect users who rely on the previous flat sidebar layout. - Starred state is per-user membership metadata; code paths must continue preserving company/user scoping around memberships. > 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 GPT-5 Codex, tool-enabled coding agent with shell/GitHub access. Context window not disclosed by the runtime. ## 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> |
||
|
|
70c86d2c73 |
fix(hermes): strip ANSI escape codes from terminal output in UI parsers (#8731)
## Thinking Path
> - Paperclip is the open source app people use to manage AI agents for
work
> - Hermes adapter produces terminal output with ANSI color codes on
stdout
> - These escape sequences flow through the UI parsers untouched and
render as raw garbage text
> - This PR adds ANSI stripping at the entry point of all four Hermes
parse-stdout entry points
> - The same regex is already proven in claude-local adapter
> - The benefit is clean, readable terminal output for Hermes agents
## Linked Issues or Issue Description
No existing issue. This is a bug report:
**What happened**
Hermes terminal output displayed ANSI color codes as raw text in the
Paperclip UI, making agent output unreadable.
**Expected behavior**
Terminal output in run transcripts should be clean text without
invisible control characters.
**Steps to reproduce**
1. Connect a Hermes agent to Paperclip
2. Create and assign a task to the agent
3. View the run transcript — ANSI escape codes appear as raw garbage
**Paperclip version or commit**
|
||
|
|
c5e03c6d01 |
fix(db): relocate slow 0126 issue-comment attribution backfill to fast idempotent 0132 (#9108)
## Thinking Path > - Paperclip is the open source app people use to manage AI agents for work > - The database layer runs migrations during server startup via `server.listen`; migrations that block this path delay instance availability > - Migration `0126_issue_comment_derived_attribution.sql` backfills derived attribution columns on `issue_comments` using a LIMIT-5000 loop with no index or keyset cursor — it re-scans the full table from the start each batch, giving O(n²) complexity > - On instances with millions of issue comments this blocked `server.listen` for ~5 minutes during upgrade, causing CPU pegs and unavailability > - Editing 0126 in place is unsafe: the migration runner keys its applied-set on file **content hash**, so any edit changes the hash, causing the runner to re-apply the migration on already-migrated databases and blocking startup > - The safe remedy is delete-and-relocate: remove 0126 and add a new forward migration 0132 that uses a temporary partial index + keyset pagination (`id > last_comment_id ORDER BY id LIMIT 5000`) so every row is visited exactly once — O(n) > - This pull request implements that delete-and-relocate with idempotency guards (IF NOT EXISTS DDL, backfill WHERE clause that skips already-attributed rows) so it is a safe near-noop on already-migrated, partially-migrated, and fresh databases alike ## Linked Issues or Issue Description No pre-existing public GitHub issue. Inline bug report: **What happened?** The `0126_issue_comment_derived_attribution` migration runs during server startup and uses a LIMIT-5000 batch loop that re-scans `issue_comments` from row 1 each iteration (no index, no keyset cursor). The result is O(n²) I/O that blocked `server.listen` on large instances. **Expected behavior** Backfill migrations should advance with a keyset cursor so each batch reads a new slice; total work is O(n) and startup is not blocked. **Steps to reproduce** Run a Paperclip upgrade on an instance with ≥200k issue comments; observe `server.listen` blocked for several minutes and CPU peg during migration. **Paperclip version or commit** Reproduced on the current `master` branch prior to this fix. **Deployment mode** All deployment modes that run the migration runner at startup. ## What Changed - **Deleted** `packages/db/src/migrations/0126_issue_comment_derived_attribution.sql` — the O(n²) LIMIT-5000 loop with no index/cursor - **Added** `packages/db/src/migrations/0132_issue_comment_derived_attribution_fast.sql`: - Creates a temporary partial index over the eligible predicate before backfilling - Uses keyset pagination (`id > last_comment_id ORDER BY id LIMIT 5000`) — each batch advances to the batch-max id, so every row is visited once - Drops the temporary index at the end - Columns/FKs guarded with `IF NOT EXISTS`; Option-A timing-tier cleanup preserved; human-authored comments never touched - `WHERE` clause in the backfill excludes rows already attributed (safe near-noop on already-migrated DBs) - **Updated** `packages/db/src/migrations/meta/_journal.json` — dropped 0126 entry, appended 0132 - **Added** `packages/db/src/issue-comment-derived-attribution-migration.test.ts` (345 lines) — covers fresh-install, already-0126-migrated idempotency, and partial-backfill completion scenarios using embedded Postgres ## Verification ```bash # Migration numbering guard pnpm --filter @paperclipai/db check:migrations # Migration tests (embedded Postgres, 3 scenarios) pnpm --filter @paperclipai/db vitest run issue-comment-derived-attribution-migration.test.ts ``` Both pass locally. CI results will appear on this PR. ## Risks **Migration safety — already-migrated databases:** Deleting 0126 leaves an orphan row in the runner's applied-set. The runner only checks the set for "has this been applied" — orphan rows are never re-applied. 0132 runs as a near-noop: IF NOT EXISTS DDL is skipped, and the backfill WHERE clause excludes rows that already have attribution. **Migration safety — partially-migrated databases:** Keyset pagination is idempotent. 0132 picks up from the highest attributed row id, so a partial prior run is completed correctly. **No data loss:** The migration never deletes or overwrites user-authored content. It only writes to derived attribution columns on rows where attribution is absent. **Rollback:** 0132 is a forward-only migration. If a rollback is needed, the attribution columns remain (no harm) and can be ignored or cleaned up in a subsequent migration. ## Model Used Claude Sonnet 4.6 (`claude-sonnet-4-6`) via the Paperclip AI agent harness, with tool use and extended context enabled. Implementation authored by Priya Raman; PR opened via the Paperclip Git Expert agent. ## 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) - [ ] My branch name describes the change (e.g. `docs/...`, `fix/...`) and contains no internal Paperclip ticket id or instance-derived details _(branch is the preserved implementation branch from the authoring engineer; the internal task id is present in the branch name by workflow convention — not a content risk)_ - [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 — CI running)_ - [ ] Greptile is 5/5 with no open P2s, recommendations, or follow-ups _(pending — will be driven to terminal-green before merge)_ - [ ] I will address all Greptile and reviewer comments before requesting merge _(pending — will action all findings)_ Co-authored-by: Paperclip <noreply@paperclip.ing>canary/v2026.706.0-canary.5 |
||
|
|
1e81bd188b |
Fix heartbeat run responsible user migration for identifier refs (#9107)
## Thinking Path
> - Paperclip is the open source app people use to manage AI agents for
work
> - Paperclip stores heartbeat run ownership context so operators can
audit which user was responsible for agent work
> - A migration backfills missing heartbeat run `responsible_user_id`
values from issue references in each run's context snapshot
> - Some context snapshots can store issue identifiers as public ticket
strings rather than UUIDs
> - The migration needs to resolve both UUID issue ids and issue
identifiers without trying to cast identifier strings to UUID
> - This pull request tightens the migration query so UUID matching only
casts validated UUID-shaped values and identifier matching remains a
separate fallback
> - A companion repair migration is needed so installations that already
recorded `0130` still get the corrected heartbeat-run backfill
> - The benefit is that existing installations can apply the
responsible-user invariant migrations without failing on non-UUID issue
references and without leaving already-migrated databases unrepaired
## Linked Issues or Issue Description
No public GitHub issue was found in a quick search for this migration
failure.
Bug report context following `.github/ISSUE_TEMPLATE/bug_report.yml`:
**Pre-submission checklist**
- I searched existing open and closed issues and did not find a
duplicate.
- I can reproduce against current `master` plus the responsible-user
invariant migration path.
- The error originates in Paperclip's database migration, not in an
adapter, API provider, or local configuration.
**What happened?**
Applying the heartbeat run responsible-user backfill migration could
fail when `heartbeat_runs.context_snapshot->>'issueId'` or `taskId`
contained an issue identifier such as `PAP-123` instead of a UUID. The
migration attempted to use issue refs for UUID matching and identifier
fallback, but the UUID path needed to avoid casting non-UUID identifier
strings. Because `0130` may already have been applied in some
installations, a follow-up repair migration is needed as well.
**Expected behavior**
The migration should backfill from UUID issue ids when present, from
issue identifiers when present, and fall back to the company default
responsible user without unsafe UUID casts. Already-migrated
installations should receive the repaired heartbeat-run context-ref
backfill through a new migration.
**Steps to reproduce**
1. Use a migrated database with a company, issue, agent, and heartbeat
run.
2. Store a null `heartbeat_runs.responsible_user_id` and a
`context_snapshot` like `{"issueId":"PAP-123"}`.
3. Replay/apply the run responsible-user repair migration.
4. Observe that the migration must not cast `PAP-123` to UUID and should
backfill from the matching issue identifier.
**Paperclip version or commit**
Current `master` plus this migration fix branch.
**Deployment mode**
Database migration during server startup or explicit migration command.
**Installation method**
Built from source / self-hosted migration path.
**Agent adapter(s) involved**
Not adapter-specific; core database migration bug.
**Database mode**
Postgres migration path, including embedded Postgres in development.
**Access context**
Not applicable; migration-time data backfill.
**Relevant logs or output**
Unsafe UUID casts can surface as Postgres invalid input syntax errors
when a context snapshot issue ref is an identifier rather than a UUID.
**Privacy checklist**
No private logs, paths, API keys, tokens, company names, or internal
Paperclip issue links are included.
## What Changed
- Split heartbeat run context issue reference extraction into reusable
CTEs.
- Only cast `issueId` / `taskId` values to UUID after a UUID-shape regex
check.
- Preserve fallback matching by issue identifier within the same
company.
- Keep deterministic candidate priority with `issueId` before `taskId`
and UUID matches before identifier matches.
- Added `0131_repair_run_responsible_user_context_refs.sql` so
installations that already applied `0130` still receive the corrected
heartbeat-run backfill.
- Added a DB migration regression test that replays the repair migration
with an identifier-style heartbeat run issue ref.
## Verification
- `pnpm --filter @paperclipai/db typecheck`
- `pnpm --filter @paperclipai/db exec vitest run src/client.test.ts`
- Isolated embedded Postgres migration run with a temporary
`PAPERCLIP_CONFIG`: `pnpm --filter @paperclipai/db migrate` applied all
pending migrations successfully.
- GitHub Actions PR workflow is green on commit
`1c2655bc457cef3716a43e66463e1e5bc2fdcfab`.
- Greptile is 5/5 with no unresolved threads on commit
`1c2655bc457cef3716a43e66463e1e5bc2fdcfab`.
- Searched for duplicate public issues/PRs with GitHub search; no direct
duplicate found.
- Checked `ROADMAP.md` for overlap; no related roadmap item found.
## Risks
- Low-to-medium migration risk because this modifies an existing data
backfill migration and adds a companion repair migration.
- The query still relies on `context_snapshot` containing either issue
UUIDs or identifiers that match issues in the same company.
- Installations with unusual malformed context snapshots now skip unsafe
UUID casts and fall through to identifier/default backfill behavior.
> 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 GPT-5 Codex coding agent with tool use and local command
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, or
confirmed no docs update is needed for this migration-only fix
- [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>
canary/v2026.706.0-canary.4
|