Commit Graph
25 Commits
Author SHA1 Message Date
Nicky LeachandPaperclip b446ff59bf refactor(acpx-engine): coordinator-owned ACP run lifecycle with a typed resource ledger (#11576)
## Thinking Path

> - Paperclip is the open source app people use to manage AI agents for
work
> - Agent adapters run agent sessions through the ACPX engine
> - The ACPX engine handled one run attempt as a long implicit procedure
> - That shape made resource ownership, cleanup order, and failure
behavior hard to verify
> - This pull request gives the attempt a coordinator, a typed resource
ledger, separate run sites, and explicit turn and settlement sequences
> - The benefit is clear ownership, one cleanup path, safer session
reuse, and testable failure behavior

## Linked Issues or Issue Description

**What existing behavior does this improve?**

The ACPX engine manages startup, turn execution, session reuse, and
cleanup inside one large run procedure.

**Current behavior**

The run procedure owns several resources through implicit control flow.
Cleanup and session reuse behavior depend on lane-specific branches and
error paths.

**Proposed behavior**

The coordinator owns the run attempt. A typed ledger records six
resources and their states. Host and sandbox run sites own lane-specific
acquisition. Turn and settlement sequences expose typed outcomes. The
engine emits allowlisted phase telemetry.

**Reason and benefit**

Explicit ownership makes cleanup and failure behavior easier to inspect.
The fault matrix and characterization tests protect the external result
while the refactor reduces hidden control flow.

**Breaking changes**

None to the public adapter contract. The host warm-save path now closes
and relaunches the runtime because a transferred runtime could retain a
run-scoped credential. A cold session-handshake failure now closes the
created runtime.

**Additional context**

This pull request contains the ACPX engine lifecycle refactor, its
tests, and the lifecycle document.

## What Changed

- Add a run coordinator for startup, turn execution, settlement, and
result reproduction.
- Add a typed resource ledger with open, sealed, and consumed states.
- Add host and sandbox run sites for lane-specific resource acquisition.
- Replace separate runtime maps with a generic session reuse store.
- Split session fingerprint identity from the outer session key.
- Add typed turn and settlement sequences with one cleanup owner.
- Add a closed allowlist for phase telemetry.
- Add characterization tests and a 17-case fault matrix.
- Add `doc/acp-run-lifecycle.md`.

## Verification

- `npx vitest run packages/adapter-utils/src/acpx-engine/` passes 18
files and 286 tests at the submitted commit.
- `pnpm --filter @paperclipai/adapter-utils typecheck` reports 0 errors
at the submitted commit.
- Run the full pull request checks after GitHub starts CI.
- Run Greptile review after the pull request opens.

## Risks

- The refactor changes internal control flow across the ACPX engine.
- Host warm-save behavior now closes and relaunches the runtime.
- Settlement changes the handling of a cold session-handshake failure
from a leak to a close.
- The characterization baselines and fault matrix reduce the risk of an
external behavior change.

> Paperclip is the open source app people use to manage AI agents for
work
> The adapter layer runs agent sessions through the ACPX engine
> The engine needs explicit lifecycle ownership for reliable cleanup
> This pull request adds coordinator-owned phases and a typed resource
ledger
> The result makes lifecycle behavior easier to test and review

## Model Used

OpenAI GPT-5 Codex. Exact model ID: GPT-5. The model used tool
execution, repository inspection, and code review support. The
implementation author supplied the submitted code.

## Checklist

- [x] I have included a thinking path that traces from project context
to this change
- [x] I have specified the model used (with version and capability
details)
- [x] I have checked ROADMAP.md and confirmed this PR does not duplicate
planned core work
- [x] I have searched GitHub for duplicate or related PRs and linked
them above
- [x] I have either (a) linked existing issues with `Fixes: #` / `Closes
#` / `Refs #` OR (b) described the issue in-PR following the relevant
issue template
- [x] I have not referenced internal/instance-local Paperclip issues or
links (only public GitHub `#NNN` / `github.com/paperclipai/paperclip`
URLs)
- [x] My branch name describes the change (e.g. `docs/...`, `fix/...`)
and contains no internal Paperclip ticket id or instance-derived details
- [x] I have run tests locally and they pass
- [x] I have added or updated tests where applicable
- [x] I have updated relevant documentation to reflect my changes
- [x] I have considered and documented any risks above
- [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>
2026-08-17 22:02:16 -07:00
DottaandPaperclip 10d0555189 fix(interactions): authorize resolvers consistently (#11376)
## Thinking Path

> - Paperclip is the open source app people use to manage AI agents for
work.
> - Issue interactions give agents and people a structured decision
record.
> - Resolver routes used different authorization rules.
> - Some routes blocked valid agents, including task watchdogs with
normal issue access.
> - The API did not show who could resolve a pending interaction.
> - This pull request gives every interaction kind one resolver policy
evaluator.
> - The benefit is a clear decision path with consistent governance and
company isolation.

## Linked Issues or Issue Description

Fixes: #8087

Refs: #7403

Related PR: #11082 proposes board-only confirmation rules. This change
keeps human-only review as an explicit policy.

**What happened?**

Agents could create issue interactions. Some resolver routes still
required board access.

This left valid agent confirmations pending. Task watchdogs could see
the same problem without board identity.

**Expected behavior**

Every interaction kind must use one resolver policy contract.

The contract must support `anyone`, `not_creator`, and `human_only`. It
must also apply all normal governance controls.

**Steps to reproduce**

1. Create a `request_confirmation` interaction as an agent.
2. Resolve it with another authorized agent.
3. Observe the board-only denial.

**Paperclip version or commit**

The problem exists on `master` before this change.

**Deployment mode**

Local development with `pnpm dev`.

## What Changed

- Add canonical policies for `anyone`, `not_creator`, and `human_only`.
- Use one server evaluator for every interaction kind.
- Apply named addressees, company limits, review rules, and task
watchdog scope.
- Charge cross-issue resolutions to the existing per-run action limit.
- Return the effective resolver audience in attention and interaction
data.
- Show the audience, governance choices, and denial reasons in the board
UI.
- Add telemetry, API documents, product documents, and regression
fixtures.
- Add migration provenance for safe legacy behavior.
- Make migration `0218` safe for complete replays and partial prior
runs.

## Product Rules

- An interaction records a response. It does not grant authority for the
next action.
- `anyone` lets any authorized issue participant respond.
- `not_creator` requires a responder other than the interaction creator.
- `human_only` requires an authorized person.
- A named addressee, company policy, or governed action can narrow the
audience.
- These controls cannot widen the audience.
- A task watchdog uses the same rules as an ordinary agent.
- A task watchdog does not receive board authority.
- An agent resolution on another issue uses the shared cross-issue
action limit.
- Legacy pending interactions keep their earlier restrictions.
- The UI shows the effective audience and a permanent denial reason.

## Verification

- `pnpm --filter @paperclipai/db check:migrations`
- `pnpm --filter @paperclipai/db typecheck`
- `pnpm exec vitest run
packages/db/src/issue-thread-interaction-resolver-policy-migration.test.ts`
- The focused PostgreSQL test applies migration `0218` twice.
- The test also completes a partial prior run and preserves existing
provenance.
- The latest GitHub head has 29 successful checks.
- The opt-in Storybook visual check skipped as expected.
- Greptile reports 5/5 with no open comments.

## Risks

- New interaction writes use `anyone` by default.
- Callers must select `not_creator` or `human_only` when they need
stricter review.
- Legacy pending interactions keep the old creator and human
restrictions.
- Migration `0218` fills only missing provenance fields during recovery.
- Cross-issue resolutions can reach the existing action limit.
- The shared evaluator affects every interaction kind.
- Route, service, database, shared contract, and UI tests cover these
rules.

> This work matches the Agent Reviews and Approvals direction in
`ROADMAP.md`. It does not duplicate a planned item.

## Model Used

OpenAI Codex, GPT-5. The runtime does not expose the exact deployment ID
or context window.

The agent used reasoning, repository tools, shell commands, and test
execution.

## Checklist

- [x] I have included a thinking path that traces from project context
to this change
- [x] I have specified the model used (with version and capability
details)
- [x] I have checked ROADMAP.md and confirmed this PR does not duplicate
planned core work
- [x] I have searched GitHub for duplicate or related PRs and linked
them above
- [x] I have either linked public issues or described the issue with the
required labels
- [x] I have not referenced internal Paperclip issues or links
- [x] My branch name describes the change and contains no internal
ticket id
- [x] I have run tests locally and they pass
- [x] I have added or updated tests where applicable
- [x] I have updated relevant documentation
- [x] I have considered and documented the risks
- [x] All Paperclip CI gates are green
- [x] Greptile is 5/5 with no open comments
- [x] I will address all Greptile and reviewer comments before
requesting merge

---------

Co-authored-by: Paperclip <noreply@paperclip.ing>
2026-08-16 13:46:50 -05:00
Nicky LeachandClaude Opus 4.8 04bf7a6ab5 feat(observability): instrument stage.sync host steps and home the agent process span (#11301)
## Thinking Path

> - Paperclip is the open source app people use to manage AI agents for
work.
> - It runs each agent in a remote sandbox and emits OpenTelemetry spans
for the sandbox bring-up and the run.
> - A real trace showed two gaps. `stage.sync` had about 3 seconds of
unattributed host work before its `pack` span. The persistent agent
process showed a `sandbox.exec` span that outlived its parent by about
50 seconds.
> - The gaps hide real cost and make the trace read as a sequencing bug,
so an operator cannot see where startup time goes.
> - This pull request wraps the two pre-`pack` host steps in their own
spans. It also homes the long-lived process in a run-scoped
`sandbox.agentProcess` span.
> - The benefit is that startup time is fully attributed and the process
reads as a resource that overlaps the turn, not a child that outlives
its parent.

## Linked Issues or Issue Description

No public issue exists. This is an enhancement to existing telemetry. It
is described inline below, following
`.github/ISSUE_TEMPLATE/enhancement.yml`. Prior related work: the merged
PR #10999 added the run-time wrapper spans and the telemetry
data-contract section this PR extends.

**What existing behavior does this improve?**

The sandbox bring-up and run OpenTelemetry trace. It closes two
attribution gaps in that trace.

**Subsystem affected**

Observability for sandbox execution. The code lives in
`packages/adapter-utils`. The span contract lives in
`packages/shared/src/telemetry`.

**Current behavior**

`stage.sync` opens a `pack` span, but the git enumeration and the
baseline content-hash walk that run before `pack` have no span, so about
3 seconds read as a gap. On the streamed process-session path the agent
process launches fire-and-forget inside the ~2.3 second
`bridge.process-session` bring-up step, so its `sandbox.exec` span
parents to that step and then runs about 50 seconds. The child dangles
past its parent and overlaps `agent.turn`.

**Proposed behavior**

Wrap the two pre-`pack` host operations in `snapshot.git` and
`snapshot.baseline` spans under `stage.sync`. Wrap the streamed launch
in a run-scoped `sandbox.agentProcess` span that parents to the live run
root (`task.run` at launch).

**Reason and benefit**

Startup time is fully attributed. The long-lived process reads as a
resource that overlaps the sibling `agent.turn`, not a mis-parented
child.

**Breaking changes**

None. The spans are opt-in and export only when an OTLP endpoint is
configured. The span seam is a no-op when no runner is injected. No
first-party telemetry event changes.

## What Changed

- `sandbox-managed-runtime.ts`: add `snapshot.git` and
`snapshot.baseline` spans around the git enumeration and the baseline
content-hash walk, nested under `stage.sync`, through a shared
`runStepSpan` helper that `pack` now also uses.
- `execution-target.ts`: wrap the fire-and-forget streamed launch in a
run-rooted `sandbox.agentProcess` span, so it parents to the live run
root and holds the inner `sandbox.exec`. The `.then`/`.catch` chain
became try/catch inside the span callback, with identical
frame-ingestion behavior.
- `packages/shared/src/telemetry/README.md`: update the span table and
the parenting prose. Add `snapshot.git`, `snapshot.baseline`, `pack`,
and `sandbox.agentProcess`, and document the intended
`sandbox.agentProcess` / `agent.turn` overlap.
- Tests: update the executor span-tree test (`childNames` and parent
assertions), update the `sandbox-managed-runtime` span-set and nesting
tests, and add two `execution-target-sandbox` tests (the launch opens
`sandbox.agentProcess`; it parents to the run root, not the bring-up
step).

## Verification

- Run `npx vitest run` on the three affected test files. Result: 174
tests pass. This includes the updated executor span-tree test and the
new `sandbox.agentProcess` open and parenting tests.
- Run `tsc --noEmit` in `packages/adapter-utils`. Result: no errors in
the changed source or test files.
- The full 37-test streamed process-session suite passes unchanged. This
confirms the try/catch restructure preserves frame delivery and
exit/error behavior.
- Pre-existing and unrelated to this PR (present on `master`): `tsc`
errors in `execute.ts` / `execute.test.ts` /
`remote-spawn-smoke.test.ts` (`onAgentStderr` / `spawnCwd`), and a
`check:forbidden-tokens` failure from internal `PAP-###` ids in
`ui/src/components/IssueRecoveryActionCard.test.tsx`. This PR does not
touch those files, and its own diff is token-clean.

## Risks

Low. The change adds instrumentation on the opt-in span path and does
not change control flow on the default path. The one production
restructure is the streamed launch, which stays fire-and-forget, so
bring-up does not block on it. Only the streamed path gains
`sandbox.agentProcess`; the legacy poll path launches the process
detached and has no host-side long-lived span to home.

## Model Used

Anthropic Claude Opus 4.8 (`claude-opus-4-8`), about 200K-token context,
agentic tool use through Claude Code. The trace was reviewed through the
Honeycomb MCP. The code was written and tested with the model.

## 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: Claude Opus 4.8 <noreply@anthropic.com>
2026-08-12 16:06:05 -07:00
Nicky LeachandPaperclip 9ace548fd2 feat(observability): rename sandbox provider spans and add run-time wrapper spans (#10999)
## Thinking Path

> - Paperclip is the open source app people use to manage AI agents for
work
> - Paperclip uses adapter and sandbox code to start agents and run
sandbox work
> - The current sandbox spans use mixed names and do not group related
run-time work
> - Mixed names make traces harder to read and compare across providers
> - This pull request renames provider spans, adds run-time wrapper
spans, and keeps the host allowlist closed
> - The benefit is clearer traces with the same sandbox behavior and
trust boundary

## Linked Issues or Issue Description

**What existing behavior does this improve?**

This improves OpenTelemetry span names and grouping for sandbox startup,
execution, callback relay, and agent session work.

**Subsystem affected**

Cross-cutting (multiple of the above): adapter utilities, sandbox
providers, shared telemetry documentation, and server instrumentation.

**Current behavior**

Sandbox provider spans use mixed names. Related run-time operations
expose inner `sandbox.exec` spans without a named wrapper span. The host
mapper uses a closed allowlist for provider span names.

**Proposed behavior**

Use descriptive provider-scoped span names. Add wrapper spans for agent
session input, agent session output polling, and callback relay. Keep
the host mapper allowlist closed and map unknown names to `other`.

**Reason and benefit**

Clear names make traces easier to read and reduce ambiguity during
sandbox operation analysis. Wrapper spans show the full operation while
preserving the inner execution spans.

**Breaking changes**

None. This change updates telemetry span names and grouping only. It
does not change sandbox behavior, endpoint behavior, or the host trust
boundary.

**Additional context**

Related prior work:
[#10758](https://github.com/paperclipai/paperclip/pull/10758).

## What Changed

- Rename Daytona provider sync and session spans with descriptive
provider-scoped names.
- Add three run-time wrapper spans for agent session input, output
polling, and callback relay.
- Add a shared span runner that preserves no-op behavior without a real
tracer.
- Keep the host mapper allowlist closed and map unknown names to
`other`.
- Update telemetry documentation and span-name tests.

## Verification

- Focused adapter-utils span tests pass for startup timing, callback
relay, and sandbox execution.
- Focused Daytona plugin span tests pass for renamed leaf spans and
session open or close spans.
- Focused server tests pass for host mapping and instrumentation.
- The stacked diff contains one commit on top of
`feat/daytona-persistent-session-model`.

## Risks

- Span names change for existing telemetry consumers.
- The wrapper spans add trace structure but do not change sandbox
execution.
- The host mapper keeps the existing closed allowlist and `other`
bucket.

> 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 agent); exact deployment revision and context window
are not exposed in this run; tool use and 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)
- [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] 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>
2026-08-06 22:31:15 -07:00
DottaandPaperclip 8e7f1c03eb feat(decisions): improve desk triage and queue parity (#10785)
## Thinking Path

> - Paperclip is the open source app people use to manage AI agents for
work.
> - The decisions desk and queue help operators find work that needs a
human decision.
> - The current views use different grouping, sorting, and labels.
> - Repeated confirmation requests can also leave stale pending actions
in the queue.
> - Blocked-work attention can point at an intermediate issue instead of
the terminal blocker.
> - This pull request aligns the server contract and both user
interfaces.
> - The benefit is a smaller, clearer queue that ranks the decisions
with the largest impact.

## Linked Issues or Issue Description

Related PR: #10774

**What existing behavior does this improve?**

The decisions desk and queue currently use different triage rules. They
can show stale repeated confirmations and can rank blocked work by an
intermediate issue.

**Subsystem affected**

This change affects attention aggregation, issue thread interactions,
shared attention contracts, and the decisions user interface.

**Current behavior**

The desk uses a can-wait group that has no clear arrival meaning. The
queue has fewer controls than the desk. Repeated pending confirmations
remain actionable. Blocked-work rows do not always identify the terminal
actionable blocker.

**Proposed behavior**

Group desk items by arrival date, and reserve Decide now for explicit
due dates. Use one toolbar and shelf model on both pages. Supersede
older repeated pending confirmations. Aggregate blocked work under the
terminal actionable blocker and rank it by impact.

**Reason and benefit**

Operators get one consistent triage model. The badge reflects new and
overdue work. High-impact blockers move to the top. Duplicate
confirmation work no longer consumes attention.

**Breaking changes**

The attention summary field `decideNowCount` changes to
`deskBadgeCount`. Consumers must use the new field. Older repeated
confirmation interactions can now finish with the
`superseded_by_newer_request` outcome.

## What Changed

- Supersede older pending confirmation requests for the same issue and
record the mutation in activity history.
- Resolve blocked-work attention to actionable terminal blockers,
suppress live blocker trees, and rank rows by blocked-work impact.
- Group the decisions desk into New today and Earlier, and count new
plus overdue work in the desk badge.
- Share the decision toolbar and shelf components across the desk and
queue.
- Add queue grouping, sorting, filtering, aging, visible training
controls, and clearer recommendation copy.
- Add server, shared-contract, and user-interface tests for the new
behavior.

## Verification

- `pnpm check:token-gates`
- `pnpm -r typecheck`
- `env -u AWS_ACCESS_KEY_ID -u AWS_SECRET_ACCESS_KEY pnpm test:run` (all
server, UI, CLI, shared, and catalog tests passed; one fixed five-second
DB timeout flaked under full-suite load)
- `NODE_ENV=test pnpm --filter @paperclipai/db exec vitest run
src/status-card-migrations.test.ts` (passed in isolation)
- `pnpm build`

## Risks

- The attention summary field rename requires synchronized consumers.
- Terminal-blocker traversal uses cycle and depth guards. A malformed
dependency graph can stop at the last safe node.
- The new arrival grouping changes which items contribute to the
decisions badge.
- Superseding repeated confirmations changes the terminal state of older
pending interactions.

> For core feature work, check [`ROADMAP.md`](ROADMAP.md) first and
discuss it in `#dev` before opening the PR. Feature PRs that overlap
with planned core work may need to be redirected — check the roadmap
first. See `CONTRIBUTING.md`.

## Model Used

OpenAI Codex with GPT-5. The runtime did not expose a dated model
snapshot or context-window size. The model used reasoning, repository
tools, code execution, and test execution.

## Checklist

- [x] I have included a thinking path that traces from project context
to this change
- [x] I have specified the model used (with version and capability
details)
- [x] I have checked ROADMAP.md and confirmed this PR does not duplicate
planned core work
- [x] I have searched GitHub for duplicate or related PRs and linked
them above
- [x] I have either (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>
2026-08-03 21:31:45 -05:00
Nicky LeachandPaperclip 6a69a3d6b0 refactor(observability): stop writing detailed per-step timing to the run log (#10776)
## Thinking Path

> - Paperclip tracks agent work for the team.
> - The startup timing path already emits detailed spans.
> - The run log repeats the same detailed timing.
> - That makes the event larger than it needs to be.
> - This pull request removes the redundant per-step timing fields from
the run-log payload.
> - The benefit is a smaller log with the same detail still available in
traces.

## Linked Issues or Issue Description

No public GitHub issue or open pull request matches this change. I
described the enhancement below.

**What existing behavior does this improve?**
`run.startup.step` event output.

**Subsystem affected**
Cross-cutting (multiple of the above)

**Current behavior**
`run.startup.step` writes `roundTrips`, `providerExecMs`,
`providerGetMs`, `createRuntimeMs`, and `ensureSessionMs`. The same
detail already exists in the spans.

**Proposed behavior**
`run.startup.step` keeps only `step`, `durationMs`, and `outcome`. The
heartbeat lifecycle timestamps stay unchanged.

**Reason and benefit**
This change removes redundant data from the run log. It keeps the useful
detail in trace spans. It also makes the payload smaller and easier to
read. The revert path stays clear because the removed data has one
producer chain.

**Breaking changes**
Yes. Consumers that read the removed fields must switch to span data or
the remaining event fields. The heartbeat lifecycle timestamps do not
change.

**Additional context**
I searched GitHub for related open PRs and issues. I found no match.

## What Changed

- Removed the redundant per-step timing fields from the run-log payload.
- Removed the now-dead producer chain that fed those fields.
- Kept the span-level timing data and the heartbeat lifecycle
timestamps.

## Verification

- `adapter-utils` typecheck clean
- `server` typecheck clean
- `startup-timing` suite: 30 passed
- `adapter-utils` `execute` suite: 99 passed
- `server` `environment-execution-target` suite: 21 passed

## Risks

- Consumers that still read the removed fields will need a code change.
- This is a one-way-door data removal for the run log.

## Model Used

OpenAI Codex, GPT-5, 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 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>
2026-08-03 15:58:21 -07:00
Nicky LeachandPaperclip af6b32d82a feat(observability): add provider OTel spans - cache-hit flag, plugin tracer, Daytona pack/transfer spans (#10764)
## Thinking Path

> - Paperclip uses pull requests to ship control-plane changes with
review and audit.
> - This change extends sandbox provider telemetry.
> - The first PR added startup and exec spans.
> - This PR adds provider spans for cache hits, plugin tracer flow, and
Daytona file sync steps.
> - The host must keep the trust boundary and reject unsafe span data.
> - The result is fuller OTel coverage with bounded labels and safe
parentage.

## Linked Issues or Issue Description

**Problem or motivation**

Sandbox provider telemetry lacks an explicit cache-hit signal, plugin
span context, and file-sync pack and transfer spans.
The current proxy for a cache hit is fragile.
The plugin SDK also needs a safe tracer surface and a per-call parent
context.

**Proposed solution**

Add an explicit `cacheHit` flag from the Daytona sandbox handle lookup.
Expose `ctx.tracer` on the plugin context and pass a `traceparent`
string with each call.
Record provider spans on the host with allowlist clamping and capability
checks.
Wrap Daytona file sync pack and transfer steps in spans.

**Alternatives considered**

Keep the old `providerGetMs == 0` proxy.
Reject that path because the cache-hit decision belongs at the handle
lookup, not in a timing proxy.

The host stays the trust boundary for worker span data.
It clamps labels, rejects bad parent data, and gates the worker-to-host
span RPC by capability.
A security review completed before this PR opened.

## What Changed

- Added an explicit `cacheHit` flag from the Daytona sandbox handle
lookup.
- Added `ctx.tracer` on the plugin context and a `traceparent` field in
the per-call context.
- Added host-side span recording with attribute clamping and capability
checks.
- Wrapped Daytona file sync pack and transfer steps in spans.
- Added tests for the host trust boundary, the plugin tracer no-op path,
and the Daytona span paths.

## Verification

- `pnpm --filter @paperclipai/plugin-daytona exec vitest run`
- `pnpm --filter @paperclipai/plugin-sdk exec vitest run`
- `pnpm --filter @paperclipai/server exec vitest run
plugin-host-services environment-execution-target instrumentation
plugin-worker-manager`
- `tsc --noEmit` for server, plugin-sdk, and adapter-utils

## Risks

- Span data now crosses the worker boundary, so the host allowlist and
capability gate must stay strict.
- The `traceparent` path must stay valid and host-owned.
- Daytona file sync spans must not add new round trips.

## Model Used

OpenAI Codex, GPT-5, tool use.

## Checklist

- [x] I have included a thinking path that traces from project context
to this change
- [x] I have specified the model used with version and capability
details
- [x] I have checked ROADMAP.md and confirmed this PR does not duplicate
planned core work
- [x] I have searched GitHub for duplicate or related PRs and linked
them above
- [x] I have either linked existing issues with `Fixes:` / `Closes:` /
`Refs:` or described the issue in the PR body
- [x] I have not referenced internal or instance-local Paperclip issues
or links
- [x] My branch name describes the change and contains no internal
Paperclip ticket id 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>
2026-08-03 13:09:01 -07:00
Nicky LeachandPaperclip c09ea7112b feat(observability): add granular OpenTelemetry spans for sandbox startup and execution (#10758)
## Thinking Path

> - Paperclip coordinates AI agent work and records execution data.
> - The sandbox startup path and the host-to-sandbox execution path need
clearer OpenTelemetry spans.
> - The trace data now shows wait time, critical path data, and bounded
labels.
> - This pull request adds bounded spans and closed attribute helpers
for sandbox startup and execution.
> - The result is better trace data with low cardinality and no secret
leakage.

## Linked Issues or Issue Description

- No public GitHub issue exists for this branch.
- Related PR: #10536
- This PR extends the sandbox OpenTelemetry work with exec spans, root
timing, and bounded labels.

## What Changed

- Added a closed span-attribute contract for sandbox startup data.
- Added a bounded label helper for command and region values.
- Threaded the active step context into the execution path.
- Added a `sandbox.exec` span with true timestamps and bounded
attributes.
- Added skipped-step and root-span timing data with low-cardinality
context.
- Moved handshake sub-times and bridge batch data onto spans.

## Verification

- `pnpm --filter @paperclipai/adapter-utils run typecheck`
- `pnpm --filter @paperclipai/server run typecheck`
- `pnpm --filter @paperclipai/adapter-utils exec vitest run`
- `pnpm --filter @paperclipai/server exec vitest run
environment-execution-target`
- `git log --oneline
origin/master..origin/feat/sandbox-startup-otel-spans`
- `git diff origin/master...origin/feat/sandbox-startup-otel-spans
--stat`

## Risks

- Span attribute rules could still miss a future field if new code skips
the shared helper.
- Low-cardinality labels may hide some detail, but that is the intended
tradeoff.
- Tracing stays fail-open, so a missing tracer still hides data rather
than stopping work.

## Model Used

- OpenAI Codex, GPT-5, tool use enabled. The runtime did not expose the
context window size.

## 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 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] Greptile is 5/5 with no open P2s, recommendations, or follow-ups
- [x] I will address all Greptile and reviewer comments before
requesting merge

The current head still has one failing required check: `e2e`. The PR
stays unready for board handoff until that check passes.

---------

Co-authored-by: Paperclip <noreply@paperclip.ing>
2026-08-03 10:13:19 -07:00
Nicky LeachandPaperclip 9f7565f4ce feat: activate OpenTelemetry spans on the sandbox start path (#10536)
## Thinking Path

> - Paperclip moves agent work through sandboxed execution and
control-plane services.
> - The sandbox start path now has a no-op span seam.
> - This change turns that seam on when OTLP export is configured.
> - It keeps the default path unchanged when export is off.
> - The result is structured startup traces with low-cardinality
attributes and explicit parent links.
> - The benefit is better observability without changing normal
behavior.

## Linked Issues or Issue Description

No public GitHub issue exists for this change.

### Problem
The sandbox start path has a tracer seam, but it stays a no-op unless
the OTLP export path is active.

### Proposed solution
Enable the server tracer on sandbox bring-up, open a root span, parent
each startup boundary to that root, and keep the export path opt-in
behind `OTEL_EXPORTER_OTLP_ENDPOINT`.

### Alternatives considered
- Keep the start path as a no-op. I rejected that path because it leaves
sandbox start opaque when OTLP export is already configured.
- Add broad attributes for commands and paths. I rejected that path
because the span allowlist must stay low-cardinality.

### Roadmap alignment
This follows the current OTel sandbox-start work and keeps the default
path unchanged.

## What Changed

- Add a root sandbox startup span and child spans for each named startup
boundary.
- Keep concurrent bridge spans parented to the root span.
- Inject the server tracer through the adapter deps without
OpenTelemetry imports in the engine.
- Attach host-received provider duration attributes only when the values
are finite.
- Keep span attributes inside the allowlist and keep command, path, id,
and error text out of span data.

## Verification

- The pushed branch already passed `pnpm --filter
@paperclipai/adapter-utils exec tsc --noEmit`.
- The pushed branch already passed `pnpm exec vitest run
packages/adapter-utils/src/acpx-engine/`.
- The pushed branch already passed `pnpm --filter @paperclipai/server
exec vitest run src/__tests__/environment-execution-target.test.ts
src/__tests__/instrumentation.test.ts`.
- The pushed branch already passed `pnpm --filter @paperclipai/server
exec tsc --noEmit`.

## Risks

- OTel export changes trace volume when the endpoint is set.
- The allowlist limits trace detail, so new fields need care.
- The change stays no-op when OTLP export is off.

## Model Used

- OpenAI GPT-5, 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 capability details
- [x] I have checked ROADMAP.md and confirmed this PR does not duplicate
planned core work
- [x] I have searched GitHub for duplicate or related PRs and linked
them above
- [x] I have either linked existing issues or described the issue in-PR
- [x] I have not referenced internal/instance-local Paperclip issues or
links
- [x] My branch name describes the change and contains no internal
ticket id 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>
2026-07-30 21:20:58 -07:00
Nicky Leach c81a089c12 feat(telemetry): align client with wire contract — chunking, deterministic batchId, batched retry, bounded store (#9946) 2026-07-21 09:25:58 -05:00
bf6365637a feat(telemetry): pin silent-drop baseline and add caps/backoff config surface (Impl-1) (#9906)
## Thinking Path

> - Paperclip is the open source app people use to manage AI agents for
work
> - The telemetry subsystem (`packages/shared/src/telemetry`) flushes
event batches to an ingest endpoint; today the client drops batches
silently on 429 / 413 / 400 / network error with no re-queue and no
retry
> - The current behaviour is uncharacterised — there are no regression
tests pinning it, so any future retry work could accidentally change the
drop semantics without a test failing
> - Before adding retry logic it is critical to lock the current
baseline as an explicit, documented contract so regressions are
immediately visible
> - Additionally, the retry/cap design needs a config surface
(`maxEventsPerBatch`, `maxBodyBytes`, `maxPendingRetryBatches`,
`backoff`) so operators can tune behaviour without forking; that surface
should be defined and defaulted before the first consumer lands, not
after
> - This pull request adds characterisation tests that pin today's
silent-drop baseline and adds an optional, additive config surface with
resolved defaults — `client.ts` is untouched so no behaviour changes
> - The benefit is that the retry work in the follow-up PR can build on
a verified baseline, safe defaults, and a pre-wired config contract
rather than specifying everything at once

## Linked Issues or Issue Description

No pre-existing public GitHub issue. Underlying problem described below
(feature-request template).

**Problem or motivation**

The telemetry client in `packages/shared/src/telemetry/client.ts` has no
regression tests covering its error-path semantics. On 429 / 413 / 400 /
network failure the current code drains the whole queue via `splice(0)`
and discards the batch — silent drop, no retry. That behaviour is
correct for a best-effort client today, but nothing verifies it. When
retry logic lands, there is no safety net to confirm it does not
accidentally re-queue already-dropped batches. In parallel, the retry
design requires a typed config surface (`maxEventsPerBatch`,
`maxBodyBytes`, `maxPendingRetryBatches`, `backoff`) that the client and
its callers need to agree on before the first consumer is wired up.

**Proposed solution**

Two-phase additive scaffolding:
1. Lock the silent-drop baseline as pinned tests (temporary; Impl-2
replaces them when retry lands).
2. Add the config surface and defaults now so Impl-2 can consume them
immediately.

**Alternatives considered**

Writing the tests and config surface inside the retry PR — rejected
because it makes the retry diff much harder to review and loses the
regression-safety benefit of a committed baseline.

**Roadmap alignment**

Maintenance / client-correctness improvement; not a core roadmap
feature.

## What Changed

- **`client.test.ts`** — 5 new Phase-1 characterisation tests pinning
silent-drop on 429, 413, 400, and network-error. A
`stubFetchStatus(status)` helper DRYs the four drop cases. These are
temporary regression anchors: marked `TODO(impl-2): replace when retry
lands`.
- **`config.ts`** — `TELEMETRY_DEFAULTS` constant (frozen) +
`resolveCaps()` + `resolveTelemetryConfig()`. Provides a single exported
source of truth for defaults; nothing reads these yet.
- **`types.ts`** — 4 optional, additive `TelemetryConfig` fields:
`maxEventsPerBatch` (default 50), `maxBodyBytes` (default 524 288),
`maxPendingRetryBatches` (default 20), `backoff` (exp-with-jitter
shape). All optional and backward-compatible.
- **`index.ts`** — re-exports `TELEMETRY_DEFAULTS` and
`resolveTelemetryConfig` from the public package surface.
- **`client.ts`** — no changes (verified via `git diff --stat`).

## Verification

```bash
# Unit tests — 16 passed (5 new Phase-1 pins + 2 new Phase-2 config tests + 9 existing)
pnpm --filter @paperclipai/shared exec vitest run src/telemetry

# Type check — clean
pnpm --filter @paperclipai/shared typecheck

# Confirm client.ts untouched (zero output expected)
git diff HEAD~1 -- packages/shared/src/telemetry/client.ts
```

All three commands verified locally before push.

## Risks

**Low risk.** `client.ts` is untouched — no behaviour change. All four
modified files are additive:
- New tests cannot regress production behaviour.
- New config fields are `optional` and their defaults match the current
implicit constants in `client.ts`, so any future reader gets identical
semantics until it overrides them.
- `resolveTelemetryConfig` replaces no existing function; it is new.
- No envelope / wire change; no new PII / crypto / sink.

The `TODO(impl-2)` markers on the Phase-1 pins make their temporary
nature explicit in code.

## Model Used

- **Provider:** Anthropic  
- **Model:** Claude Sonnet 4.6 (`claude-sonnet-4-6`)  
- **Context window:** 200k tokens  
- **Capabilities:** Tool use, code execution, agentic task completion
via Paperclip agent SDK
- **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
- [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: Harold Kim <harold@paperclip.ing>
Co-authored-by: Paperclip <noreply@paperclip.ing>
2026-07-21 06:14:03 -05:00
Nicky LeachandPaperclip 24bbc0f57e docs: add telemetry marker workflow (#9543)
## Thinking Path

> - Paperclip is an open-source agentic AI management platform that
ships anonymous usage telemetry to understand product health and
adoption.
> - The telemetry system has a generated contract
(`packages/shared/src/telemetry/generated/paperclip-telemetry.ts`) that
types every first-party event the product emits.
> - When a product change needs a new first-party event that is not yet
in the generated contract, contributors had no public workflow
explaining how to propose an event or later promote it into the contract
once accepted.
> - The gap leads to confusion at call sites: contributors either skip
tracking entirely or emit untyped events that bypass the privacy and
governance safeguards built into the contract.
> - This PR fills that gap by adding `doc/TELEMETRY_WORKFLOW.md` — a
public contributor guide that covers the full propose → promote
lifecycle: the `@ts-expect-error -- proposed-telemetry(...)` marker, the
canonical multi-line `track()` shape, the TS2578 expiry signal, and the
look-up-by-event-name promotion step.
> - `packages/shared/src/telemetry/README.md` gains a cross-reference so
readers of the data-contract doc can find the workflow guide without
searching.
> - `README.md` gains a one-line pointer in the telemetry section so the
workflow is discoverable from the project entry point.

## Linked Issues or Issue Description

No pre-existing public GitHub issue covers this doc gap. Inline
description:

**Problem:** Contributors adding product telemetry for events not yet in
the generated contract have no documented workflow. The
`@ts-expect-error -- proposed-telemetry(...)` pattern exists in the
codebase but is undocumented, leading to inconsistent usage and missing
adoption signals.

**Solution:** A new public guide (`doc/TELEMETRY_WORKFLOW.md`) documents
the marker format, the recommended multi-line `track()` shape that
preserves the TS2578 expiry signal, the dimension rules, and the
promotion checklist. Cross-references are added to
`packages/shared/src/telemetry/README.md` and the top-level `README.md`.

No related open PRs found.

## What Changed

- **New file `doc/TELEMETRY_WORKFLOW.md`** — public contributor guide
for the propose/promote lifecycle: marker format, canonical multi-line
example, TS2578 single-line trap, dimension rules, and step-by-step
promotion checklist.
- **`packages/shared/src/telemetry/README.md`** — added one-line
cross-reference pointing at `doc/TELEMETRY_WORKFLOW.md` for proposed
events not yet in the generated contract.
- **`README.md`** — added one-line pointer in the telemetry section so
the new workflow guide is reachable from the top-level project entry.

## Verification

This is a docs-only change. Verification steps:

1. Open `doc/TELEMETRY_WORKFLOW.md` and confirm it contains:
   - The `^[a-z0-9][a-z0-9._:-]{1,63}$` event-name grammar.
- The exact `// @ts-expect-error -- proposed-telemetry(<issue>):
<rationale>` marker.
- The multi-line `client.track()` copy-paste example (directive on line
before event-name string).
- The explanation of the TS2578 single-line trap and the
look-up-by-event-name step.
   - The promotion checklist in the "Promote An Event" section.
2. Confirm `packages/shared/src/telemetry/README.md` cross-references
`doc/TELEMETRY_WORKFLOW.md`.
3. Confirm the `README.md` telemetry section links to
`doc/TELEMETRY_WORKFLOW.md`.

## Risks

Low risk — docs-only change. No runtime behavior, schema, or existing
telemetry emission is affected. The risk is that the guidance could
diverge from the actual enforcement in the codebase over time; mitigated
by linking to the generated contract and keeping the doc in the same
repo.

## Model Used

Claude — `claude-sonnet-4-6` (Anthropic Claude Sonnet 4.6). Tool use
enabled. Extended context. Produced via the Paperclip agentic workflow
with `Co-authored-by: Paperclip <noreply@paperclip.ing>`.

## 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>
2026-07-14 08:25:53 -07:00
Nicky LeachandPaperclip 90f85a7d11 Add telemetry proposal extractor (#9544)
## Thinking Path

> - Paperclip is the open source app people use to manage AI agents for
work
> - It emits telemetry events to understand product usage — registered
event names are gated by a generated `PAPERCLIP_EVENTS` registry so the
client only enqueues known, schema-approved events
> - When product teams want to instrument a new behaviour, they must
first register the event name — but schema registration is a
commit-and-release cycle, which creates friction in fast-moving product
iterations
> - A proposal lane is needed: let developers mark a `track()` call with
a typed `@ts-expect-error` proposal marker so the event name can be
reviewed and tracked in CI before the schema is formally registered
> - The existing client had no guard against unregistered event names,
so any call with an out-of-registry name (or a prototype-inherited key)
would silently enter the queue, state, and network flush path
> - This PR adds an `Object.hasOwn(PAPERCLIP_EVENTS, eventName)` guard
at the entry point of `track()` to swallow unregistered calls before any
side effects, adds `scripts/extract-proposed-events.mjs` to scan source
for proposal markers and emit a v2 JSON manifest with provenance and
rationale, and documents the complete proposal workflow
> - The benefit is that new instrumentation can be proposed and reviewed
in code without touching the registered schema, and tooling can surface
missing rationale before events graduate to stable

## Linked Issues or Issue Description

No existing GitHub issue covers this change. This PR introduces a new
feature.

**Feature motivation:** Paperclip's telemetry schema is intentionally
stable — registered event names are code-generated and gated. Product
engineers who want to instrument a new behaviour today must land a
schema change first, creating a two-step process that slows iteration. A
proposal lane lets developers write the instrumentation call ahead of
schema registration, protected by a compile-time `@ts-expect-error`
marker that an extractor script can surface for review. This PR
implements both the client-side safety gate and the extraction tooling.

Refs: #9518 (closed predecessor — docs-only; this PR supersedes it with
the full implementation)

## What Changed

- Added `Object.hasOwn(PAPERCLIP_EVENTS, eventName)` guard at the top of
`TelemetryClient.track()`: unregistered event names (including
prototype-inherited keys) are now swallowed before any state, queue, or
network operation
- Added `scripts/extract-proposed-events.mjs`: scans TypeScript source
for `@ts-expect-error -- proposed-telemetry(<issue>): <rationale>`
markers; emits a v2 JSON manifest per proposed event including name,
rationale, provenance (repo-relative file + line), and a
`rationale_missing` flag for CI enforcement
- Added `scripts/extract-proposed-events.test.mjs`: test suite covering
marker parsing, multi-line markers, path validation, out-of-repo
rejection, and the v2 schema output contract
- Added `doc/TELEMETRY_WORKFLOW.md`: documents the proposal workflow,
the canonical multi-line marker example, rationale requirements, and how
to graduate a proposed event to stable schema
- Updated `packages/shared/src/telemetry/README.md`: added "Proposed
Events" section to the Telemetry Data Contract per the contributing
guide requirement for telemetry changes

## Verification

Run all of the following from the repo root:

```sh
# Extractor unit tests
node --test scripts/extract-proposed-events.test.mjs

# Telemetry client + types tests
pnpm exec vitest run --config vitest.config.ts \
  src/telemetry/client.test.ts src/telemetry/client-types.test.ts \
  --reporter=verbose
# (run from packages/shared)

# Type-check
pnpm --filter @paperclipai/shared typecheck

# Smoke-run the extractor in local-test mode
node scripts/extract-proposed-events.mjs --ref local-test
```

All four commands pass locally.

## Risks

- **Silent drop on unregistered events:** The `Object.hasOwn` guard
fails closed — any event name not in `PAPERCLIP_EVENTS` is silently
dropped. If the generated registry is missing an event that was
previously tracked, those calls will be silently lost. Mitigation: the
extractor script surfaces proposed events that need registration; the
TypeScript type system already enforces `TelemetryEventName ⊆
PAPERCLIP_EVENTS` at compile time.
- **Extractor is read-only:** `extract-proposed-events.mjs` reads source
and emits JSON; it does not modify any files. No runtime or schema risk.
- Overall risk: **low**. The guard is additive and defensive; the
extractor and docs are additive only.

## Model Used

- Provider: Anthropic
- Model ID: `claude-sonnet-4-6`
- Context window: 200 K tokens
- Capabilities: tool use, extended context, code generation

## Checklist

- [x] I have included a thinking path that traces from project context
to this change
- [x] I have specified the model used (with version and capability
details)
- [x] I have checked ROADMAP.md and confirmed this PR does not duplicate
planned core work
- [x] I have searched GitHub for duplicate or related PRs and linked
them above
- [x] I have either (a) linked existing issues with `Fixes: #` / `Closes
#` / `Refs #` OR (b) described the issue in-PR following the relevant
issue template
- [x] I have not referenced internal/instance-local Paperclip issues or
links (only public GitHub `#NNN` / `github.com/paperclipai/paperclip`
URLs)
- [x] My branch name describes the change (e.g. `docs/...`, `fix/...`)
and contains no internal Paperclip ticket id or instance-derived details
- [x] I have run tests locally and they pass
- [x] I have added or updated tests where applicable
- [x] I have updated relevant documentation to reflect my changes
- [x] I have considered and documented any risks above
- [ ] All Paperclip CI gates are green
- [ ] Greptile is 5/5 with no open P2s, recommendations, or follow-ups
- [x] I will address all Greptile and reviewer comments before
requesting merge

---------

Co-authored-by: Paperclip <noreply@paperclip.ing>
2026-07-13 23:47:27 -07:00
1b16f9611c feat(telemetry): document credential health retention (#9248)
## Thinking Path

> - Paperclip is the open source app people use to manage AI agents for
work
> - The shared telemetry package (`packages/shared/src/telemetry`)
defines the public contract for first-party telemetry events — event
names, dimension shapes, and now retention windows
> - A new telemetry event, `codex.credential_health`, carries
credential-observability fields (enums, booleans, counts, coarse
buckets) — no token material and no PII
> - The retention window for this event and its class was undocumented
at the contract level, leaving data-infra and reviewers without a
discoverable source of truth
> - This pull request adds `retention.ts` as the canonical
retention-contract surface, assigns `codex.credential_health` to the
`operational_enum_count` class (90-day window), exports the contract
from the shared package, and updates the README
> - The benefit is that the retention window is discoverable from the
event definition rather than being implicit pipeline knowledge, and the
no-token/no-PII note is locked in a contract test rather than relying on
prose

## Issue Description

No public GitHub issue exists for this change. Inline description
follows the [feature request
template](.github/ISSUE_TEMPLATE/feature_request.yml):

### Problem or motivation

`packages/shared/src/telemetry/` applies a 90-day retention window to
`codex.credential_health` events at the pipeline level, but this policy
is not stated anywhere in the shared telemetry contract. Without a
discoverable retention declaration, reviewers and data-infra must read
pipeline configuration to understand retention behaviour — there is no
contract-level source of truth. The `codex.credential_health` event
carries only enums, booleans, counts, and coarse buckets — no token
material and no PII.

### Proposed solution

Add a `retention.ts` module to the shared telemetry package that defines
the `operational_enum_count` retention class (90-day window) and maps
`codex.credential_health` to it. Export the contract from the package
index and add a focused contract test. Update the README with a
Retention section and a pointer in the Public Sources table. This is
additive documentation only — no runtime paths change.

### Alternatives considered

Keep retention implicit in pipeline configuration only. Rejected: this
leaves no discoverable, versioned contract for reviewers or data-infra,
and means every consumer must read pipeline config to understand
retention semantics. A schema-level declaration is the correct long-term
home.

### Roadmap alignment

Aligns with the telemetry contract hardening track — making implicit
operational knowledge explicit and testable at the shared-package level.

## What Changed

- **`packages/shared/src/telemetry/retention.ts`** (new): defines
`RETENTION_DAYS` (class → days) and `EVENT_RETENTION_CLASS` (event name
→ class). `operational_enum_count` is the only class: 90-day window for
enum/count/bucket events with no token material or PII.
`codex.credential_health` is the first entry. The `string` key type is
intentional to accommodate cross-system events (e.g. the Codex CLI) not
yet promoted to the first-party `PaperclipEventName` schema.
- **`packages/shared/src/telemetry/retention.test.ts`** (new): three
focused assertions — `operational_enum_count` is 90 days,
`codex.credential_health` is assigned that class, and the resolved
window is 90 days.
- **`packages/shared/src/telemetry/index.ts`**: exports
`RETENTION_DAYS`, `EVENT_RETENTION_CLASS`, and `RetentionClass` from the
shared package.
- **`packages/shared/src/telemetry/README.md`**: adds `retention.ts` to
the Public Sources table and a new Retention section with a class
reference table and guidance for future assignments.

## Verification

- `git diff --check` passes (no whitespace errors)
- `pnpm --filter @paperclipai/shared exec vitest run
src/telemetry/retention.test.ts src/telemetry/readme-contract.test.ts` —
runs the new contract tests and the existing readme-contract test
- `pnpm --filter @paperclipai/shared typecheck` — confirms the new
exports compile cleanly
- CI gates green

## Risks

Low risk. This is a documentation-only addition:
- No new telemetry event, dimension, emitter, or schema change
- No runtime code paths changed
- The new file is tree-shaken away in any consumer that doesn't import
from it
- `satisfies Record<string, number>` on `RETENTION_DAYS` ensures the
type stays correct as new classes are added

## Model Used

Claude Sonnet 4.6 (`claude-sonnet-4-6`) — Anthropic, 200k context
window, tool use enabled, no extended thinking mode. Used for code
authoring and PR composition.

## 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: Harold Kim <harold.kim@paperclip.ing>
Co-authored-by: Paperclip <noreply@paperclip.ing>
Co-authored-by: Harold Kim <harold-kim@paperclip.ing>
2026-07-08 21:27:39 -07:00
Devin FoleyandPaperclip eedc7ddef2 Make ACP the default engine for local adapters (#9238)
## Thinking Path

> - Paperclip is the open source app people use to manage AI agents for
work.
> - Adapter packages are the bridge between the control plane and local
agent harnesses such as Claude Code, Codex, and Gemini CLI.
> - ACP support was concentrated in a separate `acpx_local` adapter,
which made ACP feel like a separate agent choice instead of an execution
capability of the harness adapters.
> - Claude, Codex, and Gemini now have ACP-capable harnesses, so the
native adapter should own ACP selection, fallback, config, transcript
parsing, and environment diagnostics.
> - The standalone ACPX adapter still needs a compatibility path for
existing rows, but it should not be offered as an active adapter for new
agents.
> - This pull request moves the shared ACP runtime into
`@paperclipai/acpx-engine`, wires Claude/Codex/Gemini local adapters to
prefer ACP when prerequisites are available, and retires `acpx_local` to
a tombstone.
> - The benefit is one adapter per harness, richer ACP transcripts by
default where possible, and a migration path for existing Claude/Codex
ACPX agents.

## Linked Issues or Issue Description

Closes #5932 — the broken default `acpx_local` Claude path is replaced
by native `claude_local` ACP support, existing Claude/Codex ACPX rows
migrate to native adapters, and new agents no longer choose the
standalone ACPX adapter.

Refs #4893 — original merged ACPX local adapter runtime that this PR
replaces with native per-harness ACP engines.
Refs #6590 — prior ACPX-Claude seamlessness work folded into the new
native Claude ACP path.
Refs #197 — related open generic ACP/Kiro adapter work; this PR does not
close it because Kiro/custom generic ACP remains a separate adapter
decision.
Refs #7018 — related Kimi-specific `acpx_local` shell failure; this PR
retires the built-in standalone adapter but does not add a native Kimi
adapter.
Refs #8864 — related ACPX prompt/API guidance PR; this PR moves runtime
guidance into the shared/native ACP engine path instead of the old
standalone adapter.
Refs #8881 — related `acpx_local` POSIX shell failure from the old
`acpx` pin; this PR updates ACP dependencies but does not claim
custom/OMP ACP support as a first-class native adapter.
Refs #8964 — related open `acpx_local` stderr cleanup PR; this PR makes
the old runtime path obsolete for new agents but keeps it as a
non-closing reference.

Problem description:

- The standalone `acpx_local` adapter duplicates Claude/Codex agent
choices that already have first-class local adapters.
- ACP should be an execution engine capability of each harness adapter
when the underlying harness supports ACP.
- Existing `acpx_local` agents should either migrate to native harness
adapters or fail with an explicit retirement message instead of silently
falling back to the process adapter.

## What Changed

- Added `@paperclipai/acpx-engine` as the shared ACP execution,
session-codec, CLI formatter, and UI parser package.
- Wired `claude_local`, `codex_local`, and `gemini_local` to auto-select
ACP by default when prerequisites pass, with `engine=cli` opt-out and
`engine=acp` strict mode.
- Added ACP config schema/UI fields, environment checks, session-codec
preservation, transcript parsing, and adapter capability metadata for
the native adapters.
- Retired `acpx_local` to a server tombstone, removed its
UI/package/runtime image surface, and added a migration for existing
Claude/Codex ACPX agents.
- Updated package manifests, lockfile, release tooling, docs, Kubernetes
sandbox defaults, and tests.

## Verification

- `corepack pnpm --filter @paperclipai/acpx-engine typecheck`
- `corepack pnpm --filter @paperclipai/adapter-claude-local typecheck`
- `corepack pnpm --filter @paperclipai/adapter-codex-local typecheck`
- `corepack pnpm --filter @paperclipai/adapter-gemini-local typecheck`
- `corepack pnpm --filter @paperclipai/acpx-engine exec vitest run`
- `corepack pnpm --filter @paperclipai/adapter-claude-local exec vitest
run src/server/acp.test.ts src/server/execute.acp-fallback.test.ts
src/ui/build-config.test.ts`
- `corepack pnpm --filter @paperclipai/adapter-codex-local exec vitest
run src/server/acp.test.ts src/ui/build-config.test.ts`
- `corepack pnpm --filter @paperclipai/adapter-gemini-local exec vitest
run src/server/acp.test.ts src/ui/build-config.test.ts
src/ui/parse-stdout.test.ts`
- `corepack pnpm --filter @paperclipai/plugin-sdk ensure-build-deps &&
corepack pnpm --filter @paperclipai/server exec tsc --noEmit`
- `corepack pnpm --filter @paperclipai/server exec vitest run
src/__tests__/adapter-routes.test.ts
src/__tests__/adapter-session-codecs.test.ts
src/__tests__/adapter-models.test.ts`
- `corepack pnpm --filter @paperclipai/ui typecheck`
- `corepack pnpm --filter @paperclipai/ui exec vitest run
src/adapters/metadata.test.ts
src/adapters/adapter-display-registry.test.ts
src/components/AgentConfigForm.test.ts
src/components/AgentConfigForm.render.test.tsx
src/components/transcript/RunTranscriptView.test.tsx`
- `node --test scripts/bootstrap-npm-package.test.mjs
scripts/release-package-map.test.mjs
scripts/verify-release-registry-state.test.mjs`

Note: the server typecheck script calls `pnpm` internally; this dev
shell exposes pnpm through Corepack only, so I ran the two script steps
manually with `corepack pnpm`.

## Risks

- Migration changes existing `acpx_local` Claude/Codex agents to native
adapter types and clears old ACPX task sessions/runtime state.
- Custom ACP commands remain on the retired tombstone and will need a
separate future adapter/plugin path.
- ACP auto-selection depends on local Node and ACP server command
prerequisites; remote and unsupported environments fall back to CLI
unless `engine=acp` is explicit.
- `@paperclipai/acpx-engine` is a new public package and needs npm
trusted-publishing bootstrap before release automation can publish it.

> 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 via Codex coding agent. Exact hosted model build and
context-window size are not exposed in this runtime. Tool use included
shell execution, repository editing, GitHub CLI operations, and local
test/typecheck execution.

## Checklist

- [x] I have included a thinking path that traces from project context
to this change
- [x] I have specified the model used (with version and capability
details)
- [x] I have checked ROADMAP.md and confirmed this PR does not duplicate
planned core work
- [x] I have searched GitHub for duplicate or related PRs and linked
them above
- [x] I have either (a) linked existing issues with `Fixes: #` / `Closes
#` / `Refs #` OR (b) described the issue in-PR following the relevant
issue template
- [x] I have not referenced internal/instance-local Paperclip issues or
links (only public GitHub `#NNN` / `github.com/paperclipai/paperclip`
URLs)
- [x] My branch name describes the change (e.g. `docs/...`, `fix/...`)
and contains no internal Paperclip ticket id or instance-derived details
- [x] I have run tests locally and they pass
- [x] I have added or updated tests where applicable
- [x] I have updated relevant documentation to reflect my changes
- [x] I have considered and documented any risks above
- [x] All Paperclip CI gates are green
- [x] Greptile is 5/5 with no open P2s, recommendations, or follow-ups
- [x] I will address all Greptile and reviewer comments before
requesting merge

---------

Co-authored-by: Paperclip <noreply@paperclip.ing>
2026-07-08 19:05:03 -07:00
Nicky LeachandPaperclip 69c55d465d Add telemetry data contract docs (#8886)
Adds the public telemetry data contract README, links it from contributor docs, and adds a focused README contract test for generated helper names.

Verification:
- git diff --check origin/master..HEAD
- pnpm exec vitest run packages/shared/src/telemetry/readme-contract.test.ts
- PR CI green
- Greptile 5/5

Co-Authored-By: Paperclip <noreply@paperclip.ing>
2026-07-02 12:38:03 -07:00
Nicky LeachandPaperclip 3522b1c9be Emit interaction resolved telemetry (#8824)
## Thinking Path

> - Paperclip is the open source app people use to manage AI agents for
work
> - Issue-thread interactions are how agents ask users or the board for
decisions and structured input
> - Product telemetry needs to understand when those interactions
resolve without exposing private interaction content
> - Resolution currently happens through several service paths, so
telemetry needs to be emitted consistently from the terminal transitions
> - The interaction service should describe the resolved interaction,
while the telemetry backend owns unknown-value normalization for
dimensions
> - This pull request emits `interaction.resolved` after successful
database writes and removes redundant client-side normalization from the
service
> - The benefit is aggregate-safe telemetry for interaction completion
behavior without leaking raw IDs, answer text, rejection reasons, or
document content

## Linked Issues or Issue Description

No public GitHub issue exists for this internal telemetry follow-up.

Feature context:

- Problem/motivation: Paperclip needs aggregate product telemetry for
issue-thread interaction resolution outcomes while preserving privacy
boundaries around user answers and internal identifiers.
- Proposed solution: Emit `interaction.resolved` once from terminal
interaction resolution paths, passing runtime dimensions through the
shared telemetry helper while preserving aggregate-safe counts and
ID/free-text omission.
- Alternatives considered: Normalizing interaction dimensions in the
interaction service duplicated telemetry backend responsibility and made
unknown-value handling inconsistent across telemetry clients.
- Roadmap alignment: This is a focused telemetry instrumentation
follow-up that builds on the generated telemetry event types from #8818.

## What Changed

- Wires `interaction.resolved` telemetry into terminal issue-thread
interaction resolution paths after successful database writes.
- Passes raw interaction kind, status, continuation policy, resolution
reason, target type, and creator agent role values to the shared
telemetry helper instead of maintaining service-local allowlists.
- Preserves resolver classification, target `none` derivation for
non-confirmation interactions, non-negative aggregate counts, raw ID
omission, and free-text omission.
- Logs telemetry failures without blocking interaction resolution.
- Adds service-level tests for accepted, rejected, answered,
stale-target expiry, superseded-comment expiry, and raw creator-role
pass-through payloads.

## Verification

- `pnpm run preflight:workspace-links && pnpm exec vitest run
server/src/__tests__/issue-thread-interactions-telemetry.test.ts
server/src/__tests__/shared-telemetry-events.test.ts`
- `pnpm typecheck`
- GitHub PR checks on the latest head commit are green, including
`verify`, build, e2e, general tests, serialized server suites, security
scans, and Greptile Review.
- Security code review completed before this branch update.

## Risks

- Low operational risk: telemetry is emitted after successful
persistence and telemetry failures are logged without blocking the
user-visible interaction flow.
- Main behavioral risk is duplicate or missing telemetry from a
resolution path; the focused tests cover the terminal resolution
variants.
- Telemetry dimension normalization now depends on the shared telemetry
backend path instead of the interaction service, so backend
normalization must remain the source of truth for unknown or empty
dimension values.
- The existing PR branch name contains an internal task id because this
update continues an already-open PR branch instead of opening a
replacement PR.

## Model Used

OpenAI GPT-5 Codex coding agent, API-based coding environment with
shell, repository, and GitHub CLI tool use. Context window size was not
reported 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)
- [ ] 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>
2026-07-01 13:43:11 -07:00
Nicky LeachandPaperclip 8a93a0de4c Implement generated client telemetry types (#8818)
## Thinking Path

> - Paperclip is the open source app people use to manage AI agents for
work.
> - Telemetry is part of the control plane's operational visibility and
needs stable event contracts.
> - The shared telemetry client accepted first-party event names through
a broad string surface, which weakened compile-time guarantees.
> - Plugin telemetry still needs a dynamic path because plugin-defined
events cannot be enumerated in the core generated type module.
> - This pull request vendors generated Paperclip telemetry event and
dimension types, closes the first-party event-name union, and keeps
plugin telemetry on an explicit dynamic method.
> - Review feedback clarified that backend normalization should remain
the source of truth, so telemetry helpers now preserve raw categorical
values while keeping generated per-event type hints.
> - The benefit is stricter first-party telemetry typing without hiding
backend normalization signals or changing batching, flushing, schema
versioning, sinks, or endpoints.

## Linked Issues or Issue Description

No public GitHub issue exists for this internal type-contract
maintenance change.

### Problem or motivation

The shared telemetry client should reject unregistered first-party event
names at compile time, while the plugin telemetry bridge must continue
to emit plugin-defined events through the existing batching and envelope
path. Helper wrappers should also avoid client-side enum coercion so the
backend can detect and record normalization when clients send unexpected
categorical values.

### Proposed solution

Generate and vendor the accepted Paperclip telemetry event and dimension
types, use those types for the first-party `track()` API, keep
plugin-defined telemetry on an explicit dynamic method, and let helper
wrappers pass raw categorical dimensions through to backend validation.

### Alternatives considered

Keeping `track()` open to arbitrary strings would preserve flexibility,
but it would not give first-party callers the type safety this change is
meant to provide. Enumerating plugin events in core was also ruled out
because plugin-defined events are not known to the core package.
Client-side enum normalization was removed after review because it
duplicates backend validation and can hide misbehaving-client signals.

### Roadmap alignment

This is a tightly scoped telemetry contract maintenance change and does
not overlap with a roadmap-level core feature.

## What Changed

- Vendored the generated Paperclip telemetry event and dimension type
module under shared telemetry code.
- Closed the first-party telemetry event-name union to generated
backend-accepted names plus an explicit `RegisteredPluginEventName =
never` extension point.
- Added `TelemetryClient.trackDynamic()` for plugin telemetry bridge
emission while keeping `track()` closed and typed.
- Added JSDoc explaining when to use `track()` versus `trackDynamic()`.
- Updated telemetry helper wrappers to type dimensions from each event's
generated schema entry while passing raw categorical values through for
backend normalization.
- Added `trackInteractionResolved()` and updated focused shared/server
tests for telemetry event typing, raw pass-through behavior, and plugin
telemetry bridging.

## Verification

Local verification passed before the latest push:

- `pnpm --filter @paperclipai/shared typecheck`
- `pnpm --filter @paperclipai/server typecheck`
- `pnpm exec vitest run
packages/shared/src/telemetry/client-types.test.ts
server/src/__tests__/shared-telemetry-events.test.ts
server/src/__tests__/plugin-telemetry-bridge.test.ts
server/src/__tests__/project-goal-telemetry-routes.test.ts
server/src/__tests__/routine-run-telemetry.test.ts
server/src/__tests__/issue-telemetry-routes.test.ts`
- `git diff --check`

Post-push verification completed on head
`3d973ffbea6154b19ad208dcffd1374d1b25b654`:

- GitHub PR checks passed, including `verify`, build, typecheck/release
registry, general test shards, serialized server shards, canary dry run,
e2e, and security checks.
- Greptile Review passed with 5/5 confidence.
- All PR review threads are resolved.

## Risks

Low runtime risk. The change is intended to affect TypeScript contracts
and helper typing while preserving the existing telemetry enqueue,
batching, and backend ingest path. The main intentional behavior shift
is that helper wrappers no longer coerce unexpected categorical values
on the client; those values reach the backend so backend normalization
can record the signal. Private company import source refs still use
`hashPrivateRef` when `isPrivate` is true.

## Model Used

OpenAI GPT-5 Codex, tool-enabled coding agent. Exact context window was
not exposed by the runtime; the agent used repository file access, shell
commands, and GitHub CLI operations.

## 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>
2026-07-01 11:39:39 -07:00
DottaandPaperclip 7f893ac4ec [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
Dotta c566a9236c fix: harden heartbeat and adapter runtime workflows 2026-04-10 22:26:21 -05:00
dottaandPaperclip 37b6ad42ea Add versioned telemetry events
Co-Authored-By: Paperclip <noreply@paperclip.ing>
2026-04-03 09:25:00 -05:00
dotta af844b778e Add plugin telemetry bridge capability
Expose telemetry.track through the plugin SDK and server host bridge, forward plugin-prefixed events into the shared telemetry client, and demonstrate the capability in the kitchen sink example.\n\nCo-Authored-By: Paperclip <noreply@paperclip.ing>
2026-04-02 10:47:29 -05:00
dottaandPaperclip 53dbcd185e fix: align telemetry client payload and dimensions with backend schema
Restructure the TelemetryClient to send the correct backend envelope
format ({app, schemaVersion, installId, events: [{name, occurredAt, dimensions}]})
instead of the old per-event format. Update all event dimension names
to match the backend registry (agent_role, adapter_type, error_code, etc.).

Co-Authored-By: Paperclip <noreply@paperclip.ing>
2026-04-02 10:47:29 -05:00
dottaandPaperclip f16de6026d fix: add periodic flush and graceful shutdown for server-side telemetry
The TelemetryClient only flushed at 50 events, so the server silently
lost all queued telemetry on restart. Add startPeriodicFlush/stop methods
to TelemetryClient, wire up 60s periodic flush in server initTelemetry,
and flush on SIGTERM/SIGINT before exit.

Co-Authored-By: Paperclip <noreply@paperclip.ing>
2026-04-02 10:47:29 -05:00
dottaandPaperclip 34044cdfce feat: implement app-side telemetry sender
Add the shared telemetry sender, wire the CLI/server emit points,
and cover the config and completion behavior with tests.

Co-Authored-By: Paperclip <noreply@paperclip.ing>
2026-04-02 10:47:29 -05:00