[REFACTOR] Freeze the capsule-core public API and remove the dead surface - #426
Open
justin13888 wants to merge 9 commits into
Open
[REFACTOR] Freeze the capsule-core public API and remove the dead surface#426justin13888 wants to merge 9 commits into
justin13888 wants to merge 9 commits into
Conversation
`capsule-core` carried public items with zero call sites anywhere in the
workspace. Each one is a promise the crate cannot retire later without a
breaking change, so they go before the API is frozen.
Removed:
- `models` (`Asset`, `Album`) — plaintext-era types, zero references.
- `constants::IGNORE_RULES` — the only hit was its own definition.
`SIDECAR_EXTENSIONS` stays; `metadata` reads it.
- `validation::idempotency` (`IdempotencyKey`, `session_key`, `chunk_key`)
— zero references outside the barrel re-export.
- `metadata::export_policy` (`ExportOptions`, `strip_for_export`) — zero
code call sites. The design docs and `capsule-server`'s share module
both claimed it implemented the boundary-crossing strip; they now say
the strip is unimplemented and point at `S-C50`, which is the truth.
A documented security control with no caller is worse than an absent
one.
`utils::hash` was *not* dead and is folded rather than deleted:
`get_file_hash` becomes `crypto::hash::hash_file`, returning `Hash32`
like its neighbours instead of a hex `String`, and the `String` twin
`utils::hash::hash_bytes` gives way to `crypto::hash::hash_bytes(..)
.to_hex()`. One hash module, one return type. `utils` keeps `paths`.
Two known-answer tests cover the folded entry point: `hash_file` over a
file larger than the 64 KiB read block equals the one-shot digest, and a
missing path surfaces `NotFound` rather than a panic.
BREAKING CHANGE: `capsule_core::models`, `constants::IGNORE_RULES`,
`validation::{idempotency, IdempotencyKey}`, `metadata::export_policy`
and `utils::hash` are removed. `utils::hash::get_file_hash` is now
`crypto::hash::hash_file` and returns `Hash32`.
Deploying capsule with
|
| Latest commit: |
f508bf1
|
| Status: | ✅ Deploy successful! |
| Preview URL: | https://eb94ab59.capsule-22k.pages.dev |
| Branch Preview URL: | https://chore-freeze-capsule-core-ap.capsule-22k.pages.dev |
`library`, `import`, `db`, `crypto::keys`, `sidecar` and `domain` each
declared every submodule `pub mod` *and* re-exported its types through a
barrel, so every public type had two paths. `capsule-sdk` and
`capsule-server` used both spellings for the same type.
`lifecycle/mod.rs` is the model this follows.
59 declarations become `pub(crate) mod`. `pub(crate)` rather than plain
`mod` because the 175 intra-crate deep references then compile unchanged;
plain `mod` would rewrite all of them for the same external effect
(`pub(crate)` items are absent from rustdoc and unreachable from every
other crate).
Barrels completed, so nothing reachable became unnameable:
- `sidecar` exports all 11 `sidecar_v1` items. `CullFlag` and `GpsSource`
are needed by `capsule-cli`; the rest are field types of `SidecarV1`.
- `library` exports `paths::thumbnail_path` (a `capsule-core` test used
it) and `receipts::ReceiptStoreError` (the error type of the already
re-exported `append_receipt` — reachable but unnameable without it).
The 22 items privatization stranded — declared `pub`, now unreachable
outside the crate, and with no consumer outside it — are demoted to
`pub(crate)` rather than added to a barrel: `db::migrate::{migrate,
BASELINE_VERSION, Ddl, Step, STEPS}`, `db::schema::{SCHEMA_VERSION,
DDL}`, `import::group::{is_raw, is_primary, is_video, is_xmp}`,
`import::importers::takeout` (the barrel already re-exports
`TakeoutAdapter`), `library::lock::{LockRecord, try_acquire, release}`,
`library::scrub::startup_scrub`, `sidecar::library_version::
CURRENT_LIBRARY_VERSION`, `crypto::keys::albumstore::{ALBUM_STORE_VERSION,
ALBUM_STORE_FILE}` and `crypto::keys::kem::DEK_SEED_LEN`. A frozen API
should not gain surface as a side effect of hiding a module. `-W
unreachable_pub` (already in `CLIPPY_FLAGS`) is what found them; a
transient `#![warn(unnameable_types)]` found the two barrel gaps.
`library::receipts` no longer re-exports `BlobRole`/`role_str`; they keep
their one public home in `crypto::receipts`, which the barrel already
reaches through `library::storage_verify::BlobRole`.
32 consumer imports across 21 files move to the barrel path.
`import::scanner::scan` is `import::scan_paths`, the name the barrel
already gave it.
BREAKING CHANGE: the submodules of `capsule_core::{library, import, db,
crypto::keys, sidecar, domain}` are no longer public. Every type they
held is reached through its parent barrel instead — one path per type.
`execute_streaming` and `execute_streaming_with_source_metadata` were the same function twice: eight positionals each, both behind `#[allow(clippy::too_many_arguments)]`, differing only in whether the caller supplied a `SourceMetadataIndex` or the thin twin substituted an empty one. Neither had a caller outside the barrel. They collapse into one entry point taking `StreamingOptions` — config, source, uploader, verifier, headroom margin, cancellation token — leaving four arguments. `on_event` stays positional: as a field it would force a third type parameter on the struct for no gain. `stream_candidate` takes the same struct rather than four of its fields, going from eight arguments to five. All three `#[allow(clippy::too_many_arguments)]` in the crate are gone. Behaviour is unchanged: a caller that wants no enrichment passes `&SourceMetadataIndex::empty()`, exactly what the thin twin did for it. BREAKING CHANGE: `capsule_core::import::execute_streaming_with_source_metadata` is removed and `execute_streaming` takes a `StreamingOptions` in place of its six middle arguments.
`cargo doc` was never a gate, so 73 intra-doc link errors had accumulated across `capsule-core`, `capsule-wasm` and `capsule-i18n`. This clears them so the next commit can gate on it. No code changes. Six links pointed at `crate::media`, a module that left the tree, and three doc comments described a `media` feature `capsule-core/Cargo.toml` has never declared. Both are demoted to prose that says what is true: the media stack is retired to `legacy-review/` and restoring it is `S-B1`, so this build links no still encoder and no codecs at all. Fourteen links named genuinely private items (`PINNED_CIPHERSUITE`, `CapsuleMlsProvider`, `MlsAppPayload`, `require_canonical_runner`, `gcj02_to_bd09`, the `db::migrate` internals, …). Those become code spans: a private item has no URL, and pretending otherwise is what the lint objects to. Seven `verify_asset` links were ambiguous — `crate::crypto::verify_asset` is both a module and a function. Every one of them meant the function; they are disambiguated with `fn@`. Thirteen were redundant explicit link targets, resolving to exactly what the shortcut already resolved to. Fourteen were unresolved because the crate root carries its own `///` doc on `pub mod sharing;`, `pub mod client_build;` and `pub mod lqip;`. rustdoc merges those with each module's `//!` header and resolves the merged text in the crate-root scope, where `LINK_SECRET_LEN`, `Lqip`, `BUILD_COMMIT` and the rest are not in scope. Fully qualifying them makes the link independent of which scope wins. The remaining 22 doc links spelled a path through a submodule the previous commit made crate-private. They still resolved — the target items are re-exported — but a frozen API documenting a second spelling of its own paths is the thing this series exists to remove, so each moves to its barrel path. `capsule-wasm` and `capsule-i18n` had one each, both naming a private module in crate-level prose.
`cargo doc` ran nowhere, so a broken intra-doc link, an ambiguous one, or public documentation pointing at a private item merged unnoticed — 73 of them had accumulated by the time the previous commit cleared them. `doc-check-rust` runs `cargo doc --no-deps` under `RUSTDOCFLAGS="-D warnings"` and sits in `check-rust` immediately after clippy, where the same class of failure already lives. `--no-deps` so a dependency's own doc warnings cannot fail this build. Scoped to the four crates #399 declares frozen. `capsule-server` (12 spans), `capsule-sdk` (8) and `capsule-cli`/`capsule-wire`/`xtask` (1 each) still fail and are widened in a follow-up rather than fixed in a commit about the gate. Verified negatively: reintroducing a `crate::media` link fails the task.
`capsule-wasm` had zero Rust tests, and `capsule-sdk` sat outside `default-members`, so a bare `cargo test` skipped the crate whose push, staged, net and recovery tests this series' import rewrites touch. `capsule-sdk` joins `default-members`. `capsule-wasm` stays out deliberately: its real artefact needs `--target wasm32-unknown-unknown`, on the host its `cdylib` links a library nothing consumes, and the wasm surface is already gated by `build-check-wasm`. `cargo nextest run --workspace` (what `test-rust` runs) covers the new tests either way. Five host tests over the crate's pure, JS-free functions: - `sharing_code` and `open_code` map every `SharingError` variant, with the security property asserted directly: on the open path a wrong passphrase and a wrong fragment secret must produce the *same* code, or the viewer becomes an oracle for which half of a link was wrong. - an exhaustive match that fails the build if a variant is added upstream without a boundary code, rather than letting it reach the viewer as an unmapped string. - `hex_array` over a canonical 64-char fragment, whitespace included. - `decode_wrapped` over a base64 round trip of a canonical `WrappedScope`. Ok paths only, and the module comment says why: every `Err` arm builds a `JsError`, whose `__wbindgen_error_new` extern is a panicking placeholder off `wasm32`. Error-path behaviour at the boundary stays covered by `capsule-web`'s bun KATs.
…ore/freeze-capsule-core-api-399
…rface Four defects an adversarial read of this branch turned up. No behaviour change beyond the `hash_file` gate, which removes a call that could only ever fail. **`S-C50` does not implement the privacy strip.** `SLICES.md:280` records it as a **docs** slice, already `done`: it settled *where* the boundary-crossing strip belongs (the issuing client) and left the mandatory, no-opt-out rule binding that client. It writes no code. `capsule-docs/.../metadata.md` and `capsule-server/src/share/mod.rs` both pointed future implementation work at it. They now say what is true: the strip is the issuing client's obligation, nothing implements it, and no slice owns writing the real one. The same status note also claimed the export surface "v1 ships" while calling it unimplemented two sentences earlier; it now separates what is specified from what is built — the server's containment half ships, the client-side strip does not. **`crypto::hash::hash_file` is now `native`-gated.** It replaced `utils::hash::get_file_hash`, and `utils` is `native`; `crypto::hash` is deliberately not, because it is part of the `--no-default-features` wasm32 sealing surface. An ungated `hash_file` therefore compiled for `wasm32-unknown-unknown` — `std::fs` is stubbed there, not absent — and would have failed at runtime on every call. Both callers are `native` anyway, so the gate costs nothing and keeps the browser build's public surface free of a filesystem API. **Two doc-accuracy fixes.** `StreamingOptions` said both replaced entry points carried eight arguments; the twin carried nine. The new `capsule-wasm` exhaustiveness test asserted `!code.is_empty()` on functions that return non-empty `&'static str` consts — an assertion that cannot fail. It now pins both codes to the declared `err::` set, so a newly added variant cannot answer with an ad-hoc literal the viewer has no catalog key for, and checks that the hand-written variant list does not repeat itself.
This was referenced Sep 2, 2026
`cargo doc --no-deps` documents public items only. The commit that made 59 submodules of `library`, `import`, `db`, `crypto::keys`, `sidecar` and `domain` crate-private therefore walked them out of the gate's reach: the gate this series added went blind to exactly the modules the same series touched, and 11 pre-existing broken links inside them were hidden rather than fixed. `doc-check-rust` now passes `--document-private-items`, so every item in the four frozen crates is linted. That surfaces 23 errors, all repaired here — 22 in `capsule-core`, 1 in `capsule-i18n`; `capsule-core-ffi` and `capsule-wasm` were already clean. Fourteen unresolved links, each for a stated reason: - `HardwareSigner` is implemented in `tbs`'s `#[cfg(windows)] backend` submodule and never imported at module scope, so the bare name resolved nowhere — four links now go through `super::HardwareSigner`. - `keys::tpm` is `#[cfg(feature = "tpm")]` and has no doc page in a default build; three links to it become prose that says so. - `p256::parse_p256_public` is private to a sibling module and so is not nameable from `tbs` at all — code span. - `Tbsi_Is_Tpm_Present` is a `windows-sys` extern behind `cfg(windows)`; it gets a Win32 URL reference, matching `Tbsip_Submit_Command` in the same header. - `ingest_current_epoch` is a method, not a free item in its module; `ProtocolMessage`, `encrypt_asset_rekey` and `ReferenceAuthority` were not in their item's scope. All four now carry a resolvable path. Seven redundant explicit link targets drop to the shortcut form, and two ambiguous links (`crypto::verify_asset`, `crate::negotiate` — each both a module and a function) are disambiguated with `fn@`; both meant the function. No `#[allow]` was added: every remaining link either resolves or was demoted to a code span that states why it cannot. Verified negatively: a broken link introduced in `import/streaming.rs` — a now-crate-private module — fails the new gate and **passes** the old public-only one. Two further review findings: - `library::receipts`' module doc still said `BlobRole`/`role_str` were re-exported there after that re-export was removed. It now says where they are actually reached: `crypto::receipts::BlobRole`, and `library::BlobRole` through the storage-verify barrel. - `keystore`'s `DeviceDek` doc said the two byte formats are length-disjoint but linked one type. It now names both, `DekKeypair` and `P256HybridDek`, in shortcut form. Finally, `capsule-wasm`'s duplicate-variant guard used `Vec::dedup`, which collapses only *consecutive* duplicates — `[A, B, A]` kept its length and passed. It uses a `HashSet` of discriminants now; confirmed by introducing a non-adjacent repeat and watching the test fail.
5 tasks
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Description
Freezes the
capsule-corepublic API: exactly one path per public type, nothing publicwithout a call site, and
cargo docpromoted to a CI gate on the four crates #399 declaresfrozen.
Behaviour-preserving throughout. The only non-mechanical edits are
execute_streaming'soptions struct and the
utils::hashfold, and neither had a caller outsidecapsule-core.Six commits, one per slice, each green on its own before the next was written.
Summary
refactor(core)!: delete the dead public surfacemodels,constants::IGNORE_RULES,validation::idempotency,metadata::export_policy— all with zero call sites. Foldsutils::hashintocrypto::hashashash_file(&Path) -> io::Result<Hash32>and drops theStringtwin ofhash_bytes. Two KATs cover the folded entry point.refactor(core)!: make the six barrel modules' submodules crate-privatepub mod→pub(crate) modacrosslibrary,import,db,crypto::keys,sidecar,domain; barrels completed (all 11sidecar_v1items,library::thumbnail_path,library::ReceiptStoreError); 22 strandedpubitems demoted rather than exported; 32 consumer imports in 21 files moved to the barrel path.refactor(core)!: give execute_streaming an options structStreamingOptionsreplaces the two eight-positional twins. All three#[allow(clippy::too_many_arguments)]in the crate are gone.docs(core): fix the intra-doc links the rustdoc gate rejectscrate::medialinks + 3 falsemedia-feature claims, 14 private-item links, 7 ambiguousverify_assetlinks, 13 redundant explicit targets, 14 scope-resolution failures, and 22 doc paths that spelled a now-private submodule.ci(rust): gate rustdoc on the frozen crates[tasks.doc-check-rust]—cargo doc --no-depsunderRUSTDOCFLAGS="-D warnings"— insidecheck-rust, right after clippy.test(wasm): add host-runnable unit tests; widen default-memberscapsule-wasm's pure functions (including the wrong-passphrase/wrong-fragment oracle property);capsule-sdkjoinsdefault-members.fix(core): correct the S-C50 claim and keep hash_file off the wasm surfacefix(core): gate rustdoc over private items, and repair what that revealsdoc-check-rustgains--document-private-items(the gate had gone blind to the 59 modules this PR privatised) and the 23 errors that reveals are repaired; plus three smaller review findings. See Review round below.Two corrections to the issue's dead-item list
The issue named two items as dead that are not, found by grep before any deletion:
utils::hashis live —hash_bytesatcapsule-sdk/src/recovery/mod.rs:678,get_file_hashatcapsule-core/src/import/planner.rs:237andcapsule-core/src/metadata/file.rs:8. It is folded, not deleted.ffi::p256_hardware_dek_round_tripis live — 4 call sites incapsule-core-swift/Tests/CapsuleHardwareTests/SmokeTests.swift:197,217. Retained.What the issue asked for and this does not do
ffi/ffi-bindgenretirement and thecapsule-core/src/ffi.rsrelocation → core-ffi: retire the capsule_core uniffi namespace, which is harness-only today #424,with the blocking evidence recorded (a name collision inside the single Swift target that
compiles both generated namespaces, and three uniffi surfaces
capsule-sdkdoes not have).ROADMAP.mdbullet:ROADMAP.mddoes not exist in the tree (find . -iname 'ROADMAP*'is empty). It is being created by docs: reset the tracker and design docs to what the tree holds, and add ROADMAP.md #398 and recorded by roadmap: final API audit and tracker recount after the programme's pull requests #417; editing it here was off-limits.
Findings raised against this diff, and what was done
The branch was read adversarially before this PR was handed over. Everything in the code was
clean — no lost
?, no changed hash or encoding, no droppedtracingfield, no changed errorvariant, no swapped test argument, no type divergence from the privatization. Four real defects
were in what the diff wrote, and commit 7 fixes all four:
S-C50does not implement the privacy strip (the worst of the four). Slices 1's proseedits said "
S-C50is the slice that implements it".SLICES.md:280records S-C50 as adocs slice, already
done: it settled where the strip belongs and wrote no code. Theprose now says the strip is the issuing client's obligation, nothing implements it, and no
slice owns writing one — and that gap is filed as core: the share-link privacy strip has no implementation and no slice owns writing one #432. The same status note also called
the export surface one that "v1 ships" two sentences after calling it unimplemented; it now
separates what is specified from what is built.
hash_filelanded on the always-compiled wasm surface.utils::hashwasnative;crypto::hashdeliberately is not, because it is the--no-default-featureswasm32 sealingsurface.
std::fsis stubbed onwasm32-unknown-unknown, not absent, so an ungatedhash_filecompiled there and would have failed at runtime on every call. Now#[cfg(feature = "native")]; both callers arenativeanyway.StreamingOptions' doc miscounted. It said both replaced entry points carried eightarguments; the twin carried nine.
capsule-wasmexhaustiveness test asserted!code.is_empty()on functions returning non-empty&'static strconsts. It now pins bothcodes to the declared
err::set, so a newly added variant cannot answer with an ad-hocliteral, and checks the hand-written variant list does not repeat itself.
Two observations accepted rather than changed, both recorded here because nothing else records
them:
tracingspan for a streaming run is renamed.#[tracing::instrument]sat onexecute_streaming_with_source_metadata, and the thinexecute_streamingwrapper delegated toit, so every streaming run emitted a span named
execute_streaming_with_source_metadata. Itis now
execute_streaming. The four fields are unchanged in name, expression and meaning, andno in-tree consumer greps the old name — but an external log query or dashboard keyed on it
would need updating. This is the only observable behaviour change in the PR.
SLICES.md:1208and:3817still namecapsule_core::metadata::export_policy.SLICES.mdis owned by other lanes and off-limits here;
check-docs-truthdoes not scan it, so no gatefails. Recorded in core: the share-link privacy strip has no implementation and no slice owns writing one #432 and in Unresolved review notes below.
Review round (commit 8)
A review of
718bc820raised four findings; all four are closed.M1 — the gate was guarding least exactly what this PR changed.
cargo doc --no-depsdocuments public items only, so once commit 2 made 59 submodules
pub(crate), their//!headers and item docs left the gate's reach. Running the same flags with
--document-private-itemsfails with 23 errors: 11 pre-existing ones inside those modules thatcommit 4 had hidden rather than fixed (
crypto/keys/tbs.rs×8,albumstore.rs:113,import/streaming.rs:13,14,import/planner.rs:144), plus L2 and L3 below and nine more.The task now carries the flag and every one of the 23 is repaired — no
#[allow]was added;each link either resolves or is a code span that states why it cannot (a
tpm-feature-gatedmodule, a private sibling helper, a
cfg(windows)extern).L2 —
library/receipts.rs:12still saidBlobRole/role_strwere re-exported there aftercommit 2 removed that re-export. It now names where they are reached:
crypto::receipts::BlobRole, andlibrary::BlobRolethrough the storage-verify barrel.L3 —
crypto/keys/keystore.rs:44— commit 4's rewrite was a redundant explicit target andpointed at one type where the sentence means both byte formats. It now names both,
DekKeypairand
P256HybridDek, in shortcut form.L4 —
capsule-wasm's duplicate-variant guard usedVec::dedup, which collapses onlyconsecutive duplicates, so
[A, B, A]kept its length and passed. It uses aHashSetofdiscriminants now, confirmed by introducing a non-adjacent repeat and watching the test fail.
Validation
Every command run inside the worktree at
d64c2cdf.mise run check-rustformat-check-rust,lint-check-rust, the newdoc-check-rust,i18n-check,i18n-guard,openapi-check-kynos,architecture-check,license-check,translate-readme-check,build-rust,build-check-wasm,build-ffi,lint-check-ffi,gen-bindings,verify-examplesmise run test-rustmise run check-docs-truthmise run check-mdmise run check-docscargo check --workspace --all-targetsmise run lint-check-rustmise run doc-check-rust(cargo doc --no-deps --document-private-itemson the four frozen crates,-D warnings)f433d918→ 0 (commit 4). All-item errors: 23 remaining after commit 4 → 0 (commit 8).mise run build-check-wasmwasm32-unknown-unknownsealing surface still type-checks withhash_fileadded to the always-compiledcrypto::hashmise run gen-bindingssurface check passed: S-D9 client/session + S-P1 workspace verbs present in both languages; no FFI file is touched by this PRBuild Capsule.apk + :core JVM smokecapsule-android/src/androidMain/kotlin/**: unresolvedinitKoin,ListViewModel,DetailViewModel, thedipackage,title/artistDisplayName/objectDate. This PR touches zero Kotlin, Android, or.ktsfiles —git diff f433d918..HEAD --name-only | grep -iE '\.kts?$|capsule-android|capsule-core-kotlin'→ 0. The same job fails on the base branch's own PR #418 and onmaster(gh run list --branch master→ `Build Android appmise run build-ffi-apple,test-swift,test-kotlincapsule-core/src/ffi.rs, the harnesses,stage-bindings.shorbuild.gradle.kts, so their inputs are unchanged and host-runnablegen-bindingsis the proxy.Negative tests of the gate, both reverted after running:
crate::media::image::types::RawImageFormatdoc link makesmise run doc-check-rustexit non-zero withunresolved link;import/streaming.rs— a module commit 2 made crate-private — failsthe gate as it now stands and passes the public-only form it replaced. That is the blindness
commit 8 closes, demonstrated rather than asserted.
Success criteria, measured
f433d918grep -rE "capsule_core::(library|import|db|crypto::keys|sidecar|domain)::[a-z_0-9]+::"over the consumer cratescapsule-core/src/models/,IGNORE_RULES,validation/idempotency.rs,metadata/export_policy.rs,utils/hash.rsRUSTDOCFLAGS="-D warnings" cargo docon the frozen crates, public items--document-private-items)#[allow(clippy::too_many_arguments)]incapsule-corecargo test(bare) coverscapsule-sdkcapsule-wasmRust testsPre-existing warnings, not addressed
Two
cargo check --all-targetswarnings predate this branch and are left alone rather thanabsorbed into a refactor commit:
capsule-core/src/import/group.rs:211(find_candidateisnever used) and
capsule-core/src/library/receipts.rs:93(two unused test imports). Neitheris in the lib target, so neither fails
lint-check-rust.Risks and rollout
No persisted data, wire format, or deployed behaviour changes. Sidecar CBOR, the OpenAPI
document, and the uniffi ABI are untouched; no generated binding is committed (they are
.gitignored and regenerated bystage-bindings.sh/build.gradle.kts). Every slice is asource-level rename, deletion, or doc edit, reversible by
git revertof that commit.Two residual risks worth naming:
-D warningson rustdoc is toolchain-sensitive. A toolchain bump can add lints andbreak
doc-check-rust.rust-toolchain.tomlpins the toolchain, so the gate isreproducible; a bump must re-run it.
metadata::export_policyremoved a documented (but unimplemented) security control.capsule-docs/.../metadata.mdandcapsule-server/src/share/mod.rsnow say theboundary-crossing strip is unimplemented and point at
S-C50, which is what was true.Related Issues
Refs #399 — the API freeze lands; the FFI retirement and the workspace-wide rustdoc gate are
filed as #424 and #425, and the
ROADMAP.mdbullet belongs to #417.Filed by this PR: #424 (
core-ffi: retire the capsule_core uniffi namespace, which is harness-only today), #425 (ci: extend the rustdoc gate to the whole workspace), #432(
core: the share-link privacy strip has no implementation and no slice owns writing one) —the last opened after removing
metadata::export_policyrevealed that the strip it was citedas implementing exists nowhere.
Contributor Checklist
Decisions taken
Decisions taken inside the manifest during delivery
Unresolved review notes
SLICES.md:1208andSLICES.md:3817still namecapsule_core::metadata::export_policy,which slice 1 deleted.
SLICES.mdis owned by other lanes in this run and was off-limits tothis one;
check-docs-truthscanscapsule-docs/, notSLICES.md, so no gate catches it.Recorded in core: the share-link privacy strip has no implementation and no slice owns writing one #432 and appropriate for roadmap: final API audit and tracker recount after the programme's pull requests #417's tracker reconciliation.
The rename of the streamingSettled by decision 9: the span keeps its new nametracingspan is the one observable behaviour change in thisPR.
execute_streaming. It remainsthe one observable behaviour change, and it has no deployed consumer — the server has no
binary yet (server: give capsule-server a binary, configuration, operator commands and a serve task #401) and CLI traces are local.