# Permanent session deletion: reference audit and DSH 0.2.0-rc.2 limits This report records the **2026-10-07 source and publication inspection** of `MichengAI/dsh-archive-manager`, fixed at commit `46af4c54bab466b11ccddf2b63818749ded98c17`, and the resource contracts in this repository's exact public npm SDK, **DSH `0.2.0-rc.2`**. It distinguishes **source observation**, **design inference**, and **missing runtime proof**. Implementation status remains in the [README](../../README.md); selected product scope and admission conditions belong to the [design proposal](../design-proposal.md). **Conclusion:** the reference is a published plugin implementing physical deletion through a custom JSONL adapter, private Workspace/Session/cache integration, and filesystem removal. It does not reveal a supported native permanent-deletion API in DSH `0.2.0-rc.2`. Its ordering, generation recognition, lifecycle identities, cache tombstones, and partial batch results are useful precedents. Its deletion path does not establish the writer, activity, ownership, shared-resource, or crash-recovery guarantees required by Session Bin. Recursively removing the JSONL session directory also removes the POSIX writer's stable `session.lock` inode. [Reference deletion][ref-delete], [physical removal][ref-removal], [SDK persistence limits][sdk-persistence-limits], [SDK writer lease][sdk-lease]. The original reference audit used primary GitHub source/API responses, npm metadata, and read-only inspection of the published tarball and locked SDK files. Tarball members were read in memory; no reference package was installed, built, imported, or executed. That audit performed no session operation or deletion test. The later independent admission probes below run public SDK owners in isolated temporary data; they do not perform erasure or reproduce the reference's deletion suite. Neither stage contacts the running `19387` GUI or operates on real user sessions. Upstream CI records below describe the reference project's executions. ## Pinned identity, publication, and license | Source observation | Primary evidence | |---|---| | GitHub main is fixed at `46af4c54bab466b11ccddf2b63818749ded98c17`, authored on `2026-10-06T09:48:40Z`; the manifest is `1.0.13`. | [Commit API][ref-commit], [manifest][ref-manifest]. | | `v1.0.13` points directly to that commit. The GitHub Release is published, neither draft nor prerelease, at `2026-10-06T09:55:46Z`, with no attached assets. Automatically generated source archives are separate from an attached prebuilt release tarball. | [Tag API][ref-tag], [release API][ref-release]. | | The actual package is **`@michengai/dsh-archive-manager`**. npm reports `latest: 1.0.13`, publication time `2026-10-06T09:55:15.276Z`, the same `gitHead`, a registry tarball, and a GitHub Actions trusted publisher. | [Package registry][ref-registry], [exact version metadata][ref-npm-version]. | | The unscoped `dsh-archive-manager` is a different package: npm `latest: 1.1.1`, repository `Jasonrale/dsh-archive-manager`, and MIT license. It must not identify the user-specified MichengAI project. | [Unscoped registry][other-registry]. | | The pinned project and exact npm version declare **Apache-2.0**, not MIT. The license is present in GitHub and the tarball; the pinned tree contains no `NOTICE` file. | [License][ref-license], [manifest][ref-manifest], [tree API][ref-tree], [npm metadata][ref-npm-version]. | | Development DSH packages are pinned to `0.2.0-rc.2`; peers declare a list of supported prereleases. This is the reference's declared range, not Session Bin's compatibility claim. | [Manifest][ref-manifest]. | **Observed artifact identity:** the npm `1.0.13` tarball contains **27 regular files**, agreeing with registry `dist.fileCount`. Its SHA-1 matches registry `8120aead72739a34793d6711e208569c4fe6f489`; the independently computed SHA-256 is `508cc6d35c8a8ec3d35b4782da73567fd5379c57312f16ff02c954e36363b0a8`. The packed manifest, license, and compiled Workspace, projection-cache, Host-install, tombstone, and Client modules are byte-identical to their fixed GitHub files. This verifies the inspected runtime files' publication identity; it does not prove TypeScript/build equivalence or deletion safety. [Exact metadata][ref-npm-version], [tarball][ref-tarball], [compiled Workspace][ref-lib-workspace], [compiled cache][ref-lib-cache], [compiled Client][ref-lib-client], [tree][ref-tree]. **License implication:** copying Apache-2.0 implementation into an MIT project still requires retaining applicable upstream notices and license, marking modified files, and carrying applicable `NOTICE` content when present in the reused distribution. The pinned license's appendix retains its placeholder copyright template; this report does not invent an author copyright statement. License identity is separate from runtime compatibility. [Redistribution conditions][ref-license]. ## Deletion mechanism observed in the reference The active Host installer preserves official Workspace/cache service objects and overlays methods and fields on them. The Workspace overlay copies methods from a subclass, modifies path accounting, adds Remote markers/binding, and restores installed methods on uninstall. The cache overlay installs a separate domain and write guards, with a fallback guarding the official table. This is native-service integration, not an independent plugin-owned Bin catalog. [Host installer][ref-install], [Workspace overlay][ref-overlay], [cache][ref-cache], [bundle patch][ref-patch]. The single-session endpoint uses Host-local `enqueueOperation()`. Its body checks `sessionKnown(id)`; unknown IDs receive cache/spill/Workspace/archive cleanup without first proving artifact absence. For live Sessions it awaits `flush`, obtains private `liveEntryFor`, and calls private `detachEntered`; older Hosts may temporarily prepare/enter/announce/detach cold Sessions. It then awaits optional cache `whenIdle`, deletes the cache row, attempts subagent/spill cleanup, removes the recognized JSONL directory or located artifact, and checks optional `stat(id)`. Finally it clears archive state, updates Workspace rows, forgets private indexes, saves the old `{ createdAt, cwd }` identity in a memory tombstone, and emits `api-session/removed`. Child/spill failures only warn. The result is `{ deleted: true }`, with no operation ID, persisted intent/phase, or historical receipt. [Deletion][ref-delete], [cold removal][ref-cold], [physical removal][ref-removal], [cascade/spill][ref-cascade]. ## API and filesystem authority | Source observation | Design inference | |---|---| | The plugin registers its own `workspaceRegistry/deleteSession` and `deleteArchivedSessions` strict Typert descriptors/Remote markers and calls them through `ctx.remote`. | A plugin-created Remote endpoint is not a native SDK deletion capability. [Descriptors][ref-descriptors], [Client calls][ref-client-calls]. | | Native persistence exposes `create`, `open`, `flush`, `stat`, and `list`, and explicitly has no deletion/retention API. The base declaration has no `locate`; JSONL's concrete `locate()` is a diagnostic-path hook. | A backend path is not a portable erase interface or authority over its ancestors. [Persistence declarations][sdk-persistence-types], [limits][sdk-persistence-limits], [diagnostic locator][sdk-locate]. | | The reference casts Workspace private fields/methods including `headers`, `sessionPaths`, `entities`, `requireTable`, `setState`, `readSessionHeader`, `sessionKnown`, and `enqueueOperation`; deletion uses private SessionStore `liveEntryFor`/`detachEntered`. Cache table/write paths are extended similarly. | JavaScript access does not make these supported resource-lifecycle extension points. [Reference compatibility types][ref-compat], [Workspace declaration][sdk-workspace-types], [Session declaration][sdk-session-types], [cache declaration][sdk-cache-types]. | | Directory recognition requires backend name `session-persistence-jsonl`, kind `jsonl`, an absolute initialized root or absolute configured-root fallback, canonical generation filenames, encoded ID/project layout, and exact path equality. It handles `.`/`..`, UTF-16 code units, raw/Zstandard files, and preserved generations. | This is more specific than deleting any located path's parent. A layout match still does not prove write exclusion or exclusive ownership of every colocated resource. [Directory recognition][ref-paths]. | | Recognized project/session directories are checked with `lstat()` and symlinks are rejected. The root may be an intentional alias; the code explicitly assumes stable trusted ancestors and acknowledges that `lstat` then `rm` is not atomic against replacement. Unrecognized layouts use artifact-only deletion. | Identity, root, and directory-replacement races remain part of a provider deletion protocol. The Client supplies an ID, not a file path. [Removal checks][ref-removal]. | | Optional post-removal `stat(id)` rejects if the Session remains observable. | This catches removing an absent successor while older logs survive, but is an observation after irreversible work, not a storage transaction. [Removal/stat][ref-removal], [generation fixture][ref-latest-fixture]. | ## Writer lifetime, activity, selection, and ownership | Area | Source observation | Design inference or missing runtime proof | |---|---|---| | Writer lock | Deletion never acquires `acquireLease`; **repair** does. JSONL directory removal includes POSIX `session.lock`. SDK acquisition uses `flock` and device/inode validation; release closes the descriptor without unlinking. [Repair][ref-repair], [delete][ref-delete], [removal][ref-removal], [SDK lease][sdk-lease], [limits][sdk-jsonl-limits]. | Unlinking a live lock forfeits exclusion. Another writer/newly admitted writer is not excluded by local detach or the Bin lease. The existing single-Host boundary is retained. [Deployment contract](../host-lifecycle.md#并发与部署边界). | | Flush/close | `SessionStore.flush` awaits durability listeners, not writer close. Detach emits disposal without collectively awaiting async observers; JSONL's observer starts `writer.close().catch(...)` without a caller-awaited close barrier. Handles retain separate lifetimes. [Session runtime][sdk-session-runtime], [JSONL listeners][sdk-jsonl-lifetime]. | The fixture observes close-before-removal in its tested case, but that does not establish settlement of all observers, retained handles, Agents, or competing Hosts. The projection tail is not a provider-wide close acknowledgement. [Fixture][ref-latest-fixture]. | | Activity/current | Archive uses the native activity waterfall; delete has no such gate or stop-settlement barrier. Native delete-menu/confirmation has no archived/current/running/pending predicate. Delete text includes running children; idle cleanup protections apply to archiving. [Archive][ref-archive], [delete][ref-delete], [menu][ref-menu], [wording][ref-delete-copy], [idle rules][ref-organizer]. | Current/active protection is not established for permanent deletion. Archive success and detach do not prove all work stopped. | | Ownership/absence | Batch uses native global archives; single delete admits unarchived known Sessions. Favorites do not establish Bin ownership. Unknown-delete cleanup does not prove absence; a separate pruning helper uses `stat`, and native discovery can omit unreadable headers. [Batch][ref-batch], [delete][ref-delete], [test][ref-host-delete-tests], [favorites][ref-favorites], [absence helper][ref-absence], [SDK discovery][sdk-jsonl-layout]. | Native archive/confirmation cannot replace durable entry identity and execution-time checks. Unknown indexes cannot prove artifacts absent. [Session Bin semantics](../host-lifecycle.md#公共接口). | ## Linked resources and accounting | Resource | Source observation | Design inference or missing proof | |---|---|---| | Generations | Recognized JSONL directories are removed recursively, including historical/current raw/Zstandard files. A regression covers `locate()` naming an absent successor while old input survives. Native migration preserves predecessor bytes and reads the highest generation. [Adapter][ref-paths], [fixture][ref-latest-fixture], [SDK layout/read rules][sdk-jsonl-layout]. | A generation-aware definition is needed; directory removal still does not prove safe lifetime coordination or exclusive ownership of colocated files. | | Subagents/forks | Cascade accepts only `parentSession === parentId && origin === 'subagent'`, combines live/stored headers, recurses, and preserves forks. Child/enumeration failures warn; parent success can coexist with surviving children. [Cascade][ref-cascade], [lineage tests][ref-host-lineage-tests]. | Preserving independent forks is useful. New/omitted/corrupt child headers, failed discovery, and activity changes need explicit outcomes and recovery. Header lineage alone does not establish all resource ownership. | | Shared attachments | No attachment reference-accounting/GC API is called. A regression fabricates session-local `attachments/output.txt`. Official attachment storage deduplicates content-addressed objects and shared canonical files/named hard links; resumed/forked Sessions can reference the same objects. [Delete path][ref-delete], [local attachment fixture][ref-host-delete-tests], [SDK attachment contract][sdk-attachments]. | A local fixture proves neither canonical-object cleanup nor exclusive ownership. Shared objects require reference/retention rules; direct shared-store removal is outside Session Bin's allowed mechanism. | | Spill | A session directory derived from exposed `spillStore.root` is recursively removed; failures only warn. [Spill helper][ref-cascade]. | `{ deleted: true }` does not certify spill cleanup success or a complete resource transaction. | | Workspace/archive | The known branch clears native archive state after transcript removal, then updates Workspace rows/entities and private indexes. The unknown branch updates Workspace rows before archive state. [Delete order][ref-delete], [accounting][ref-removal]. | Separate global/row writes are not atomic with erasure. A Workspace update can fail after the archive mark has already disappeared. | | Pins/favorites | Archive removes pins; deletion preserves other global-state fields and has no explicit pin removal. Pinned unarchived Sessions are reachable through single delete. Persistent favorites are pruned on a later read after confirmed absence; batch UI removes completed IDs locally. [Archive][ref-archive], [delete][ref-delete], [favorites][ref-favorites], [batch UI][ref-client-batch]. | Previous archive behavior does not prove pin cleanup for all allowed targets. Favorite pruning/local display updates are not atomic with deletion. | | Projection cache | The overlay uses `session_projcache_archive_manager_v2`, SHA-256 keys, tracked `write`/`put`, and memory tombstones; post-write cleanup prevents covered late writes resurrecting its row. Imports preserve source domains; uninstall restores the official table. [Cache implementation][ref-cache]. | These guards do not erase every cache domain. Tombstones are process-local; old-source data and restart/uninstall behavior need a retention/rebuild policy. | | Query indexes | The reference deletes no SQLite rows and invokes no generic query-delete API. Its real fixture checks `SessionQueryEngine.listSessions()` after deletion/reopen. Official SQLite separately reconciles persistence/live observations with stable double observation; private `_deleteSession()` is used in index reconciliation/replacement. [Core][ref-delete], [query fixture][ref-latest-fixture], [SQLite source][sdk-query]. | Observation can remove stale index rows, but is neither Session erasure nor immediate consistency for all query consumers/providers. | | Live/client state | The reference detaches live entries, drops private Workspace indexes, and emits `api-session/removed`. Native removed handling can retain a resident Client Session: `handleRemoved()` sets `removed`/notifies, while `dispose()` separately awaits event-stream disposal. [Reference][ref-delete], [SessionStore][sdk-session-runtime], [Client removal][sdk-client-removal], [resident Session][sdk-client-session]. | Removal notifications/list refreshes do not certify release of all references, Agent contexts, caches, or resources. | ## Failures, retry, authorization, and batches | Area | Source observation | Design inference | |---|---|---| | Retry/idempotency | Cache/transcript failures propagate; ordinary physical failures preserve parent bookkeeping. Unknown-ID repeats clean references and return success. Memory tombstones use a 4,096 FIFO bound and `{ createdAt, cwd }` lifecycle checks; tests cover partial removal, injected I/O/bookkeeping errors, stale lists, and ID reuse. [Core][ref-delete], [identity][ref-identities], [bookkeeper][ref-tombstone], [fault tests][ref-host-fault-tests], [reuse tests][ref-host-identity-tests]. | There is no persisted operation/receipt fence against later same-ID lifecycles. Separate parent/child/storage/bookkeeping/cache steps leave partial-commit windows; archive removal before a failed Workspace write can exclude a retry target. Child/spill/notification warnings do not become failed-resource results. [Batch selector][ref-batch], [cascade][ref-cascade]. These are source-derived windows, not reproduced failures. | | Authentication/admission | Strict native Typert descriptors/binding add no unauthenticated custom HTTP route. Codecs accept nonempty IDs/scope shape without batch bound, cancellation parameter, or confirmation token. Native Connection requires browser cookies, root launch-token exchange, Host/Origin/fetch checks, and admits an operator peer; in-process defaults do not bypass browser auth. [Descriptors][ref-descriptors], [Client calls][ref-client-calls], [Connection][sdk-connection], [admission][sdk-connection-runtime], [Gateway peer][sdk-gateway-peer]. | Carrier/operator authority is separate from entry/lifecycle/operation admission. The captured-interceptor test is not browser/network authentication evidence. [Gateway test][ref-host-gateway-tests], [Session Bin Remote contract](../client-interface.md#严格-remote-边界). | | Batches | Current management UI makes one Host scope call. Host deduplicates native-archive targets, snapshots descendants once, runs sequentially, continues after failures, and reports requested/deleted/skipped IDs plus failures. Explicit-ID selection constrains targets; all/Workspace/ungrouped resolve at execution. UI clears completed selections and reconfirms explicit-ID failure retries. [Host][ref-batch], [UI][ref-client-batch], [tests][ref-host-batch-tests]. | Scoped confirmation counts are not frozen plans. The README's first-failure-stops claim matches organizer archive/restore/older delete composition, not current scope deletion. No per-item progress stream, durable lookup, or pending-object cancellation exists in the scope call; UI locks do not provide restart idempotency. [README][ref-readme], [organizer][ref-organizer]. | ## Upstream execution evidence and missing proof **Observed upstream record:** this exact commit has a successful compatibility CI run, a `windows-latest` test job, and a successful `pnpm verify` step. Pinned verification includes an isolated version matrix whose `0.2.0-rc.2` profile runs the real JSONL/query fixture and test suite. A published registry version and GitHub Release independently establish publication. [CI run][ref-ci-run], [jobs][ref-ci-jobs], [workflow][ref-ci-workflow], [manifest scripts][ref-manifest], [matrix][ref-matrix], [npm version][ref-npm-version], [Release][ref-release]. **Source observation — positive scenarios:** the latest-host fixture uses real `SessionStore`, `JsonlSessionPersistence`, and `SessionQueryEngine`. It defines raw/Zstandard live flush/delete/reopen checks, observes writer close before removal in that case, verifies cold parent/subagent deletion and fork survival, and covers a diagnostic successor path with historical input. Other tests define generation/layout, symlink, cache late-write, partial-batch, error-retention, and lifecycle-reuse checks. Workspace/global persistence is substantially backed by test maps/facades; the query fixture uses the generic engine rather than an explicitly installed SQLite backend. This is meaningful source and upstream CI evidence, without a claim of independent reproduction here. [Latest-host fixture][ref-latest-fixture], [Host tests][ref-host-tests], [CI jobs][ref-ci-jobs]. **Missing runtime proof for Session Bin:** the inspected evidence does not establish exclusion of a separately running writer during deletion, preservation of the POSIX lock inode, an atomic activity gate, release of every retained handle/reference, shared-attachment accounting, all optional query/cache providers' convergence, or saved intent/receipt recovery across actual process termination. A successful upstream suite does not prove those additional properties. This source audit is not Session Bin's deletion runtime acceptance. [Lease][sdk-lease], [resource observations above](#linked-resources-and-accounting), [admission conditions](../design-proposal.md#永久删除准入). ## Independent resource-lifetime admission probes **Executed on 2026-10-07:** [admission probes](../../tests/deletion-admission.test.mjs) and their [writer worker](../../tests/helpers/persistence-worker.mjs) run public npm `0.2.0-rc.2` owners on macOS ARM64/Node `24.18.1`, with explicit temporary DSH_HOME, JSON domain storage and JSONL roots under random ignored `.local/lifecycle/` directories. **12 tests passed.** They establish the following boundary observations, not deletion safety. Exact source fingerprints, full regression result and reproduction are in the [Host verification report](../verification/host-lifecycle.md#永久删除资源准入探针). | Independently executed observation | Consequence for a deletion protocol | | --- | --- | | For raw and Zstandard logs, service-wide `flush()` leaves the writer claim held; a separate Node process cannot open a writer until `close()`. Closing and reopening the writer preserve the lock's device/inode and leave the log revision unchanged. A retained read handle works afterwards. | Durability, writer release, read lifetime and lifecycle identity require separate witnesses. The tested lock is never removed. [Persistence contract][sdk-persistence-types], [lease][sdk-lease]. | | For both encodings, the public `enter()` detach disposer returns while a deliberately delayed caller-owned `close()` and an async `session/disposed` listener are unresolved. After writer close, the listener can still be pending and the retained reader still works. | There is no aggregate awaited deletion barrier on detach. Delay is injected only through the public handle method and a fixture observer; this is not a claim that every ordinary Agent teardown uses that order. [Disposal source][sdk-session-runtime], [JSONL listeners][sdk-jsonl-lifetime]. | | A quiet session moved through Session Bin remains archived and owned by the Bin while a public persistence write open appends another completed turn. | Archive/activity observations do not exclude persistence writers; a writer operation does not consult the archive gate. No actual Agent/worker is started by this test. [Open implementation][sdk-jsonl-open]. | | Two exact live Session objects are created sequentially with identical headers; the first object's detach capability cannot remove the second object. | The store has exact process-local lifetime protection, but header equality alone cannot name a live generation. `createdAt` is caller-supplied and the public header has no durable incarnation nonce. This test re-enters memory objects; it does not replace durable logs. [Header/options][sdk-header], [detach][sdk-session-runtime]. | | An unmaterialized create is visible to its own persistence instance but absent from another; flush makes it visible there. Replacing an instance changes `identity: symbol`. | An empty foreign listing is not a universal inventory of pending lifecycles. A process-local symbol cannot bind a receipt across restart. [Create/visibility][sdk-persistence-types], [tracker][sdk-jsonl-lifetime]. | | For both encodings, a valid seeded physical V3 log is translated to logical V4. Read open publishes no successor; write open publishes V4 while preserving V3 byte-for-byte, and the original read handle remains usable. | Deletion must cover provider-classified retained generations. Acquiring an ordinary write handle as a retirement lock can itself migrate storage. The probe covers V3→V4 and two turn events, not the full historical migration corpus. [Generation contract][sdk-jsonl-layout], [write open][sdk-jsonl-open]. | | A seeded invalid-JSON header, raw or in a valid single Zstandard header frame, yields `stat === undefined` and an empty `list()` while its artifact bytes remain. | Public absence observations cannot certify physical erasure or safe shared-resource enumeration. [Header discovery][sdk-jsonl-discovery]. | | Two public `saveFile` calls with equal bytes and different names return one attachment ID; named paths and the canonical object share an inode (`nlink >= 3`). Both remain readable. | Session membership, a name and a path are not exclusive ownership of attachment bytes. No reference is released or collected by this probe. [Attachment store][sdk-attachments], [public methods][sdk-attachment-types]. | **Source correction:** the locked npm Session declaration identifies `SESSION_FORMAT_VERSION = 4`; JSONL's README layout example still labels V3 as current. The generation probe uses the actual public constant, a V3 header including mandatory `type: 'session'`/`delegationDepth`, and separate Zstandard header/event frames. The proposal must identify logical lifetime independently of physical format version or a diagnostic successor filename. [Actual format/header][sdk-header], [published README][sdk-jsonl-layout]. **Additional source observation:** AgentLoop's own composite teardown cancels its exact machine, awaits `whenIdle()` and scope disposal, awaits its owned persistence handle `close()`, and only then detaches Agent/Session. This is stronger than arbitrary SessionStore detach; it is a capability held by that lifecycle owner, without an atomic retirement gate or a guarantee about every other owner. Projection cache `write()` skips live flush once the Session is detached and still writes its checkpoint; `coldSnapshot()` also starts independent asynchronous write-back. Therefore a complete protocol must include these owners and late writers explicitly. These source paths were inspected, not executed as a real Agent/cache deletion test. [Agent close sequence][sdk-agent-close], [cache write paths][sdk-cache-write]. ## Resource owner contract gaps The following are **interface requirements derived from the locked source**, not new callable services or product capabilities. The [candidate protocol](../design-proposal.md#永久删除资源生命周期候选协议) makes the identity binding, frozen manifest, admission fence, per-owner phases and receipt semantics reviewable. | Owner / concern | Public evidence in `0.2.0-rc.2` | Specific missing contract | | --- | --- | --- | | Persistence identity / JSONL | `identity` is a symbol; `revision` is scoped to one instance/ID; the header admits repeated timestamp/cwd. Write open takes the writer lease and can publish migration. | Durable store/lifecycle token; non-migrating retirement lease; pending-lifecycle admission; complete exclusive artifact manifest; durable erase/tombstone/receipt and recovery. `locate()` supplies none of these. [Types][sdk-persistence-types], [header][sdk-header], [open][sdk-jsonl-open]. | | Agent / activity / reads | The archive waterfall refuses reported work; stop requests do not wait for settlement. Composite Agent disposal can await its writer, Session disposal listeners are contained emits, and retained handles have separate lifetime. | Joint admission fence covering new and already admitted work, native visibility changes and reads; exact owner disposal/close acknowledgements; a way to reject incomplete participant coverage. [Session][sdk-session-types], [Agent][sdk-agent-close], [activity](current-dsh-interfaces.md#archive-semantics-and-protection). | | Workspace | Public archive/unarchive/pin APIs preserve membership; `Workspace.detachSession(id)` publicly removes a candidate account member without touching its stored log. Private header indexes and the mutation queue are not deletion extension points. | Identity-bound, coordinated convergence of membership/archive/pin/header observations, with durable recovery confirmation. Public detach is one owned mutation, not a retirement transaction. [Registry declaration][sdk-workspace-types], [public entity interface][sdk-workspace-entity]. | | Projection / query | Cache exposes reads and writes, no per-lifecycle retirement fence; SQLite erases rows only through private reconciliation helpers. | Persisted invalidation epoch/tombstone; drain/reject late write-backs and retained preparations; owned record removal and rebuild/reopen acknowledgement. Raw domain mutation cannot supply this contract. [Cache types][sdk-cache-types], [cache writes][sdk-cache-write], [SQLite][sdk-query]. | | Attachments / request variants | Public save/read/host-path APIs; shared content-addressed bytes and named hard links; no session reference/GC API. | Complete reference inventory, atomic release/retention decision, owned variant cleanup, and receipt stating which shared bytes were preserved. [Store][sdk-attachments], [methods][sdk-attachment-types]. | | Spill / lineage | Session-scoped path grouping and age-based cleanup; the documented retention explicitly permits resumed/forked sessions to reference old locators. | Lifecycle-bound reference ownership and exclusion; a directory named for a Session is insufficient. Unselected child Sessions/forks must not become deletion targets. [Spill declaration][sdk-spill-types], [lineage evidence above](#linked-resources-and-accounting). | | Restart / completion | Current Bin intent/applied/done is a recoverable archive protocol; native owners expose no retirement operation journal. | Owner-side durable fence loaded before admission, per-resource recovery, queryable same-operation receipt, and late same-ID lifecycle refusal. Plugins cannot infer completion from missing paths/list rows or replay irreversible work from an archive journal. [Host protocol](../host-lifecycle.md#持久化协议). | **Admission conclusion:** no audited public owner can implement the proposed complete protocol on this SDK. The tests preserve all session directories, lock files, shared attachments and indexes. They do not validate erasure, shared-reference GC, index removal, actual Agent quiescence or crash recovery during deletion, and do not enlarge the product's supported deletion scope. Implementing a private `rm`/Workspace/cache overlay would leave the gaps unresolved. **Locked declaration follow-up for native-archive authorization:** the concrete JSONL class does declare public `acquireWriteLease(header)` for created-session materialization, while `acquireLease`, `listGenerations` and `locate` are private in its published declaration. This local writer capability is not a verified lifecycle-bound, non-migrating retirement lease or full resource inventory. Workspace entity `detachSession(id)` removes an account member without touching the persisted transcript; SessionStore exact live entry/disposal likewise does not supply an awaited barrier for every resource owner. These partial capabilities leave the admission conclusion unchanged. [JSONL declaration](../../node_modules/@deepseek-ai/dsh-session-persistence-jsonl/lib/types/index.d.ts#L194), [private diagnostic declaration](../../node_modules/@deepseek-ai/dsh-session-persistence-jsonl/lib/types/index.d.ts#L81), [Workspace entity declaration][sdk-workspace-entity]. ## Implications for Session Bin **Design inference:** supported erasure needs a resource owner that can admit the exact lifecycle, exclude writers/new activity during retirement, preserve coordination identity, resolve exclusive/shared resources, and expose durable completion/recovery to Workspace/query/cache consumers. A stable upstream deletion/retention interface would be a stronger foundation than copying private overlays. This is an interface requirement inferred from the locked SDK, not a claim that such an interface exists. [Persistence limits][sdk-persistence-limits], [Session lifetime][sdk-session-runtime], [JSONL lease][sdk-lease], [attachments][sdk-attachments]. The project's boundaries remain: retire only a fixed observed native archive after explicit preparation and execution checks of membership, owner exact lifecycle and frozen scope; legacy Bin v1 journals keep their original authorization binding and recovery path. The native v2 binding is specified in the [Host contract](../host-lifecycle.md#原生归档单项删除准备与授权) and [ADR 0006](../decisions/0006-native-archive-retirement-binding.md). Observation and migration never mint deletion authority. Preserve activity refusal; support one Host owning native Workspace storage; use the same coordination directory for shared Bin backends; do not infer precise archive provenance during unobserved changes; and do not directly remove session directories, lock files, shared attachments, or private indexes to simulate a supported feature. Every new version/provider and resource-lifecycle protocol needs independent evidence. Another plugin's publication, declared range, and CI do not expand Session Bin's runtime support or authorize destructive testing. [Host contract](../host-lifecycle.md), [product/deletion admission](../design-proposal.md). ## 自实现 Adapter 的后续决定 The public SDK interface findings above remain valid. The user subsequently authorized implementing deletion inside this plugin instead of waiting for a native delete endpoint. [ADR 0007](../decisions/0007-native-jsonl-deletion-adapter.md) adopts a version/source-bound cold JSONL owner: exact physical inventory and content identities, existing stable lock exclusion, managed instance admission/read barriers, Workspace/cache medium convergence, and SQLite's own reconciliation transaction. It unlinks confirmed individual log files, retains directories/locks/shared attachment stores, and does not copy the audited references' recursive deletion or directly mutate private SQLite indexes. This is custom Adapter support with its own runtime evidence, not a new public DSH capability or a retroactive success claim for the earlier admission probes. The actual erasure, crash, UI and restricted combinations are recorded in the [Host verification](../verification/host-lifecycle.md) and [client verification](../verification/client-interface.md). ## Primary-source index Reference source links use commit `46af4c54bab466b11ccddf2b63818749ded98c17`. SDK links below identify exact locked public npm `0.2.0-rc.2` files, not a moving branch or research snapshot. Corresponding version-pinned tarballs: [persistence](https://registry.npmjs.org/@deepseek-ai/dsh-session-persistence/-/dsh-session-persistence-0.2.0-rc.2.tgz), [JSONL](https://registry.npmjs.org/@deepseek-ai/dsh-session-persistence-jsonl/-/dsh-session-persistence-jsonl-0.2.0-rc.2.tgz), [Session](https://registry.npmjs.org/@deepseek-ai/dsh-session/-/dsh-session-0.2.0-rc.2.tgz), [Workspace](https://registry.npmjs.org/@deepseek-ai/dsh-workspace/-/dsh-workspace-0.2.0-rc.2.tgz), [projection cache](https://registry.npmjs.org/@deepseek-ai/dsh-session-projection-cache/-/dsh-session-projection-cache-0.2.0-rc.2.tgz), [attachments](https://registry.npmjs.org/@deepseek-ai/dsh-attachment-local/-/dsh-attachment-local-0.2.0-rc.2.tgz), [query SQLite](https://registry.npmjs.org/@deepseek-ai/dsh-session-query-sqlite/-/dsh-session-query-sqlite-0.2.0-rc.2.tgz), [Gateway](https://registry.npmjs.org/@deepseek-ai/dsh-api-gateway/-/dsh-api-gateway-0.2.0-rc.2.tgz), [Connection](https://registry.npmjs.org/@deepseek-ai/dsh-client-connection/-/dsh-client-connection-0.2.0-rc.2.tgz), [Session Controller](https://registry.npmjs.org/@deepseek-ai/dsh-api-session-controller/-/dsh-api-session-controller-0.2.0-rc.2.tgz). [ref-commit]: https://api.github.com/repos/MichengAI/dsh-archive-manager/commits/46af4c54bab466b11ccddf2b63818749ded98c17 [ref-tag]: https://api.github.com/repos/MichengAI/dsh-archive-manager/git/ref/tags/v1.0.13 [ref-release]: https://api.github.com/repos/MichengAI/dsh-archive-manager/releases/tags/v1.0.13 [ref-tree]: https://api.github.com/repos/MichengAI/dsh-archive-manager/git/trees/46af4c54bab466b11ccddf2b63818749ded98c17?recursive=1 [ref-registry]: https://registry.npmjs.org/@michengai%2fdsh-archive-manager [ref-npm-version]: https://registry.npmjs.org/@michengai%2fdsh-archive-manager/1.0.13 [ref-tarball]: https://registry.npmjs.org/@michengai/dsh-archive-manager/-/dsh-archive-manager-1.0.13.tgz [other-registry]: https://registry.npmjs.org/dsh-archive-manager [ref-manifest]: https://github.com/MichengAI/dsh-archive-manager/blob/46af4c54bab466b11ccddf2b63818749ded98c17/package.json [ref-license]: https://github.com/MichengAI/dsh-archive-manager/blob/46af4c54bab466b11ccddf2b63818749ded98c17/LICENSE [ref-readme]: https://github.com/MichengAI/dsh-archive-manager/blob/46af4c54bab466b11ccddf2b63818749ded98c17/README.md [ref-lib-workspace]: https://github.com/MichengAI/dsh-archive-manager/blob/46af4c54bab466b11ccddf2b63818749ded98c17/lib/workspace.js [ref-lib-cache]: https://github.com/MichengAI/dsh-archive-manager/blob/46af4c54bab466b11ccddf2b63818749ded98c17/lib/projcache.js [ref-lib-client]: https://github.com/MichengAI/dsh-archive-manager/blob/46af4c54bab466b11ccddf2b63818749ded98c17/lib/client.js [ref-install]: https://github.com/MichengAI/dsh-archive-manager/blob/46af4c54bab466b11ccddf2b63818749ded98c17/src/host-install.ts [ref-overlay]: https://github.com/MichengAI/dsh-archive-manager/blob/46af4c54bab466b11ccddf2b63818749ded98c17/src/workspace.ts#L1447-L1497 [ref-patch]: https://github.com/MichengAI/dsh-archive-manager/blob/46af4c54bab466b11ccddf2b63818749ded98c17/cordis.patch.yml [ref-compat]: https://github.com/MichengAI/dsh-archive-manager/blob/46af4c54bab466b11ccddf2b63818749ded98c17/src/host-compat.ts [ref-paths]: https://github.com/MichengAI/dsh-archive-manager/blob/46af4c54bab466b11ccddf2b63818749ded98c17/src/workspace.ts#L52-L100 [ref-descriptors]: https://github.com/MichengAI/dsh-archive-manager/blob/46af4c54bab466b11ccddf2b63818749ded98c17/src/workspace.ts#L150-L395 [ref-repair]: https://github.com/MichengAI/dsh-archive-manager/blob/46af4c54bab466b11ccddf2b63818749ded98c17/src/workspace.ts#L570-L583 [ref-favorites]: https://github.com/MichengAI/dsh-archive-manager/blob/46af4c54bab466b11ccddf2b63818749ded98c17/src/workspace.ts#L617-L654 [ref-absence]: https://github.com/MichengAI/dsh-archive-manager/blob/46af4c54bab466b11ccddf2b63818749ded98c17/src/workspace.ts#L675-L726 [ref-archive]: https://github.com/MichengAI/dsh-archive-manager/blob/46af4c54bab466b11ccddf2b63818749ded98c17/src/workspace.ts#L855-L900 [ref-batch]: https://github.com/MichengAI/dsh-archive-manager/blob/46af4c54bab466b11ccddf2b63818749ded98c17/src/workspace.ts#L951-L1035 [ref-delete]: https://github.com/MichengAI/dsh-archive-manager/blob/46af4c54bab466b11ccddf2b63818749ded98c17/src/workspace.ts#L989-L1105 [ref-identities]: https://github.com/MichengAI/dsh-archive-manager/blob/46af4c54bab466b11ccddf2b63818749ded98c17/src/workspace.ts#L1110-L1183 [ref-cold]: https://github.com/MichengAI/dsh-archive-manager/blob/46af4c54bab466b11ccddf2b63818749ded98c17/src/workspace.ts#L1191-L1209 [ref-removal]: https://github.com/MichengAI/dsh-archive-manager/blob/46af4c54bab466b11ccddf2b63818749ded98c17/src/workspace.ts#L1212-L1298 [ref-cascade]: https://github.com/MichengAI/dsh-archive-manager/blob/46af4c54bab466b11ccddf2b63818749ded98c17/src/workspace.ts#L1321-L1379 [ref-cache]: https://github.com/MichengAI/dsh-archive-manager/blob/46af4c54bab466b11ccddf2b63818749ded98c17/src/projcache.ts [ref-tombstone]: https://github.com/MichengAI/dsh-archive-manager/blob/46af4c54bab466b11ccddf2b63818749ded98c17/src/tombstone.ts [ref-organizer]: https://github.com/MichengAI/dsh-archive-manager/blob/46af4c54bab466b11ccddf2b63818749ded98c17/src/archive-organizer.ts [ref-client-batch]: https://github.com/MichengAI/dsh-archive-manager/blob/46af4c54bab466b11ccddf2b63818749ded98c17/src/client.ts#L607-L723 [ref-client-calls]: https://github.com/MichengAI/dsh-archive-manager/blob/46af4c54bab466b11ccddf2b63818749ded98c17/src/client.ts#L4155-L4174 [ref-menu]: https://github.com/MichengAI/dsh-archive-manager/blob/46af4c54bab466b11ccddf2b63818749ded98c17/src/client.ts#L4262-L4305 [ref-delete-copy]: https://github.com/MichengAI/dsh-archive-manager/blob/46af4c54bab466b11ccddf2b63818749ded98c17/src/client.ts#L3886-L3914 [ref-host-tests]: https://github.com/MichengAI/dsh-archive-manager/blob/46af4c54bab466b11ccddf2b63818749ded98c17/test/host.test.mjs [ref-host-delete-tests]: https://github.com/MichengAI/dsh-archive-manager/blob/46af4c54bab466b11ccddf2b63818749ded98c17/test/host.test.mjs#L812-L903 [ref-host-lineage-tests]: https://github.com/MichengAI/dsh-archive-manager/blob/46af4c54bab466b11ccddf2b63818749ded98c17/test/host.test.mjs#L1599-L1640 [ref-host-fault-tests]: https://github.com/MichengAI/dsh-archive-manager/blob/46af4c54bab466b11ccddf2b63818749ded98c17/test/host.test.mjs#L1145-L1567 [ref-host-batch-tests]: https://github.com/MichengAI/dsh-archive-manager/blob/46af4c54bab466b11ccddf2b63818749ded98c17/test/host.test.mjs#L1262-L1365 [ref-host-identity-tests]: https://github.com/MichengAI/dsh-archive-manager/blob/46af4c54bab466b11ccddf2b63818749ded98c17/test/host.test.mjs#L2363-L2425 [ref-host-gateway-tests]: https://github.com/MichengAI/dsh-archive-manager/blob/46af4c54bab466b11ccddf2b63818749ded98c17/test/host.test.mjs#L2426-L2550 [ref-latest-fixture]: https://github.com/MichengAI/dsh-archive-manager/blob/46af4c54bab466b11ccddf2b63818749ded98c17/test/fixtures/latest-host.mjs [ref-ci-run]: https://github.com/MichengAI/dsh-archive-manager/actions/runs/37445537603 [ref-ci-jobs]: https://api.github.com/repos/MichengAI/dsh-archive-manager/actions/runs/37445537603/jobs?per_page=100 [ref-ci-workflow]: https://github.com/MichengAI/dsh-archive-manager/blob/46af4c54bab466b11ccddf2b63818749ded98c17/.github/workflows/test.yml [ref-matrix]: https://github.com/MichengAI/dsh-archive-manager/blob/46af4c54bab466b11ccddf2b63818749ded98c17/scripts/test-version-matrix.mjs [sdk-persistence-types]: <../../node_modules/@deepseek-ai/dsh-session-persistence/lib/types/index.d.ts#L99-L157> [sdk-persistence-limits]: <../../node_modules/@deepseek-ai/dsh-session-persistence/README.md#L152> [sdk-jsonl-layout]: <../../node_modules/@deepseek-ai/dsh-session-persistence-jsonl/README.md#L54-L100> [sdk-jsonl-limits]: <../../node_modules/@deepseek-ai/dsh-session-persistence-jsonl/README.md#L163-L166> [sdk-locate]: <../../node_modules/@deepseek-ai/dsh-session-persistence-jsonl/lib/index.js#L2411-L2420> [sdk-lease]: <../../node_modules/@deepseek-ai/dsh-session-persistence-jsonl/lib/index.js#L612-L729> [sdk-jsonl-lifetime]: <../../node_modules/@deepseek-ai/dsh-session-persistence-jsonl/lib/index.js#L355-L435> [sdk-session-types]: <../../node_modules/@deepseek-ai/dsh-session/lib/types/index.d.ts#L415-L441> [sdk-session-runtime]: <../../node_modules/@deepseek-ai/dsh-session/lib/types/index.js#L934-L1027> [sdk-workspace-types]: <../../node_modules/@deepseek-ai/dsh-workspace/lib/types/index.d.ts#L126-L287> [sdk-cache-types]: <../../node_modules/.pnpm/@deepseek-ai+dsh-session-projection-cache@0.2.0-rc.2_@deepseek-ai+cordis@4.0.4_@deepsee_da38ef051ef02d0e9efd2b60de4aab7e/node_modules/@deepseek-ai/dsh-session-projection-cache/lib/types/index.d.ts#L53-L165> [sdk-attachments]: <../../node_modules/.pnpm/@deepseek-ai+dsh-attachment-local@0.2.0-rc.2_@deepseek-ai+cordis@4.0.4_@deepseek-ai+dsh_29d677c1a811b3450ea239f4c669b10f/node_modules/@deepseek-ai/dsh-attachment-local/README.md#L55-L151> [sdk-query]: <../../node_modules/.pnpm/@deepseek-ai+dsh-session-query-sqlite@0.2.0-rc.2_@deepseek-ai+cordis@4.0.4_@deepseek-ai_713598a3e3c9bcba814f71654813b06d/node_modules/@deepseek-ai/dsh-session-query-sqlite/lib/index.js#L646-L788> [sdk-connection]: <../../node_modules/@deepseek-ai/dsh-client-connection/README.md#L39-L45> [sdk-connection-runtime]: <../../node_modules/@deepseek-ai/dsh-client-connection/lib/index.js#L585-L594> [sdk-gateway-peer]: <../../node_modules/@deepseek-ai/dsh-api-gateway/lib/index.js#L798-L807> [sdk-client-removal]: <../../node_modules/@deepseek-ai/dsh-api-session-controller/lib/types/client/sessions/manager.js#L589-L615> [sdk-client-session]: <../../node_modules/@deepseek-ai/dsh-api-session-controller/lib/types/client/sessions/session.js#L495-L525> [sdk-workspace-entity]: <../../node_modules/@deepseek-ai/dsh-workspace/lib/types/types.d.ts#L112-L120> [sdk-header]: <../../node_modules/@deepseek-ai/dsh-session/lib/types/types.d.ts#L54-L122> [sdk-jsonl-open]: <../../node_modules/@deepseek-ai/dsh-session-persistence-jsonl/lib/index.js#L2454-L2519> [sdk-jsonl-discovery]: <../../node_modules/@deepseek-ai/dsh-session-persistence-jsonl/lib/index.js#L3031-L3092> [sdk-agent-close]: <../../node_modules/.pnpm/@deepseek-ai+dsh-agent-loop@0.2.0-rc.2_0c5ce3d184ce320f0d23631770cc12ac/node_modules/@deepseek-ai/dsh-agent-loop/lib/index.js#L1677-L1709> [sdk-cache-write]: <../../node_modules/.pnpm/@deepseek-ai+dsh-session-projection-cache@0.2.0-rc.2_@deepseek-ai+cordis@4.0.4_@deepsee_da38ef051ef02d0e9efd2b60de4aab7e/node_modules/@deepseek-ai/dsh-session-projection-cache/lib/index.js#L266-L355> [sdk-attachment-types]: <../../node_modules/.pnpm/@deepseek-ai+dsh-attachment-local@0.2.0-rc.2_@deepseek-ai+cordis@4.0.4_@deepseek-ai+dsh_29d677c1a811b3450ea239f4c669b10f/node_modules/@deepseek-ai/dsh-attachment-local/lib/types/index.d.ts#L65-L87> [sdk-spill-types]: <../../node_modules/.pnpm/@deepseek-ai+dsh-spill-local@0.2.0-rc.2_@deepseek-ai+cordis@4.0.4_@deepseek-ai+dsh-spil_b16f5c9476445e95b067f2cbec48e025/node_modules/@deepseek-ai/dsh-spill-local/lib/types/index.d.ts#L29-L51>