# kcode-k1-web-source-object
`kcode-k1-web-source-object` preserves a canonical `kcode_k1_web_package::SourcePackage` as a K1 Objects transaction and retains the resulting transaction identifier for the caller.
## API
- `SourceObjectCapture::new(objects: &K1Objects) -> SourceObjectCapture<'_>` creates an empty capture associated with `objects`.
- `SourceObjectCapture::preserve(&self, package: &SourcePackage) -> Result<(), String>` encodes `package` with `kcode_k1_web_transaction::encode`, then saves the resulting bytes through `K1Objects::save("", "k1-web-source-package-v1", "", bytes)`. On successful save it records that transaction's `TxId`, replacing any previously recorded ID.
- `SourceObjectCapture::captured(&self) -> Option<TxId>` returns a copy of the most recently recorded transaction ID. It returns `None` before a successful preservation and when the capture mutex is poisoned.
- `SourceObjectCapture::finish(self) -> Result<TxId, CaptureStateError>` consumes the capture and returns the recorded ID. It returns `CaptureStateError::Missing` if no ID was recorded and `CaptureStateError::Poisoned` if the mutex is poisoned.
- `CaptureStateError` has the variants `Poisoned` and `Missing`, implements `Display` and `std::error::Error`, and has stable display messages.
## Effects and ordering
`preserve` performs no Objects save if encoding fails. It acquires the capture mutex before saving. While that mutex is held, it saves the encoded bytes to Objects; only after a successful save does it replace the captured ID. Thus a failed save leaves the prior captured ID unchanged. If locking fails because the mutex is poisoned, no save is attempted. A successful call has the external effect of creating an Objects transaction and the in-memory effect of recording its ID.
Calling `preserve` more than once may create more than one Objects transaction; `captured` and `finish` expose only the ID from the last successful call.
## Errors
Encoding failures, Objects save failures, and a poisoned mutex in `preserve` are returned as `String` values. `finish` reports absent or poisoned capture state using `CaptureStateError`. `captured` intentionally collapses both absent and poisoned state to `None`.
## Concurrency and performance
The capture state is protected by a `Mutex`, so `preserve` calls on the same capture are serialized through the complete save operation. `captured` also locks that mutex. Encoding allocates the encoded package bytes; the dominant work and latency are the package encoding and the underlying `K1Objects::save` operation. The crate performs no retrying, batching, persistence beyond the Objects save, or background work.