Skip to content

feat: mount privacy remediation, multi-root dashboard scope, native-integration notifications - #516

Merged
ScriptedAlchemy merged 17 commits into
codex/tracedecay-total-redesign-planfrom
cursor/mount-privacy-multiroot-native-511e
Aug 19, 2026
Merged

feat: mount privacy remediation, multi-root dashboard scope, native-integration notifications#516
ScriptedAlchemy merged 17 commits into
codex/tracedecay-total-redesign-planfrom
cursor/mount-privacy-multiroot-native-511e

Conversation

@ScriptedAlchemy

Copy link
Copy Markdown
Owner

Mounts the three unmounted product claims (B5/B6/B7 from the V2 implementation audit) as real production journeys. No version bumps.

B5 — At-rest privacy remediation (feat(privacy))

  • New owner: MemoryApplication::privacy_remediation_rescan (crates/tracedecay-usecases/src/memory/privacy_remediation.rs) re-runs the current in-process detector over every currently served project-memory fact, redacts what the detector can make safe, quarantines (removes from serving) what it cannot, and settles all mutations through the canonical curation authority — one atomic batch, one durable ProjectMemoryFactCurationReceiptV1, plus a typed ProjectMemoryPrivacyRemediationReceiptV1 (trigger, detector revision, scanned/clean/redacted/quarantined counts).
  • Daemon production caller: project-open spawns the rescan as bounded background work (src/daemon/privacy_remediation.rs) after fail-closed admission; it never blocks admission or retrieval. No scanner binary, no network, no unsanitized payload persisted.
  • Test: seeds legacy receipt-bound rows the current rules never evaluated (redactable secret in content; quarantinable secret-bearing metadata key), proves the rescan quarantines/redacts them with truthful receipt counts, that no served fact retains the hit, and that a second pass is clean and settles nothing.

B6 — Named multi-root collection resolver for the dashboard (feat(multi-root))

  • Application resolver (crates/tracedecay-application/src/multi_root/collection.rs): selection precedence (MultiRootCollectionSelectorV1 — a default collection can never outrank an explicit target) and typed resolution states (Mounted with the frozen scope-set revision and canonical member order, or typed unavailable: transport-not-admitted / no-collection-named / not-persisted / authority fault).
  • Dashboard mount: GET /api/multi-root/collection?collection=<scope-set-id> resolves an explicit named collection through the daemon scope-set read (DashboardApplicationRuntime::read_multi_root_scope_set, implemented over MultiRootScopeSetRead); /api/capabilities now reports the resolver's typed states instead of the hardcoded "no multi-root scope set is mounted" string, and features.multi_root reflects the mounted resolver.
  • Tests: precedence and mapping unit tests; dashboard tests proving an explicit persisted collection resolves as mounted (id/revision/digest/root count), an unknown collection stays typed not-persisted, and capabilities report the typed no-default state.

B7 — Native-integration dashboard status + LSP notification (feat(native-integration))

  • Catalog: only the read-only native_integration_status operation gains a Dashboard binding surface; every mutating transaction operation stays CLI/MCP-only, so no gateway can advance a transaction, apply edits, or mutate Git.
  • Dashboard: GET /api/native-integration/status?transaction_id=… answers the same NativeIntegrationSurfaceResultV1 CLI and MCP project, resolved through the catalog-bound dashboard surface; standalone dashboards answer the typed authority_unmounted state.
  • LSP: the daemon invocation handler publishes observed NativeIntegrationStatusProjectionV1 into a per-project fan-out (NativeIntegrationStatusBroadcastV1); ready LSP sessions forward changed projections as read-only tracedecay/nativeIntegrationStatus server-to-client notifications with per-session dedupe. No client-callable native-integration LSP method is admitted.
  • Tests: mount test proving the dashboard binding is status-only; session tests proving each status change notifies exactly once, terminal outcomes are forwarded, and uninitialized sessions receive nothing; broadcast retention/regression tests; dashboard route tests.

Verification

  • cargo check --all-features clean; clippy clean on touched crates.
  • tracedecay-application (390), tracedecay-lsp (181), tracedecay-usecases (780) lib suites green; tests/native_integration_surface_mount (8) green; the new daemon privacy remediation test green.
  • tracedecay-dashboard-api lib: 200 passed, 1 failure (doctor_findings_api::…_preserves_canonical_unknown_entries, 11 vs 10) — verified pre-existing by running the identical test on the base branch in a clean worktree; unrelated to this change.
  • Commit messages pass commitlint.
Open in Web Open in Cursor 

cursoragent and others added 4 commits August 19, 2026 04:41
The dashboard resolves a named multi-root collection (a persisted scope
set with a frozen revision and canonical member order) through the daemon
application transport: GET /api/multi-root/collection resolves explicit
targets and /api/capabilities reports the resolver's typed states instead
of a hardcoded unmounted string. Selection precedence lives in the
application resolver, where a default collection can never outrank an
explicit target.

Co-authored-by: Zack Jackson <ScriptedAlchemy@users.noreply.github.com>
The dashboard reads one native-integration transaction status over the
catalog-bound dashboard surface (GET /api/native-integration/status),
answering the same application result CLI and MCP project; only the
read-only status operation gains a dashboard binding, so no gateway can
advance a transaction, apply edits, or mutate Git. The daemon handler
publishes observed status projections into a per-project fan-out, and
ready LSP sessions forward changed projections as read-only
tracedecay/nativeIntegrationStatus notifications.

Co-authored-by: Zack Jackson <ScriptedAlchemy@users.noreply.github.com>
Project-open now spawns a bounded background PrivacyRemediation pass per
adopted store: the owner re-runs the current in-process detector over
every served project-memory fact, redacts what the detector can make
safe, quarantines what it cannot, and settles every mutation through the
canonical curation authority so a durable curation receipt records what
changed. No scanner binary runs, no network is touched, and no
unsanitized payload is persisted back.

Co-authored-by: Zack Jackson <ScriptedAlchemy@users.noreply.github.com>
Co-authored-by: Zack Jackson <ScriptedAlchemy@users.noreply.github.com>
@changeset-bot

changeset-bot Bot commented Aug 19, 2026

Copy link
Copy Markdown

⚠️ No Changeset found

Latest commit: 48a335b

Merging this PR will not cause a version bump for any packages. If these changes should not result in a new version, you're good to go. If these changes should result in a version bump, you need to add a changeset.

Click here to learn what changesets are, and how to add one.

Click here if you're a maintainer who wants to add a changeset to this PR

Co-authored-by: Zack Jackson <ScriptedAlchemy@users.noreply.github.com>
cursoragent and others added 5 commits August 19, 2026 18:01
Co-authored-by: Zack Jackson <ScriptedAlchemy@users.noreply.github.com>
Co-authored-by: Zack Jackson <ScriptedAlchemy@users.noreply.github.com>
Co-authored-by: Zack Jackson <ScriptedAlchemy@users.noreply.github.com>
Co-authored-by: Zack Jackson <ScriptedAlchemy@users.noreply.github.com>
…plan' into cursor/mount-privacy-multiroot-native-511e

# Conflicts:
#	src/daemon/project_open_owners.rs
@ScriptedAlchemy
ScriptedAlchemy marked this pull request as ready for review August 19, 2026 19:26

@chatgpt-codex-connector chatgpt-codex-connector Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

💡 Codex Review

Here are some automated review suggestions for this pull request.

Reviewed commit: 5e513dc2ac

ℹ️ About Codex in GitHub

Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you

  • Open a pull request for review
  • Mark a draft as ready
  • Comment "@codex review".

If Codex has suggestions, it will comment; otherwise it will react with 👍.

Codex can also answer questions or update the PR. Try commenting "@codex address that feedback".

let context =
MemoryOperationContext::generated(&self.owner, "privacy_remediation_rescan", None)?;
let receipt = self
.apply_project_memory_curation(operations, confidence, context, None, write_control)

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

P1 Badge Chunk remediation mutations within the curation limit

When a project contains at least 257 facts requiring redaction or quarantine, this submits them as one curation batch, but ProjectMemoryFactCurationBatchV1::new rejects more than 256 operations. The rescan consequently commits nothing, leaving every sensitive fact served, and each later project open repeats the same failure; split the work within the canonical batch limit while preserving truthful receipts.

AGENTS.md reference: AGENTS.md:L141-L143

Useful? React with 👍 / 👎.

fact.tags(),
fact.entities(),
fact.metadata(),
fact.source_label(),

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

P1 Badge Apply canonical source-label sanitization during rescans

For legacy facts whose source_label contains structured sensitive text, this passes the label directly into the generic JSON sanitizer and omits the current ingest path's sanitize_provider_metadata_text preprocessing. A YAML label containing an ordinary-valued vault_passphrase, for example, is only detected through structured parsing, so the rescan classifies it as clean and continues serving a value that current ingest would redact.

AGENTS.md reference: AGENTS.md:L67-L74

Useful? React with 👍 / 👎.

Comment on lines +1310 to +1312
"/api/multi-root/collection",
get(multi_root_api::resolve_collection),
)

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

P1 Badge Bind selected-project collection reads to that project

When this route is reached as /api/projects/{project_id}/multi-root/collection, the selected state reuses active.application_invocation_executor, whose in-process daemon handshake is bound to the active project's path. The gateway rewrites the request into this shared router, and the daemon reads the scope set using that handshake path, so selecting project B can return project A's collection with the same ID—or incorrectly report B's collection missing. The route needs a selected-project/root-addressed executor or must not be exposed through the project-qualified gateway.

Useful? React with 👍 / 👎.

Comment on lines +58 to +60
let mut recent = statuses.values().cloned().collect::<Vec<_>>();
recent.sort_by_key(|status| std::cmp::Reverse(status.updated_at));
recent.truncate(maximum);

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

P1 Badge Advance status polling beyond the newest page

After more than 16 transactions are retained between LSP flushes, every poll sorts the same retained map and truncates it to the newest 16. Because the session's dedupe state is not fed back as a cursor or acknowledgement, later flushes keep receiving those already-notified entries and the older transactions are never returned, causing their native-integration notifications to be silently and permanently lost.

Useful? React with 👍 / 👎.

Comment thread src/mcp/tools/handlers/dashboard.rs Outdated
Comment on lines +242 to +244
let result = crate::application_surface::resolve_dashboard_application_surface(
crate::application_surface::ApplicationSurfaceOperation::NativeIntegrationStatus,
control.request_id(),

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

P2 Badge Preserve the dashboard request's cancellation controls

When a native-integration status request is disconnected or its admitted dashboard deadline is shorter than the catalog maximum, this helper forwards only the request ID. resolve_dashboard_application_surface creates a fresh cancellation signal and derives a new maximum deadline, so cancelling the live DashboardHttpRequestControlV1 does not cancel the daemon invocation and the read can continue after the HTTP request is gone; dispatch this operation with the supplied deadline and cancellation signal.

Useful? React with 👍 / 👎.

@ScriptedAlchemy
ScriptedAlchemy merged commit 70182de into codex/tracedecay-total-redesign-plan Aug 19, 2026
6 of 7 checks passed
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants