Commit Graph
4 Commits
Author SHA1 Message Date
DottaandPaperclip 0dedbf23c3 fix(chat): retain receiver ownership during runtime construction (#18930)
## Thinking Path

> - Paperclip manages agents and their work.
> - Chat receivers hold a durable lease before they accept messages.
> - Runtime construction can outlast a lease renewal interval.
> - Renewal previously required an attached runtime before construction
had returned.
> - That check could revoke the same receiver that was still starting.
> - This change uses the exact pending initialization as proof during
construction.
> - The existing durable token and endpoint checks still fence every
renewal.

## Linked Issues or Issue Description

Related: #18899 exposed the existing receiver failure in its chat CI
shard. This is a separate lifecycle repair. #18795 provides the relevant
production and sleep fixture context. Searches found no overlapping open
initialization repair.

**What happened?**

The receiver acquired its lease and started its renewal timer. The
service then awaited credentials, command preparation and runtime
construction before attaching the runtime to its context. A renewal
during that interval treated the missing attachment as lost ownership.
Configuration later failed with a Gateway ownership error, although its
original durable token was still current.

**Expected behavior**

The exact pending initialization can retain its own lease while
construction runs. Missing attachment alone must grant no ownership. A
changed token, paused or removed endpoint, changed generation or
credentials, and shutdown must still fence the receiver.

**Steps to reproduce**

1. Use the real configure and PostgreSQL ownership producers with a
60-second lease and 50-millisecond renewal.
2. Hold the actual runtime construction call for 200 milliseconds.
3. Release construction. Untouched code returns the Gateway ownership
error.
4. With the same construction delay and a five-second renewal control,
configuration succeeds.

**Paperclip version or commit**

The causal regression fails on unchanged production source at
`e7549ab613`. The original CI error was observed in the chat shard of
#18899. That CI run did not record the precise setup and renewal order,
so this local proof does not establish its historical scheduling.

## What Changed

- Store the runtime context identity in the existing pending
initialization entry.
- Allow pre-attachment renewal only for that exact tracked
initialization and current local ownership.
- Recheck local ownership inside the existing renewal transaction.
Preserve company, endpoint, generation, credential and original-token
checks.
- Before SDK listener initialization, wait for any older renewal,
recheck local ownership, then obtain fresh durable proof. Preserve the
existing checks after initialization.
- Keep attached runtime identity checks, lease deadlines, renewal
intervals, shutdown and listener retirement unchanged.
- Add actual configure and database race controls. Document the shared
Discord and Photon receiver contract.

## Verification

- Untouched production red: the actual construction gate crosses a
renewal and returns the same Gateway ownership error. The otherwise
identical slower-renewal control passes. No lease, exception or provider
outcome is injected in these positive cases.
- A subsequent review found a second real race: final runtime removal
did not prove that SDK initialization had never started. Four actual
initialization-hook controls failed before the pre-initialize fence. The
final matrix asserts zero hook calls for lost or changed authority,
including a foreign-token control with no periodic renewal due. An
attempted cross-company endpoint move is rejected by the existing
database foreign key; the valid original initialization still succeeds.
- A third actual-producer red holds completion of a real committed
renewal, changes the durable token, and proves that joining that old
promise could incorrectly accept configuration. The corrected startup
check waits for that renewal and then obtains fresh proof; it cannot
credit the earlier result alone.
- Final relevant full Discord registration group, takeover/callback
cases, buffered host-pause recovery, failed construction,
credential-fenced pause and shared Photon consumers: 34 passed across
two files; 1,840 other cases were deselected. Four executed cases cover
Photon transport recovery, failed authentication, duplicate allocation
ownership and checkpoint fencing. The tests use the real
configure/database producers with fake provider transports and observe
SDK initialization; they do not prove physical network behavior.
- All server type layers, the module-boundary gate, and production
server/vendored Runner build pass at exact final
`38cf82ec114bd12c0aa7bbc125ed72b1ae941b4e`. The production build stamp
records this exact commit.
- Earlier fixture mistakes are preserved separately: a test initially
changed every lease key, including the credential lease, and another
attempted an invalid cross-company row move. Neither is counted as a
production behavior red. The corrected controls target the Gateway key
and assert the existing company constraint.
- An initial isolated dependency graph resolved an older shared
telemetry build. Correct workspace links restored the all-layer
typecheck without changing telemetry source.
- Full repository checks were not run locally for this narrow slice.
Fresh current-head CI and substantive reviews remain required. No hosted
task, provider work, fleet action or deployment was performed.

## Risks

The ownership helper is shared by Discord and Photon. The selected tests
cover both consumers. The pending entry grants only permission to renew
the original token; it grants no message, callback or publication
authority and adopts no listener. Missing or changed initialization
identity fails closed. There is no schema change, historical backfill,
new worker or additional idle scan.

## Model Used

OpenAI `gpt-6.1-sol` in Codex, with reasoning, repository inspection,
source editing, shell execution and test tools. The host did not report
the context-window size. A separate coordinator reviews the source
before delivery.

## 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-11-03 22:57:39 -06:00
DottaandPaperclip dce0042593 fix(server): wake chat receiver discovery from configuration and lease deadlines (#17572)
## Thinking Path

> - Paperclip is the open source app people use to manage AI agents for
work.
> - Chat receivers own persistent provider connections and fenced
database leases.
> - The chat maintenance timer repeatedly queries all eligible
receivers, including when none exist.
> - Configuration changes and known lease deadlines already identify
when discovery is needed.
> - This pull request moves receiver discovery to the shared delivery
coordinator.
> - Empty or settled discovery stops querying, while ownership and
recovery remain explicit.

## Linked Issues or Issue Description

Refs #17557. This is the next stacked slice after Discord command
registration. The base is `codex/sleep-19-discord-command-registration`.

**What happened?**
The recurring chat maintenance lane scans receiver inventory and
reconciles Discord and Photon runtimes even when configuration has not
changed.

**Expected behavior**
Reconstruct receiver work at startup. React to committed configuration
changes and local listener retirement. Retry foreign ownership at the
saved lease expiry. Stop discovery when there is no remaining
obligation.

**Steps to reproduce**
Start an instance with no chat endpoints. Let startup finish. Observe
the recurring receiver inventory query from chat maintenance. With a
configured receiver, remove its ownership token while listener shutdown
is delayed and signal a configuration refresh: the old implementation
can replace the listener before shutdown completes.

## What Changed

- Preserve healthy receiver progress after a slow failed batch while
retaining per-receiver retry backoff.

- Register a receiver discovery worker with scoped refreshes, paged
startup inventory, fair batches, and per-receiver or scope failure
backoff.
- Keep owned receiver identities cached without a discovery deadline, so
deletion still stops their listeners.
- Use existing transaction signals for configuration, credentials,
health, access revocation, company deletion, and provider lifecycle
changes. Rename the generic command-only helper to describe its broader
configuration contract.
- Keep lease-key selection with the receiver owner. Shared scheduling
contains no provider protocol.
- Retain stopping ownership until listener shutdown and lease release
complete. Concurrent acquisition joins the existing stop promise.
- Remove receiver discovery from the periodic chat lane. Preserve voice
and the other unmigrated duties.
- Record producer coverage, failure evidence, limits, and remaining work
in `doc/plans/2026-10-25-chat-receiver-discovery-sleep-audit.md`.

## Verification

Published head: `ab39569250f4b699a0ab7a829e66dbe27c15020b`. Discord
#17557 has landed at master `5bf0142d45`. A normal merge reconciles its
squash ancestry by applying only the recorded 27-file receiver patch
from parent `547fdf2139`. Every other path matches that master. Every
server and package production/test file is byte-identical to the
published `6e88ca0201` source that passed the 131-case run, typecheck
and build. Unrelated upstream UI/eval/documentation changes are
preserved. This PR targets master. Fresh exact-head reviews and CI are
required.

- **131 distinct targeted cases pass.** Five complete receiver,
coordinator, batching, startup, and GitHub health error-projection
suites pass 99 cases. Twelve real Discord
automatic-registration/receiver and Slack held-transaction cases pass
separately, with 1,581 other chat integration cases deselected. The
complete Photon channel suite passes 20 cases.
- The standalone receiver and Photon fixtures each reproduced
missing-table failures on separate initially empty PostgreSQL 17
databases. Both now apply pending migrations before client use; their
complete 20-case files pass on those same databases. The large chat
producer suite uses a separate migrated clone.
- The old review concerns already have source fixes: discovery stops
suppress their own completion wake at `1604a9fcba`; slow failed batches
supply `nextRunAtOnError` at `ab56393acc`. Guarded mutations prove the
existing regressions: reenabling the stop wake yields two inventory
reads instead of one, and removing the error deadline fails the 1,100 ms
provider-delay next-wake assertion. Both original source files are
restored byte for byte. Normal full worker and real producer suites pass
with those fixes.
- All 131 distinct targeted cases, production server typecheck and build
pass on source `6e88ca0201`. Exact source comparison carries that
evidence to this normal merge; the unchanged suites were not rerun just
for unrelated upstream changes. Receiver and Photon fixtures
self-migrate separate initially empty databases; the large producer
fixture uses its own migrated clone. Source is unchanged after these
checks. Recorded listener-count warnings and controlled provider failure
logs remain; no assertion was weakened. An initial whole-file identity
check rejected expected parent queue additions; precise patch comparison
confirms those declarations are correctly preserved.
- Old server shard 12 failed because GitHub reports that its self-hosted
runner lost communication. The grouped-test step is cancelled, and the
retained log has no failing assertion or completed summary. The
underlying host/resource/network cause is unproven. That interrupted job
is not a pass; the updated parent and fixture source require a fresh
full CI run.
- [Current acceptance and failure
record](https://github.com/paperclipai/paperclip/blob/ab39569250f4b699a0ab7a829e66dbe27c15020b/doc/plans/2026-10-25-chat-receiver-discovery-sleep-audit.md#compatibility-after-discord-squash-merge-october-27).
Prior 218-case and full-workspace results describe earlier revisions. No
full local repository-suite, multi-writer deployment, Cloud wake, host
suspension, or fleet cost claim is made.

## Risks

- Process-local transaction hints cover the active database owner and
its shared clients. Arbitrary direct SQL or independent configuration
writers need explicit wake integration. Startup/resume reconstruction
and known foreign-lease takeover remain supported; this does not add
general multi-writer discovery.
- Active receiver sockets and lease renewals continue. This change does
not prove host suspension or extend Cloud alarm coverage.
- Configuration signals can arrive during drain, initialization, or
shutdown. The worker preserves dirty scopes and the owner joins listener
retirement before replacement.
- Voice, Teams, milestone projection, publication maintenance, GitHub
recovery, and the remaining stack inventory are separate work.
- The Discord parent has landed and the receiver child now targets
master. Fresh exact-head reviews and all CI must pass before merge.

## Model Used

OpenAI GPT-6 via Codex, with repository inspection, code execution, and
test tools. The runtime does not expose a more specific deployment
identifier or context-window limit.

## Checklist

- [x] I have included a thinking path that traces from project context
to this change
- [x] I have specified the model used (with version and capability
details)
- [x] I have checked ROADMAP.md and confirmed this PR does not duplicate
planned core work
- [x] I have searched GitHub for duplicate or related PRs and linked
them above
- [x] I have either linked existing issues or described the issue in-PR
following the relevant issue template
- [x] I have not referenced internal/instance-local Paperclip issues or
links
- [x] My branch name describes the change and contains no internal
ticket identifier
- [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-10-28 07:25:20 -05:00
DottaandPaperclip 09a2f0b7b0 refactor(server): isolate provider message admission and runtime policies (#16289)
## Thinking Path

> - Paperclip helps people manage AI agents for work.
> - Chat channels turn external messages into shared task workflows.
> - The main service still contains some provider decisions.
> - These decisions belong with the existing channel modules.
> - This pull request isolates provider message-admission and runtime
policies.
> - Shared authorization, persistence, and runtime ownership keep their
current order.

## Linked Issues or Issue Description

Refs: #16235. Stack part 3/3. Base: `master`. #16276 and #16283 are
merged.

**What existing behavior does this improve?**

Provider ownership and readability in the chat channel service.

**Current behavior**

The entry point combines shared workflows with provider decisions.

**Proposed behavior**

Provider modules own their decisions. Shared modules own product state
and authorization.

**Reason and benefit**

Maintainers can find provider behavior in its channel folder.

**Breaking changes**

None intended. Public service methods and durable data shapes stay
compatible.

## What Changed

- Move Discord SDK admission and its barrier to the Discord message
module.
- Move Photon live-message eviction and startup recovery policy to its
runtime callbacks module.
- Move Slack mention eligibility and Teams setup-channel eligibility to
their message modules.
- Keep Photon deferred ingress and Speko conversation policy with their
provider modules.
- Keep ordered SDK message batching in a shared runtime module with a
live per-message ingress callback.
- Keep receiver leases, cache lifetime, startup failure cleanup,
authorization locks, and transaction ownership shared.
- Reduce `chat-channels.ts` from 3,570 to 3,548 lines.

## Verification

- The same 46 runtime/admission integration cases and all 18 Photon
channel cases passed before and after in the owned Linux container.
- The existing first-channel Teams orphan-admission case passed before
and after moving its eligibility predicate.
- The same 94 SDK adapter and lifecycle-normalization tests passed
locally.
- Server typecheck and module-boundary checks passed.
- Token comparison confirms ordered SDK batching and every processor
argument, plus Photon invalidation and its live runtime lookup.
- The shared factory creates no cache or worker. It reads the ingress
policy for each message and awaits processing in order.
- The extraction rebased without conflicts onto master after #16276 and
#16283 merged. Git range-diff reports the same patch. Final head
`7b63b569e2a0dbcc959310f565f77f367fa64aa0` has the same patch by
range-diff. The 94 SDK/lifecycle tests, server typecheck, and boundary
check passed on the final head. All CI gates pass on that exact head.
Greptile reviewed it at 5/5 with no inline findings or unresolved review
threads.
- One Runner CI test failed its original short timing window. The
unchanged test passed earlier-head CI and local reproduction. The single
failed-job retry passed.
- Cumulative `pnpm -r typecheck` and `pnpm build` passed. All 1,321
channel integration cases passed. The normal UI, CLI, database, adapter,
plugin, and serialized API test selections ran.
- The first Linux `pnpm test:run` returned 1. Original-source runs
reproduced the local failures. Container-only repairs supplied missing
tools, process reaping, and sufficient Node heap. The existing
mocked-fetch CLI telemetry fixture passed with the image opt-out flag
overridden only for that fixture.
- One local venue limitation remains: adapter-utils T24 fails unchanged
on both original and final source in the Linux container. Its entire
56-case suite passes before and after on the host. All other failed or
aborted suites passed in repaired reruns. No test assertion or timeout
changed.
- These fixtures prove application integration. They do not prove live
provider execution.

## Risks

- A captured option value or changed callback order could affect
deferred ingress or stale-runtime handling.
- The ingress callback and runtime getter remain live. Core maps and
receiver lease operations keep one owner.
- No schema migration or public API change is included.

## Model Used

OpenAI GPT-6, running in Codex with reasoning, tool use, and code
execution. The exact deployment identifier and context-window size are
not exposed in this session.

## 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-10-14 10:50:34 -05:00
DottaandPaperclip 721e87ac02 refactor(server): separate receiver ownership and provider callbacks (#16185)
## Thinking Path

> - Paperclip accepts provider callbacks as durable task input.
> - Runtime ownership prevents two servers from accepting the same
receiver stream.
> - Discord and Photon share the lease machinery but have different
callback details.
> - Moving that shared machinery into Discord would create the wrong
platform dependency.
> - This pull request extracts common receiver ownership and puts
provider callbacks in their own folders.
> - The service keeps startup and shutdown coordination.

## Linked Issues or Issue Description

Depends on #16183; review against the parent branch. Refs #16180 and
#16080. Related open work: #15532 changes Discord command reconciliation
scheduling. This extraction preserves existing scheduling.

**What existing behavior does this improve?**
The structure of shared receiver ownership and Discord/Photon runtime
callbacks.

**Current behavior**
The shared entry point mixes lease acquisition, renewal, provider
capability checks, and Photon checkpoint transactions.

**Proposed behavior**
Put the common lease operations in runtime/ownership.ts and the protocol
details in the provider folders.

**Reason and benefit**
The ownership lifetime stays explicit without making Photon depend on
Discord implementation code.

## What Changed

- Extract 11 receiver-ownership helpers into runtime/ownership.ts (397
lines). Expose only the operations used by the service.
- Extract Photon ownership checks and checkpoint callbacks (44 lines).
Retain the same runtime context object.
- Extract Discord command and capability reconciliation (112 lines).
- Keep the original service-owned lease map, runtime versions, stop
tasks, and shutdown sequence. Read shutdown and test overrides through
live accessors.
- Reduce chat-channels.ts from 6,880 to 6,340 lines, including removal
of blank gaps left by extractions.

## Verification

- Merge preparation: replayed this stack onto current master after
#16180 landed. Preserve master's new Telegram scheduling methods and
connection-scoped Photon notifications. Server typecheck, callback
syntax audit, and module-boundary check passed. Fresh local integration
and wiring checks passed (1,318 tests). The dedicated Photon suite
passed 18 before and 18 after the conflict resolution. Current head is
6d52aba35f; CI and review are running. Earlier verification below
describes the previous stack commits.

- Existing Discord, Photon, and runtime integration cases: 110 passed
before and 110 passed after; 1,185 other cases excluded.
- Server typecheck, module-boundary check, and git diff --check passed.
- Syntax-tree comparison: 11 ownership helpers, two Photon callback
bodies, Discord reconciliation, unrelated service functions, and the
full public API/shutdown return expression preserve structure.
Intentional binding changes are audited.
- Both preceding PRs have 55 passing CI checks and current-head 5/5
reviews.
- Repository typecheck and build passed earlier in this stack. Final
stack checks are recorded below. The first broad local run hit a macOS
PostgreSQL shared-memory fixture limit and was interrupted after that
failure.
- All 55 CI checks pass on df15f9dd9c. Greptile rates that head 5/5 with
no inline findings. Tests use real local persistence with fixture
runtimes; they do not prove live Discord or Photon execution.

- Previous stack validation on #16192 (55417debfe): repository typecheck
and build passed; all 1,295 chat integration cases plus 14 source-wiring
checks passed locally (1,309 total). All five PRs have current-head 5/5
reviews and 55 passing CI checks. The broad local pnpm test:run hit
PostgreSQL shared-memory fixture failures and was interrupted after 868
seconds (exit 130); it is not a local full-suite pass.

## Risks

Lease loss and partial startup can create overlapping receivers if
cleanup order changes. The service retains the same map objects and
shutdown ordering. The ownership module reads current shutdown state,
and Photon callbacks retain the exact mutable runtime context reference.
No new worker or timer starts during module initialization.

## Model Used

OpenAI GPT-6 via Codex, with code execution and repository tools. The
precise serving variant and context-window size are not exposed in this
session.

## Checklist

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

Co-authored-by: Paperclip <noreply@paperclip.ing>
2026-10-13 11:17:21 -05:00