返回 DeepSeek-Reasonix
ATTACHMENT_REPAIR_10457.md
根目录 / docs / ATTACHMENT_REPAIR_10457.md
1 # Attachment admission and request isolation (#10457)
2
3 [中文](ATTACHMENT_REPAIR_10457.zh-CN.md)
4
5 The attachment source is PR head
6 `b582ebabe089fb75a6ee8ba23dddcb0a48a873ca`. It was semantically replayed on
7 `main-v2` `93fb72870758f2ff60ae24386406b0e5f0782f0e`, which already contains the
8 durable-draft work from #10469 and the fixed-snapshot export implementation
9 from #10471, then rebased onto `main-v2`
10 `9b0cc56e5c0e60d92cb447b360ef8fa018c7c72b`. That base also includes #10500's
11 model-scoped reasoning capability resolution. `git range-diff` against the prior
12 `bd0733b9` replay changes only the generated Desktop contract digest, so the
13 attachment patch and later mainline behavior are both preserved. No changes
14 from #10346 are incorporated. The design borrows admission,
15 capability ownership and independent cancellation from deepseek-harness
16 `ddefc45fbc7f8e46dd73185e68295696d1297887`, without importing its image
17 normalization, Sharp dependency or global attachment store.
18
19 ## Behavior and ownership
20
21 An explicit image is part of the submission, not a suggestion for a tool to
22 search the filesystem. Preparation validates the complete ordered batch and
23 persists originals before admission. Failure leaves the draft intact and does
24 not start the provider, tools, a user message or Goal setup. Content objects
25 published before a later failure are harmless unreferenced objects; rollback
26 never removes originals that another submission may already reference.
27
28 `PreparedSubmission` is a host-only candidate. The final admission gate checks
29 its controller and storage scope again and looks up the receipt before source
30 access. A versioned fingerprint describes text, action and logical attachment
31 identities; it excludes temporary credentials and accepted content digests.
32 The acceptance event contains the frozen image references. Deferred turn
33 bodies capture those references before parking and never read temporary
34 submission state asynchronously. Legacy gate-owned synchronous adapters remain.
35
36 The target RPC captures tab generation, controller, workspace, host/session
37 storage identity and runtime epoch. Capture precedes file reads and hashing.
38 Changing focus does not retarget work; retiring the target invalidates it.
39 The controller service owns draft credentials; the host shares only immutable
40 content and discardable variants. Same-session runtime replacement transfers
41 credential proofs. Validation on an explicit user retry renews credentials;
42 repeated renewal returns the same credential. Releasing either proof revokes
43 that draft family. Rebinding never sends a message. Successful Composer cleanup
44 is conditional on the exact submitted draft version, including queue receipts.
45
46 Late session publication also binds the attachment store to that runtime's
47 authoritative content graph. Creating a controller before its session must not
48 pin attachments to a legacy fallback directory. `attachment_owner_test.go`
49 reproduces that construction order and verifies subsequent runtime renewal.
50
51 ## Finding-to-fix map
52
53 | Finding | Shared repair | Regression evidence |
54 | --- | --- | --- |
55 | Accepted images absent from actual requests | Carry `ImageInputs` through ordinary, edited, Goal, invocation and queued turns; resolve before protocol normalization | `attachment_endpoints_test.go`, `attachment_routing_test.go`, loopback provider capture |
56 | Legacy workspace path escape | Open under `os.Root`, refuse leaf links, compare opened/path identities before and after reading; nonblocking Unix open | `isolation_regression_test.go`, workspace/permission identity tests |
57 | Export omits images or damages an existing target | Extend #10471 `ExportSnapshot` with the authorized ordered image closure and task-private rendering; retain its no-replace publication and recovery journal | `sessionexport/build_test.go`, session attachment closure and #10471 publication tests |
58 | Queue depends on temporary draft | Persist ordered inputs and source aliases; validate immutable objects before claim; prepare edits before replacing old envelopes | Queue endpoint, corruption-block and mixed-source edit tests |
59 | Retry creates a second turn or rereads deleted sources | Lookup durable versioned receipt before preparation and again under admission gate | Draft-release retry and canonical credential fingerprint tests |
60 | Mixed attachments bypass batch limits | Merge structured, legacy and authorized sources; validate all originals with one policy | Invalid endpoint batches, mixed-source/dedup, 20/21 and byte-boundary tests |
61 | Service/draft lifetime follows focus or runtime accidentally | Owner-created service, lifecycle-bound contexts, opaque target tokens and validated credential renewal | Desktop target, replacement, cancellation and Composer tests |
62 | Canceled transform captures a later request | Remove last-waiter inflight entry under lock; only its own task may finish/remove it | Deterministic independent-waiter and successor tests with race detector |
63 | Encoding/upload follows wrong model/account | Capture provider configuration; resolve by actual parent/child/understanding model; propagate cancellation | Upload route interception, real boot child and text-to-vision provider tests |
64
65 Test paths are under `internal/control`, `internal/attachment`, `internal/boot`,
66 `internal/session`, and `desktop`. They assert actual provider messages in
67 addition to preparer return values. Tool originals are persisted before an
68 understanding request. A persistence failure preserves completed tool text and
69 diagnostics rather than replaying an action that may have side effects.
70
71 ## Compatibility and cache contract
72
73 - Originals, `.content-v1`, revision 3 and inbox schema 3 stay in place.
74 - Legacy `Images []string`, system prompts, tool schemas and history order are
75 not rewritten. Three loopback protocol tests compare the actual serialized
76 OpenAI, Responses and Anthropic bodies before/after legacy resolution.
77 - New images use the existing deterministic policy v1 (1568-pixel bound,
78 JPEG quality 85 where applicable); the 512 MiB variant cache never deletes
79 original objects. Both source validation and encoding use the same host
80 heavy-work limit of two.
81 - New image request bytes differ from the broken request that omitted images;
82 the first prompt-cache miss for those submissions is expected.
83 - Unknown receipt versions and unverifiable legacy receipt mismatches fail
84 explicitly instead of guessing and replaying.
85 - `attachments-v2` target operations are negotiated explicitly; unsupported remote hosts do not
86 silently fall back to another workspace.
87 - Schema compatibility tests prove that unsupported revision 3 data is rejected
88 without an in-place downgrade. Packaged previous-binary validation remains a
89 separate release-qualification step and is not inferred from source tests.
90
91 ## Reproducible qualification
92
93 Qualification has three risk-based layers.
94
95 The PR gate runs after code changes and blocks a push on failure. It covers the
96 focused attachment, submission, queue, history-preview and variant-cache Go
97 tests; deterministic concurrency tests and relevant race suites; Desktop and
98 Composer attachment tests; type checking, contract freshness, `repolint`,
99 inventory, the preview bundle budget, actual provider image digests, zero
100 provider/tool/Bash calls after explicit-image rejection, and unchanged legacy
101 `Images []string` bytes for OpenAI, Responses and Anthropic. A substantial shared
102 code change also runs the root, Desktop and frontend suites once. Later changes
103 limited to documentation, mocks or package splitting rerun their affected suites
104 and static gates.
105
106 The patch-id-equivalent integration candidate completed the root and Desktop Go
107 suites, focused race suites, all 409 frontend suites, frontend type checking,
108 the production build and bundle budgets, generated-contract freshness, inventory
109 and repository lint. The final rebase preserves the attachment patch according
110 to `range-diff` and reruns the affected model-routing, Desktop and frontend gates.
111 Desktop Linux cross-lint still reports four unchanged tray stubs from the
112 `main-v2` baseline; it is not an attachment regression.
113
114 The final-SHA package gate runs once before pushing. Build with
115 `scripts/desktop-build.sh`, extract the **finished** ZIP into a new directory,
116 and run:
117
118 ```sh
119 node desktop/packaging/smoke.mjs /isolated/Reasonix.app
120 node desktop/packaging/attachment-native-smoke.mjs \
121 /isolated/Reasonix.app /isolated/evidence
122 ```
123
124 The attachment fixture launches the production Electron shell and bundled
125 service with a disposable data home and a loopback provider. It checks exact
126 image bytes with a process directory distinct from the workspace under
127 workspace-write permission, `view_image` parity, cancellation/retry without a
128 duplicate turn, and real Composer preservation after an image read fails. It
129 writes JSON evidence and a screenshot without installing or replacing an app.
130
131 The source branch previously produced an isolated preview package from
132 `86fd76f20d7d` and loopback evidence for its attachment flow. That evidence is
133 historical input, not qualification of the integrated head. Generated package
134 evidence remains uncommitted; a release candidate must rerun the ordinary package
135 smoke and `attachment-native-smoke.mjs` against its own SHA before making a
136 packaged-runtime claim.
137
138 Release and high-risk gates are conditional. Storage revision or inbox schema
139 changes require previous-version upgrade/downgrade checks; shell, signing or
140 service-layout changes require native signing and startup matrices; permission
141 model changes require workspace-write/full-access comparison; provider, Files
142 API or upload-cache changes require live-provider and account-isolation checks.
143 This PR keeps revision 3 and inbox schema 3 and does not change Files API or
144 upload caching, so previous-binary and live-network checks are not applicable.
145
146 Loopback capture proves image transport, routing and permission behavior, not
147 semantic recognition by a paid remote model. No live credential is required or
148 read by these fixtures. Crash publication recovery runs when the same destination
149 is reopened for publication; there is no scan of arbitrary export directories at
150 application startup.
151
152 The repair does not merge or release the PR, overwrite an installed application,
153 change Bash search behavior, add upload caching or collect original objects.
154
154 lines MARKDOWN