Files
PaperClipAI/maps/agent-access-map
DottaandPaperclip 71a20453e1 fix(workspaces): honor inherited remote workspace bindings (#18611)
## Thinking Path

> - Paperclip manages AI agents and their work.
> - Task creation can bind a child to its parent's execution workspace.
> - Native sandbox runs reserve that workspace before the provider
starts.
> - Remote reservation rejected inherited isolated workspaces and
operator branches because the original source task differed.
> - This check stopped valid child tasks before their existing access
and writer checks could run.
> - This pull request uses the persisted binding and existing
source-access checks to admit that continuation.
> - The benefit is that authorized child tasks can continue saved work
while the single-writer lock stays effective.

## Linked Issues or Issue Description

**What happened?**

A child inherited an active isolated remote workspace through normal
task creation. Its next run failed during setup with `Workspace
ownership changed.` No provider work started. The reservation guard
treated the original `sourceIssueId` as exclusive ownership, although
task creation had persisted a valid child binding.

**Expected behavior**

A bound child or follow-up can reserve the workspace after the prior
writer saves. Current task/run access, source visibility, trust, company
scope, closed-workspace state, and writer checks must still apply. The
original source task remains provenance.

**Steps to reproduce**

1. Create a task with an active saved remote isolated workspace or
operator branch.
2. Create a child without an explicit workspace override.
3. Confirm that the child inherited the execution workspace ID.
4. Start its native sandbox run. The old reservation guard rejects it
before provider execution.

**Paperclip version or commit**

Reproduced on source based on
`06bc8db75c71142ed108e0f331394c5187015d6a`. The same guard is present at
`1a6017d6460267ad89d7e1784e2b521c28d8e9ac`.

Related: #17156 proposes separate workspaces for child tasks. This
repair preserves the current inheritance contract and enforces the
remote writer lock. #16911 addresses child bindings across repositories.

## What Changed

- Remove the original-task equality restriction for active remote
workspaces. Keep the existing persisted-binding and retained-source
authorization path. Explicit task-root selection follows the existing V1
filesystem contract; task-assignment grants do not define filesystem
permissions.
- Keep closed workspace rejection and unfinished-writer checks.
- Add database-backed regressions for inheritance, replay, competing
children, an unbound task, private source data, company isolation, and
closed records.
- Extend real save/restore tests for inherited isolated workspaces and
operator branches. Keep shared-workspace discovery coverage.
- Update the development guide and workspace maps.

## Verification

- Red: before the repair, the inherited isolated/operator cases fail
with `Workspace ownership changed.` The shared case passes. The unfixed
suite has five failures and four passes.
- Green: 11 reservation cases pass with real PostgreSQL 18 in an
isolated Docker container.
- An earlier run of the four affected workspace/preparation/trust suites
passed 191 tests. The review follow-up passes all 15 selected
reservation/save/restore cases. Inherited cases remove the original
files, use a distinct allocation and target, restore the saved file,
append child work, and independently read that work from the child's new
snapshot. Shared-source discovery stays covered. The filter excludes 42
other integration cases.
- `pnpm -r typecheck`, `pnpm build`, `node scripts/check-maps.mjs`, and
`git diff --check` pass. A direct server typecheck also passes after the
final test edit.
- `pnpm test:run` stopped in its first chat shard: 338 passed, one
Discord receiver-lease setup failure, 1,478 outside the shard. The
failing test passes in isolation on both the unchanged baseline and the
fix. Its suite-order failure is not explained by that retry and remains
recorded. The unchanged baseline also fails three other Discord
publication cases in that chat shard, while its next chat shard passes.
This does not reproduce or explain the original lease failure; both
results remain recorded. CI is complete on `e697f6e1b8`: 54 successful
check runs, one successful legacy status, three skipped checks, and one
neutral check. No check is pending or failed. Greptile gives this commit
5/5 with no remaining findings. The security reviewer accepted the
V1-contract explanation; both review threads are resolved.
- Live sandbox acceptance remains unverified. The available test
credentials could not resolve the required sandbox snapshot. The
provider rejected creation before workspace execution, and a scoped
follow-up found no allocation. No live model turn, deployment, or
original-task recovery is claimed.
- Local environment: macOS arm64, Node 26.4.0, pnpm 9.15.4. Native
PostgreSQL startup hit the host semaphore limit; tests use disposable
Docker databases. No shared database was reset.

## Risks

- A bound child can now write after the prior writer releases the
workspace. Incorrect binding or access checks could expose source data.
Regressions cover unbound, private-source, and foreign-company
rejection.
- Concurrent children must not become two writers. A real transaction
race grants exactly one reservation; saved-file tests keep the second
writer blocked until save completes.
- No schema or migration changes. This PR does not change task-creation
inheritance, requested models, credentials, trust, approval gates, or
recovery budgets.

## Model Used

- OpenAI Codex, based on GPT-6. The exact serving model ID and context
window are not exposed in this session. Used reasoning, tool use, code
execution, and browser diagnostics. No sub-agents were used.

## 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 — the targeted workspace
suites pass; the full local chat-suite failure and baseline comparison
are documented above
- [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-11-02 09:36:05 -06:00
..

Paperclip agent access map

This map accompanies the feature map. It records APIs, agent entry points, permission boundaries and verification for the same capability IDs. The shared contract defines the format and maintenance rules.

The chat scenario catalog uses these same IDs for human requests and expected outcomes. Its scenarios retain the access boundaries here; neither a CEO role nor a planned scenario grants board authority or establishes a working production tool binding.

Use full capability IDs when referring to access contracts outside their file: onboarding/company means the company capability in onboarding.md in both maps. The feature index lists feature and capability IDs; IDs and references explains entry-point references and stable naming.

Browse access contracts

The same-named feature recipes define navigation and capability IDs. Run node scripts/storybook-catalog.mjs for the generated maps/generated/agent-access-map.md index, or browse the published feature guide. Add or update the affected companion; there is no central registration or count.

Existing baseline source references describe the original inspection, not current verification. Record new executed evidence in the PR, issue, or CI artifact with its revision and scope. Do not refresh unrelated headers as bookkeeping.

Using an entry

Read its Policy and Gaps before selecting an agent path. Native fallback, legacy REST/CLI, stdio MCP and a personal assistant connection can have different authority and availability. Use a real admitted production binding; a scenario declaration is not an installed tool. A restricted entry records current enforcement and leaves any unresolved delegation decision visible.

For API catalog disagreements, follow the route/service authorization and record discovery drift. For not-applicable, retain the concrete exception and local path. Split shared business operations from client-only presentation.

Use maintain-verification-skill to reconcile changed source and both maps. Use verify-paperclip and existing API/runner/MCP fixtures to collect the permitted-agent and denial evidence; report blocked/not-run coverage honestly. Run node scripts/check-maps.mjs after editing. The structural check does not certify permissions, API catalog coverage, tool admission or live behavior.

Native REST transport

The call_api parity change reconciles affected baselines against 58e16dbddfc9c8d0cf60867f9d9847f0feda055b and the changes in this PR. Ordinary REST operations use the same route authorization as legacy agent REST. Dedicated tools remain optional for those operations; protocol endpoints still need their existing clients. Board-only routes remain restricted for agent identity.

Native search_api / call_api is enabled by default, but explicit server, company-allowlist and binding settings can narrow admission. It requires a running authorized native run, current task assignment and execution-run binding, company and budget authority, task privacy, and a permitted work mode. Ask and Plan retain mutation restrictions, and runs retain their admitted JWT scope during restart recovery even when task mode changes. A waiting agent does not gain independent native control just because a REST route exists. Connection-management reads support Standard, Ask and Plan; mutations require Standard. Skill-test runs and nonstandard task-bridge keys cannot administer connections. These gates supplement each operation's grants, resolved resource and target scope, and responsible-user authority. See the rollout policy and connection authorization.

Credential-bearing replies, including company exports and their legacy alias, stay inline under a 10 MiB limit and use encrypted mutation receipts. Other saved API snapshots are limited to the issuing actor and responsible user, plus authorized administrators. Artifact uploads enforce the same access checks as downloads; private snapshots are excluded from company exports and public company logos. Explicit deliverables use the existing sharing path. Native event history, checkpoints and completion records omit API bodies while preserving receipt metadata and replay digests. Restored webhook secrets use the same encrypted receipt and inline response policy as newly created webhook secrets. Task image access requires the company boundary and the task permission; skill-test and low-trust agents do not need company-wide browsing authority. Completion replay applies the same idempotent projection to stored and expected payloads; the run-log guide describes its fields.

Sources: API client, catalog, native authority, credential storage classification, snapshot access, and history redaction. The affected entries remain baseline and source-only; this reconciliation does not certify every operation. Targeted real-route proof lives in the API integration suite, including owned routines, skill tests, scoped secrets, proposals and private export replay.