2026-03-17 09:24:28 -05:00
|
|
|
import express from "express";
|
|
|
|
|
import request from "supertest";
|
|
|
|
|
import { beforeEach, describe, expect, it, vi } from "vitest";
|
|
|
|
|
|
|
|
|
|
const mockInstanceSettingsService = vi.hoisted(() => ({
|
2026-03-20 08:00:39 -05:00
|
|
|
getGeneral: vi.fn(),
|
2026-03-17 09:24:28 -05:00
|
|
|
getExperimental: vi.fn(),
|
2026-03-20 08:00:39 -05:00
|
|
|
updateGeneral: vi.fn(),
|
2026-03-17 09:24:28 -05:00
|
|
|
updateExperimental: vi.fn(),
|
|
|
|
|
listCompanyIds: vi.fn(),
|
|
|
|
|
}));
|
|
|
|
|
const mockLogActivity = vi.hoisted(() => vi.fn());
|
|
|
|
|
|
2026-04-10 22:26:21 -05:00
|
|
|
vi.mock("../services/index.js", () => ({
|
|
|
|
|
instanceSettingsService: () => mockInstanceSettingsService,
|
|
|
|
|
logActivity: mockLogActivity,
|
|
|
|
|
}));
|
2026-03-17 09:24:28 -05:00
|
|
|
|
[codex] Harden execution reliability and heartbeat tooling (#3679)
## Thinking Path
> - Paperclip orchestrates AI agents for zero-human companies
> - Reliable execution depends on heartbeat routing, issue lifecycle
semantics, telemetry, and a fast enough local verification loop to keep
regressions visible
> - The remaining commits on this branch were mostly server/runtime
correctness fixes plus test and documentation follow-ups in that area
> - Those changes are logically separate from the UI-focused
issue-detail and workspace/navigation branches even when they touch
overlapping issue APIs
> - This pull request groups the execution reliability, heartbeat,
telemetry, and tooling changes into one standalone branch
> - The benefit is a focused review of the control-plane correctness
work, including the follow-up fix that restored the implicit
comment-reopen helpers after branch splitting
## What Changed
- Hardened issue/heartbeat execution behavior, including self-review
stage skipping, deferred mention wakes during active execution, stranded
execution recovery, active-run scoping, assignee resolution, and
blocked-to-todo wake resumption
- Reduced noisy polling/logging overhead by trimming issue run payloads,
compacting persisted run logs, silencing high-volume request logs, and
capping heartbeat-run queries in dashboard/inbox surfaces
- Expanded telemetry and status semantics with adapter/model fields on
task completion plus clearer status guidance in docs/onboarding material
- Updated test infrastructure and verification defaults with faster
route-test module isolation, cheaper default `pnpm test`, e2e isolation
from local state, and repo verification follow-ups
- Included docs/release housekeeping from the branch and added a small
follow-up commit restoring the implicit comment-reopen helpers that were
dropped during branch reconstruction
## Verification
- `pnpm vitest run
server/src/__tests__/issue-comment-reopen-routes.test.ts
server/src/__tests__/issue-telemetry-routes.test.ts`
- `pnpm vitest run server/src/__tests__/http-log-policy.test.ts
server/src/__tests__/heartbeat-run-log.test.ts
server/src/__tests__/health.test.ts`
- `server/src/__tests__/activity-service.test.ts`,
`server/src/__tests__/heartbeat-comment-wake-batching.test.ts`, and
`server/src/__tests__/heartbeat-process-recovery.test.ts` were attempted
on this host but the embedded Postgres harness reported
init-script/data-dir problems and skipped or failed to start, so they
are noted as environment-limited
## Risks
- Medium: this branch changes core issue/heartbeat routing and
reopen/wakeup behavior, so regressions would affect agent execution flow
rather than isolated UI polish
- Because it also updates verification infrastructure, reviewers should
pay attention to whether the new tests are asserting the right failure
modes and not just reshaping harness behavior
## Model Used
- OpenAI Codex coding agent (GPT-5-class runtime in Codex CLI; exact
deployed model ID is not exposed in this environment), reasoning
enabled, tool use and local code execution 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)
- [ ] I have run tests locally and they pass
- [x] I have added or updated tests where applicable
- [ ] If this change affects the UI, I have included before/after
screenshots
- [x] I have updated relevant documentation to reflect my changes
- [x] I have considered and documented any risks above
- [x] I will address all Greptile and reviewer comments before
requesting merge
---------
Co-authored-by: Paperclip <noreply@paperclip.ing>
2026-04-14 13:34:52 -05:00
|
|
|
function registerModuleMocks() {
|
|
|
|
|
vi.doMock("../services/index.js", () => ({
|
|
|
|
|
instanceSettingsService: () => mockInstanceSettingsService,
|
|
|
|
|
logActivity: mockLogActivity,
|
|
|
|
|
}));
|
|
|
|
|
}
|
|
|
|
|
|
2026-04-09 06:12:39 -05:00
|
|
|
async function createApp(actor: any) {
|
[codex] Harden execution reliability and heartbeat tooling (#3679)
## Thinking Path
> - Paperclip orchestrates AI agents for zero-human companies
> - Reliable execution depends on heartbeat routing, issue lifecycle
semantics, telemetry, and a fast enough local verification loop to keep
regressions visible
> - The remaining commits on this branch were mostly server/runtime
correctness fixes plus test and documentation follow-ups in that area
> - Those changes are logically separate from the UI-focused
issue-detail and workspace/navigation branches even when they touch
overlapping issue APIs
> - This pull request groups the execution reliability, heartbeat,
telemetry, and tooling changes into one standalone branch
> - The benefit is a focused review of the control-plane correctness
work, including the follow-up fix that restored the implicit
comment-reopen helpers after branch splitting
## What Changed
- Hardened issue/heartbeat execution behavior, including self-review
stage skipping, deferred mention wakes during active execution, stranded
execution recovery, active-run scoping, assignee resolution, and
blocked-to-todo wake resumption
- Reduced noisy polling/logging overhead by trimming issue run payloads,
compacting persisted run logs, silencing high-volume request logs, and
capping heartbeat-run queries in dashboard/inbox surfaces
- Expanded telemetry and status semantics with adapter/model fields on
task completion plus clearer status guidance in docs/onboarding material
- Updated test infrastructure and verification defaults with faster
route-test module isolation, cheaper default `pnpm test`, e2e isolation
from local state, and repo verification follow-ups
- Included docs/release housekeeping from the branch and added a small
follow-up commit restoring the implicit comment-reopen helpers that were
dropped during branch reconstruction
## Verification
- `pnpm vitest run
server/src/__tests__/issue-comment-reopen-routes.test.ts
server/src/__tests__/issue-telemetry-routes.test.ts`
- `pnpm vitest run server/src/__tests__/http-log-policy.test.ts
server/src/__tests__/heartbeat-run-log.test.ts
server/src/__tests__/health.test.ts`
- `server/src/__tests__/activity-service.test.ts`,
`server/src/__tests__/heartbeat-comment-wake-batching.test.ts`, and
`server/src/__tests__/heartbeat-process-recovery.test.ts` were attempted
on this host but the embedded Postgres harness reported
init-script/data-dir problems and skipped or failed to start, so they
are noted as environment-limited
## Risks
- Medium: this branch changes core issue/heartbeat routing and
reopen/wakeup behavior, so regressions would affect agent execution flow
rather than isolated UI polish
- Because it also updates verification infrastructure, reviewers should
pay attention to whether the new tests are asserting the right failure
modes and not just reshaping harness behavior
## Model Used
- OpenAI Codex coding agent (GPT-5-class runtime in Codex CLI; exact
deployed model ID is not exposed in this environment), reasoning
enabled, tool use and local code execution 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)
- [ ] I have run tests locally and they pass
- [x] I have added or updated tests where applicable
- [ ] If this change affects the UI, I have included before/after
screenshots
- [x] I have updated relevant documentation to reflect my changes
- [x] I have considered and documented any risks above
- [x] I will address all Greptile and reviewer comments before
requesting merge
---------
Co-authored-by: Paperclip <noreply@paperclip.ing>
2026-04-14 13:34:52 -05:00
|
|
|
const [{ errorHandler }, { instanceSettingsRoutes }] = await Promise.all([
|
|
|
|
|
vi.importActual<typeof import("../middleware/index.js")>("../middleware/index.js"),
|
|
|
|
|
vi.importActual<typeof import("../routes/instance-settings.js")>("../routes/instance-settings.js"),
|
2026-04-09 06:12:39 -05:00
|
|
|
]);
|
2026-03-17 09:24:28 -05:00
|
|
|
const app = express();
|
|
|
|
|
app.use(express.json());
|
|
|
|
|
app.use((req, _res, next) => {
|
|
|
|
|
req.actor = actor;
|
|
|
|
|
next();
|
|
|
|
|
});
|
|
|
|
|
app.use("/api", instanceSettingsRoutes({} as any));
|
|
|
|
|
app.use(errorHandler);
|
|
|
|
|
return app;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
describe("instance settings routes", () => {
|
|
|
|
|
beforeEach(() => {
|
2026-04-09 06:12:39 -05:00
|
|
|
vi.resetModules();
|
[codex] Harden execution reliability and heartbeat tooling (#3679)
## Thinking Path
> - Paperclip orchestrates AI agents for zero-human companies
> - Reliable execution depends on heartbeat routing, issue lifecycle
semantics, telemetry, and a fast enough local verification loop to keep
regressions visible
> - The remaining commits on this branch were mostly server/runtime
correctness fixes plus test and documentation follow-ups in that area
> - Those changes are logically separate from the UI-focused
issue-detail and workspace/navigation branches even when they touch
overlapping issue APIs
> - This pull request groups the execution reliability, heartbeat,
telemetry, and tooling changes into one standalone branch
> - The benefit is a focused review of the control-plane correctness
work, including the follow-up fix that restored the implicit
comment-reopen helpers after branch splitting
## What Changed
- Hardened issue/heartbeat execution behavior, including self-review
stage skipping, deferred mention wakes during active execution, stranded
execution recovery, active-run scoping, assignee resolution, and
blocked-to-todo wake resumption
- Reduced noisy polling/logging overhead by trimming issue run payloads,
compacting persisted run logs, silencing high-volume request logs, and
capping heartbeat-run queries in dashboard/inbox surfaces
- Expanded telemetry and status semantics with adapter/model fields on
task completion plus clearer status guidance in docs/onboarding material
- Updated test infrastructure and verification defaults with faster
route-test module isolation, cheaper default `pnpm test`, e2e isolation
from local state, and repo verification follow-ups
- Included docs/release housekeeping from the branch and added a small
follow-up commit restoring the implicit comment-reopen helpers that were
dropped during branch reconstruction
## Verification
- `pnpm vitest run
server/src/__tests__/issue-comment-reopen-routes.test.ts
server/src/__tests__/issue-telemetry-routes.test.ts`
- `pnpm vitest run server/src/__tests__/http-log-policy.test.ts
server/src/__tests__/heartbeat-run-log.test.ts
server/src/__tests__/health.test.ts`
- `server/src/__tests__/activity-service.test.ts`,
`server/src/__tests__/heartbeat-comment-wake-batching.test.ts`, and
`server/src/__tests__/heartbeat-process-recovery.test.ts` were attempted
on this host but the embedded Postgres harness reported
init-script/data-dir problems and skipped or failed to start, so they
are noted as environment-limited
## Risks
- Medium: this branch changes core issue/heartbeat routing and
reopen/wakeup behavior, so regressions would affect agent execution flow
rather than isolated UI polish
- Because it also updates verification infrastructure, reviewers should
pay attention to whether the new tests are asserting the right failure
modes and not just reshaping harness behavior
## Model Used
- OpenAI Codex coding agent (GPT-5-class runtime in Codex CLI; exact
deployed model ID is not exposed in this environment), reasoning
enabled, tool use and local code execution 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)
- [ ] I have run tests locally and they pass
- [x] I have added or updated tests where applicable
- [ ] If this change affects the UI, I have included before/after
screenshots
- [x] I have updated relevant documentation to reflect my changes
- [x] I have considered and documented any risks above
- [x] I will address all Greptile and reviewer comments before
requesting merge
---------
Co-authored-by: Paperclip <noreply@paperclip.ing>
2026-04-14 13:34:52 -05:00
|
|
|
vi.doUnmock("../routes/instance-settings.js");
|
|
|
|
|
vi.doUnmock("../routes/authz.js");
|
|
|
|
|
vi.doUnmock("../middleware/index.js");
|
|
|
|
|
registerModuleMocks();
|
2026-04-10 22:26:21 -05:00
|
|
|
vi.resetAllMocks();
|
[codex] Harden execution reliability and heartbeat tooling (#3679)
## Thinking Path
> - Paperclip orchestrates AI agents for zero-human companies
> - Reliable execution depends on heartbeat routing, issue lifecycle
semantics, telemetry, and a fast enough local verification loop to keep
regressions visible
> - The remaining commits on this branch were mostly server/runtime
correctness fixes plus test and documentation follow-ups in that area
> - Those changes are logically separate from the UI-focused
issue-detail and workspace/navigation branches even when they touch
overlapping issue APIs
> - This pull request groups the execution reliability, heartbeat,
telemetry, and tooling changes into one standalone branch
> - The benefit is a focused review of the control-plane correctness
work, including the follow-up fix that restored the implicit
comment-reopen helpers after branch splitting
## What Changed
- Hardened issue/heartbeat execution behavior, including self-review
stage skipping, deferred mention wakes during active execution, stranded
execution recovery, active-run scoping, assignee resolution, and
blocked-to-todo wake resumption
- Reduced noisy polling/logging overhead by trimming issue run payloads,
compacting persisted run logs, silencing high-volume request logs, and
capping heartbeat-run queries in dashboard/inbox surfaces
- Expanded telemetry and status semantics with adapter/model fields on
task completion plus clearer status guidance in docs/onboarding material
- Updated test infrastructure and verification defaults with faster
route-test module isolation, cheaper default `pnpm test`, e2e isolation
from local state, and repo verification follow-ups
- Included docs/release housekeeping from the branch and added a small
follow-up commit restoring the implicit comment-reopen helpers that were
dropped during branch reconstruction
## Verification
- `pnpm vitest run
server/src/__tests__/issue-comment-reopen-routes.test.ts
server/src/__tests__/issue-telemetry-routes.test.ts`
- `pnpm vitest run server/src/__tests__/http-log-policy.test.ts
server/src/__tests__/heartbeat-run-log.test.ts
server/src/__tests__/health.test.ts`
- `server/src/__tests__/activity-service.test.ts`,
`server/src/__tests__/heartbeat-comment-wake-batching.test.ts`, and
`server/src/__tests__/heartbeat-process-recovery.test.ts` were attempted
on this host but the embedded Postgres harness reported
init-script/data-dir problems and skipped or failed to start, so they
are noted as environment-limited
## Risks
- Medium: this branch changes core issue/heartbeat routing and
reopen/wakeup behavior, so regressions would affect agent execution flow
rather than isolated UI polish
- Because it also updates verification infrastructure, reviewers should
pay attention to whether the new tests are asserting the right failure
modes and not just reshaping harness behavior
## Model Used
- OpenAI Codex coding agent (GPT-5-class runtime in Codex CLI; exact
deployed model ID is not exposed in this environment), reasoning
enabled, tool use and local code execution 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)
- [ ] I have run tests locally and they pass
- [x] I have added or updated tests where applicable
- [ ] If this change affects the UI, I have included before/after
screenshots
- [x] I have updated relevant documentation to reflect my changes
- [x] I have considered and documented any risks above
- [x] I will address all Greptile and reviewer comments before
requesting merge
---------
Co-authored-by: Paperclip <noreply@paperclip.ing>
2026-04-14 13:34:52 -05:00
|
|
|
mockInstanceSettingsService.getGeneral.mockReset();
|
|
|
|
|
mockInstanceSettingsService.getExperimental.mockReset();
|
|
|
|
|
mockInstanceSettingsService.updateGeneral.mockReset();
|
|
|
|
|
mockInstanceSettingsService.updateExperimental.mockReset();
|
|
|
|
|
mockInstanceSettingsService.listCompanyIds.mockReset();
|
|
|
|
|
mockLogActivity.mockReset();
|
2026-03-20 08:00:39 -05:00
|
|
|
mockInstanceSettingsService.getGeneral.mockResolvedValue({
|
|
|
|
|
censorUsernameInLogs: false,
|
2026-04-02 11:45:15 -05:00
|
|
|
keyboardShortcuts: false,
|
2026-04-02 09:11:49 -05:00
|
|
|
feedbackDataSharingPreference: "prompt",
|
2026-03-20 08:00:39 -05:00
|
|
|
});
|
2026-03-17 09:24:28 -05:00
|
|
|
mockInstanceSettingsService.getExperimental.mockResolvedValue({
|
|
|
|
|
enableIsolatedWorkspaces: false,
|
2026-03-20 08:43:47 -05:00
|
|
|
autoRestartDevServerWhenIdle: false,
|
2026-03-17 09:24:28 -05:00
|
|
|
});
|
2026-03-20 08:00:39 -05:00
|
|
|
mockInstanceSettingsService.updateGeneral.mockResolvedValue({
|
|
|
|
|
id: "instance-settings-1",
|
|
|
|
|
general: {
|
|
|
|
|
censorUsernameInLogs: true,
|
2026-04-02 11:45:15 -05:00
|
|
|
keyboardShortcuts: true,
|
2026-04-02 09:11:49 -05:00
|
|
|
feedbackDataSharingPreference: "allowed",
|
2026-03-20 08:00:39 -05:00
|
|
|
},
|
|
|
|
|
});
|
2026-03-17 09:24:28 -05:00
|
|
|
mockInstanceSettingsService.updateExperimental.mockResolvedValue({
|
|
|
|
|
id: "instance-settings-1",
|
|
|
|
|
experimental: {
|
|
|
|
|
enableIsolatedWorkspaces: true,
|
2026-03-20 08:43:47 -05:00
|
|
|
autoRestartDevServerWhenIdle: false,
|
2026-03-17 09:24:28 -05:00
|
|
|
},
|
|
|
|
|
});
|
|
|
|
|
mockInstanceSettingsService.listCompanyIds.mockResolvedValue(["company-1", "company-2"]);
|
|
|
|
|
});
|
|
|
|
|
|
|
|
|
|
it("allows local board users to read and update experimental settings", async () => {
|
2026-04-09 06:12:39 -05:00
|
|
|
const app = await createApp({
|
2026-03-17 09:24:28 -05:00
|
|
|
type: "board",
|
|
|
|
|
userId: "local-board",
|
|
|
|
|
source: "local_implicit",
|
|
|
|
|
isInstanceAdmin: true,
|
|
|
|
|
});
|
|
|
|
|
|
|
|
|
|
const getRes = await request(app).get("/api/instance/settings/experimental");
|
|
|
|
|
expect(getRes.status).toBe(200);
|
2026-03-20 08:43:47 -05:00
|
|
|
expect(getRes.body).toEqual({
|
|
|
|
|
enableIsolatedWorkspaces: false,
|
|
|
|
|
autoRestartDevServerWhenIdle: false,
|
|
|
|
|
});
|
2026-03-17 09:24:28 -05:00
|
|
|
|
|
|
|
|
const patchRes = await request(app)
|
|
|
|
|
.patch("/api/instance/settings/experimental")
|
|
|
|
|
.send({ enableIsolatedWorkspaces: true });
|
|
|
|
|
|
|
|
|
|
expect(patchRes.status).toBe(200);
|
|
|
|
|
expect(mockInstanceSettingsService.updateExperimental).toHaveBeenCalledWith({
|
|
|
|
|
enableIsolatedWorkspaces: true,
|
|
|
|
|
});
|
|
|
|
|
expect(mockLogActivity).toHaveBeenCalledTimes(2);
|
|
|
|
|
});
|
|
|
|
|
|
2026-03-20 08:43:47 -05:00
|
|
|
it("allows local board users to update guarded dev-server auto-restart", async () => {
|
2026-04-09 06:12:39 -05:00
|
|
|
const app = await createApp({
|
2026-03-20 08:43:47 -05:00
|
|
|
type: "board",
|
|
|
|
|
userId: "local-board",
|
|
|
|
|
source: "local_implicit",
|
|
|
|
|
isInstanceAdmin: true,
|
|
|
|
|
});
|
|
|
|
|
|
|
|
|
|
await request(app)
|
|
|
|
|
.patch("/api/instance/settings/experimental")
|
|
|
|
|
.send({ autoRestartDevServerWhenIdle: true })
|
|
|
|
|
.expect(200);
|
|
|
|
|
|
|
|
|
|
expect(mockInstanceSettingsService.updateExperimental).toHaveBeenCalledWith({
|
|
|
|
|
autoRestartDevServerWhenIdle: true,
|
|
|
|
|
});
|
|
|
|
|
});
|
|
|
|
|
|
2026-03-20 08:00:39 -05:00
|
|
|
it("allows local board users to read and update general settings", async () => {
|
2026-04-09 06:12:39 -05:00
|
|
|
const app = await createApp({
|
2026-03-20 08:00:39 -05:00
|
|
|
type: "board",
|
|
|
|
|
userId: "local-board",
|
|
|
|
|
source: "local_implicit",
|
|
|
|
|
isInstanceAdmin: true,
|
|
|
|
|
});
|
|
|
|
|
|
|
|
|
|
const getRes = await request(app).get("/api/instance/settings/general");
|
|
|
|
|
expect(getRes.status).toBe(200);
|
2026-04-02 09:11:49 -05:00
|
|
|
expect(getRes.body).toEqual({
|
|
|
|
|
censorUsernameInLogs: false,
|
2026-04-02 11:45:15 -05:00
|
|
|
keyboardShortcuts: false,
|
2026-04-02 09:11:49 -05:00
|
|
|
feedbackDataSharingPreference: "prompt",
|
|
|
|
|
});
|
2026-03-20 08:00:39 -05:00
|
|
|
|
|
|
|
|
const patchRes = await request(app)
|
|
|
|
|
.patch("/api/instance/settings/general")
|
2026-04-02 09:11:49 -05:00
|
|
|
.send({
|
|
|
|
|
censorUsernameInLogs: true,
|
2026-04-02 11:45:15 -05:00
|
|
|
keyboardShortcuts: true,
|
2026-04-02 09:11:49 -05:00
|
|
|
feedbackDataSharingPreference: "allowed",
|
|
|
|
|
});
|
2026-03-20 08:00:39 -05:00
|
|
|
|
|
|
|
|
expect(patchRes.status).toBe(200);
|
|
|
|
|
expect(mockInstanceSettingsService.updateGeneral).toHaveBeenCalledWith({
|
|
|
|
|
censorUsernameInLogs: true,
|
2026-04-02 11:45:15 -05:00
|
|
|
keyboardShortcuts: true,
|
2026-04-02 09:11:49 -05:00
|
|
|
feedbackDataSharingPreference: "allowed",
|
2026-03-20 08:00:39 -05:00
|
|
|
});
|
|
|
|
|
expect(mockLogActivity).toHaveBeenCalledTimes(2);
|
|
|
|
|
});
|
|
|
|
|
|
2026-04-02 11:45:15 -05:00
|
|
|
it("allows non-admin board users to read general settings", async () => {
|
2026-04-09 06:12:39 -05:00
|
|
|
const app = await createApp({
|
2026-03-17 09:24:28 -05:00
|
|
|
type: "board",
|
|
|
|
|
userId: "user-1",
|
|
|
|
|
source: "session",
|
|
|
|
|
isInstanceAdmin: false,
|
|
|
|
|
companyIds: ["company-1"],
|
|
|
|
|
});
|
|
|
|
|
|
2026-03-20 08:00:39 -05:00
|
|
|
const res = await request(app).get("/api/instance/settings/general");
|
2026-03-17 09:24:28 -05:00
|
|
|
|
2026-04-02 11:45:15 -05:00
|
|
|
expect(res.status).toBe(200);
|
[codex] Harden execution reliability and heartbeat tooling (#3679)
## Thinking Path
> - Paperclip orchestrates AI agents for zero-human companies
> - Reliable execution depends on heartbeat routing, issue lifecycle
semantics, telemetry, and a fast enough local verification loop to keep
regressions visible
> - The remaining commits on this branch were mostly server/runtime
correctness fixes plus test and documentation follow-ups in that area
> - Those changes are logically separate from the UI-focused
issue-detail and workspace/navigation branches even when they touch
overlapping issue APIs
> - This pull request groups the execution reliability, heartbeat,
telemetry, and tooling changes into one standalone branch
> - The benefit is a focused review of the control-plane correctness
work, including the follow-up fix that restored the implicit
comment-reopen helpers after branch splitting
## What Changed
- Hardened issue/heartbeat execution behavior, including self-review
stage skipping, deferred mention wakes during active execution, stranded
execution recovery, active-run scoping, assignee resolution, and
blocked-to-todo wake resumption
- Reduced noisy polling/logging overhead by trimming issue run payloads,
compacting persisted run logs, silencing high-volume request logs, and
capping heartbeat-run queries in dashboard/inbox surfaces
- Expanded telemetry and status semantics with adapter/model fields on
task completion plus clearer status guidance in docs/onboarding material
- Updated test infrastructure and verification defaults with faster
route-test module isolation, cheaper default `pnpm test`, e2e isolation
from local state, and repo verification follow-ups
- Included docs/release housekeeping from the branch and added a small
follow-up commit restoring the implicit comment-reopen helpers that were
dropped during branch reconstruction
## Verification
- `pnpm vitest run
server/src/__tests__/issue-comment-reopen-routes.test.ts
server/src/__tests__/issue-telemetry-routes.test.ts`
- `pnpm vitest run server/src/__tests__/http-log-policy.test.ts
server/src/__tests__/heartbeat-run-log.test.ts
server/src/__tests__/health.test.ts`
- `server/src/__tests__/activity-service.test.ts`,
`server/src/__tests__/heartbeat-comment-wake-batching.test.ts`, and
`server/src/__tests__/heartbeat-process-recovery.test.ts` were attempted
on this host but the embedded Postgres harness reported
init-script/data-dir problems and skipped or failed to start, so they
are noted as environment-limited
## Risks
- Medium: this branch changes core issue/heartbeat routing and
reopen/wakeup behavior, so regressions would affect agent execution flow
rather than isolated UI polish
- Because it also updates verification infrastructure, reviewers should
pay attention to whether the new tests are asserting the right failure
modes and not just reshaping harness behavior
## Model Used
- OpenAI Codex coding agent (GPT-5-class runtime in Codex CLI; exact
deployed model ID is not exposed in this environment), reasoning
enabled, tool use and local code execution 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)
- [ ] I have run tests locally and they pass
- [x] I have added or updated tests where applicable
- [ ] If this change affects the UI, I have included before/after
screenshots
- [x] I have updated relevant documentation to reflect my changes
- [x] I have considered and documented any risks above
- [x] I will address all Greptile and reviewer comments before
requesting merge
---------
Co-authored-by: Paperclip <noreply@paperclip.ing>
2026-04-14 13:34:52 -05:00
|
|
|
expect(res.body).toEqual({
|
|
|
|
|
censorUsernameInLogs: false,
|
|
|
|
|
keyboardShortcuts: false,
|
|
|
|
|
feedbackDataSharingPreference: "prompt",
|
|
|
|
|
});
|
2026-04-02 11:45:15 -05:00
|
|
|
});
|
|
|
|
|
|
feat: implement multi-user access and invite flows (#3784)
## Thinking Path
> - Paperclip is the control plane for autonomous AI companies.
> - V1 needs to stay local-first while also supporting shared,
authenticated deployments.
> - Human operators need real identities, company membership, invite
flows, profile surfaces, and company-scoped access controls.
> - Agents and operators also need the existing issue, inbox, workspace,
approval, and plugin flows to keep working under those authenticated
boundaries.
> - This branch accumulated the multi-user implementation, follow-up QA
fixes, workspace/runtime refinements, invite UX improvements,
release-branch conflict resolution, and review hardening.
> - This pull request consolidates that branch onto the current `master`
branch as a single reviewable PR.
> - The benefit is a complete multi-user implementation path with tests
and docs carried forward without dropping existing branch work.
## What Changed
- Added authenticated human-user access surfaces: auth/session routes,
company user directory, profile settings, company access/member
management, join requests, and invite management.
- Added invite creation, invite landing, onboarding, logo/branding,
invite grants, deduped join requests, and authenticated multi-user E2E
coverage.
- Tightened company-scoped and instance-admin authorization across
board, plugin, adapter, access, issue, and workspace routes.
- Added profile-image URL validation hardening, avatar preservation on
name-only profile updates, and join-request uniqueness migration cleanup
for pending human requests.
- Added an atomic member role/status/grants update path so Company
Access saves no longer leave partially updated permissions.
- Improved issue chat, inbox, assignee identity rendering,
sidebar/account/company navigation, workspace routing, and execution
workspace reuse behavior for multi-user operation.
- Added and updated server/UI tests covering auth, invites, membership,
issue workspace inheritance, plugin authz, inbox/chat behavior, and
multi-user flows.
- Merged current `public-gh/master` into this branch, resolved all
conflicts, and verified no `pnpm-lock.yaml` change is included in this
PR diff.
## Verification
- `pnpm exec vitest run server/src/__tests__/issues-service.test.ts
ui/src/components/IssueChatThread.test.tsx ui/src/pages/Inbox.test.tsx`
- `pnpm run preflight:workspace-links && pnpm exec vitest run
server/src/__tests__/plugin-routes-authz.test.ts`
- `pnpm exec vitest run server/src/__tests__/plugin-routes-authz.test.ts
server/src/__tests__/workspace-runtime-service-authz.test.ts
server/src/__tests__/access-validators.test.ts`
- `pnpm exec vitest run
server/src/__tests__/authz-company-access.test.ts
server/src/__tests__/routines-routes.test.ts
server/src/__tests__/sidebar-preferences-routes.test.ts
server/src/__tests__/approval-routes-idempotency.test.ts
server/src/__tests__/openclaw-invite-prompt-route.test.ts
server/src/__tests__/agent-cross-tenant-authz-routes.test.ts
server/src/__tests__/routines-e2e.test.ts`
- `pnpm exec vitest run server/src/__tests__/auth-routes.test.ts
ui/src/pages/CompanyAccess.test.tsx`
- `pnpm --filter @paperclipai/shared typecheck && pnpm --filter
@paperclipai/db typecheck && pnpm --filter @paperclipai/server
typecheck`
- `pnpm --filter @paperclipai/shared typecheck && pnpm --filter
@paperclipai/server typecheck`
- `pnpm --filter @paperclipai/ui typecheck`
- `pnpm db:generate`
- `npx playwright test --config tests/e2e/playwright.config.ts --list`
- Confirmed branch has no uncommitted changes and is `0` commits behind
`public-gh/master` before PR creation.
- Confirmed no `pnpm-lock.yaml` change is staged or present in the PR
diff.
## Risks
- High review surface area: this PR contains the accumulated multi-user
branch plus follow-up fixes, so reviewers should focus especially on
company-boundary enforcement and authenticated-vs-local deployment
behavior.
- UI behavior changed across invites, inbox, issue chat, access
settings, and sidebar navigation; no browser screenshots are included in
this branch-consolidation PR.
- Plugin install, upgrade, and lifecycle/config mutations now require
instance-admin access, which is intentional but may change expectations
for non-admin board users.
- A join-request dedupe migration rejects duplicate pending human
requests before creating unique indexes; deployments with unusual
historical duplicates should review the migration behavior.
- Company member role/status/grant saves now use a new combined
endpoint; older separate endpoints remain for compatibility.
- Full production build was not run locally in this heartbeat; CI should
cover the full matrix.
## Model Used
- OpenAI Codex coding agent, GPT-5-based model, CLI/tool-use
environment. Exact deployed model identifier and context window were not
exposed 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 run tests locally and they pass
- [x] I have added or updated tests where applicable
- [x] If this change affects the UI, I have included before/after
screenshots
- [x] I have updated relevant documentation to reflect my changes
- [x] I have considered and documented any risks above
- [x] I will address all Greptile and reviewer comments before
requesting merge
Note on screenshots: this is a branch-consolidation PR for an
already-developed multi-user branch, and no browser screenshots were
captured during this heartbeat.
---------
Co-authored-by: dotta <dotta@example.com>
Co-authored-by: Paperclip <noreply@paperclip.ing>
Co-authored-by: Claude Opus 4.6 <noreply@anthropic.com>
2026-04-17 09:44:19 -05:00
|
|
|
it("rejects signed-in users without company access from reading general settings", async () => {
|
|
|
|
|
const app = await createApp({
|
|
|
|
|
type: "board",
|
|
|
|
|
userId: "user-2",
|
|
|
|
|
source: "session",
|
|
|
|
|
isInstanceAdmin: false,
|
|
|
|
|
companyIds: [],
|
|
|
|
|
memberships: [],
|
|
|
|
|
});
|
|
|
|
|
|
|
|
|
|
const res = await request(app).get("/api/instance/settings/general");
|
|
|
|
|
|
|
|
|
|
expect(res.status).toBe(403);
|
|
|
|
|
expect(mockInstanceSettingsService.getGeneral).not.toHaveBeenCalled();
|
|
|
|
|
});
|
|
|
|
|
|
2026-04-02 11:45:15 -05:00
|
|
|
it("rejects non-admin board users from updating general settings", async () => {
|
2026-04-09 06:12:39 -05:00
|
|
|
const app = await createApp({
|
2026-04-02 11:45:15 -05:00
|
|
|
type: "board",
|
|
|
|
|
userId: "user-1",
|
|
|
|
|
source: "session",
|
|
|
|
|
isInstanceAdmin: false,
|
|
|
|
|
companyIds: ["company-1"],
|
|
|
|
|
});
|
|
|
|
|
|
|
|
|
|
const res = await request(app)
|
|
|
|
|
.patch("/api/instance/settings/general")
|
|
|
|
|
.send({ censorUsernameInLogs: true, keyboardShortcuts: true });
|
|
|
|
|
|
2026-03-17 09:24:28 -05:00
|
|
|
expect(res.status).toBe(403);
|
2026-04-02 11:45:15 -05:00
|
|
|
expect(mockInstanceSettingsService.updateGeneral).not.toHaveBeenCalled();
|
2026-03-17 09:24:28 -05:00
|
|
|
});
|
|
|
|
|
|
|
|
|
|
it("rejects agent callers", async () => {
|
2026-04-09 06:12:39 -05:00
|
|
|
const app = await createApp({
|
2026-03-17 09:24:28 -05:00
|
|
|
type: "agent",
|
|
|
|
|
agentId: "agent-1",
|
|
|
|
|
companyId: "company-1",
|
|
|
|
|
source: "agent_key",
|
|
|
|
|
});
|
|
|
|
|
|
|
|
|
|
const res = await request(app)
|
2026-03-20 08:00:39 -05:00
|
|
|
.patch("/api/instance/settings/general")
|
2026-04-02 09:11:49 -05:00
|
|
|
.send({ feedbackDataSharingPreference: "not_allowed" });
|
2026-03-17 09:24:28 -05:00
|
|
|
|
|
|
|
|
expect(res.status).toBe(403);
|
2026-03-20 08:00:39 -05:00
|
|
|
expect(mockInstanceSettingsService.updateGeneral).not.toHaveBeenCalled();
|
2026-03-17 09:24:28 -05:00
|
|
|
});
|
|
|
|
|
});
|