Skip to content

Restack #590: make the feature-adoption log reachable after the learning stack - #743

Merged
davekilleen merged 3 commits into
mainfrom
cursor/usage-adoption-log-41dd
Sep 22, 2026
Merged

davekilleen merged 3 commits into
mainfrom
cursor/usage-adoption-log-41dd

Conversation

@davekilleen

@davekilleen davekilleen commented Sep 22, 2026

Copy link
Copy Markdown
Owner

Linked Issue

What Changed

  • Cherry-picked the three real The feature-adoption log had a reader, a documented writer, and no way to reach it #590 commits onto d475fdcb31c2b535b24a756045aee1f9273ebe6f (current main).
  • Dropped no product commits. The only conflict was generated drift (docs/architecture/INVENTORY.md and docs/examples/dex-lens-catalog-enriched-preview.json); both were regenerated. portable_contract.py auto-merged with the half-life seed rules already on main.
  • Intended behavior is unchanged: mark_feature_used is a real dex-analytics tool, matching is ordered and refuses to guess, and the usage-log write goes through the lifecycle transaction door.

Old head: 3f42685538b4e5bbc62a1a55dba5ffd806fd3c9f
New head: 3a2e6100ccd04be78ece2f703751fdbb3447251f

Same-origin branch updated in place: cursor/usage-adoption-log-41dd.

The original fork PR (#590, chrisjackson-coding:usage-tracking-has-no-mechanism) is untouched.

Test Plan

Ralph Wiggum Loop

  • I implemented the change.
  • I self-reviewed for defects and edge cases.
  • I requested specialist review for risky areas (testing/infra/security when relevant).
  • I addressed review findings and re-ran checks.

Quality Gates

  • I added/updated tests or documented why no tests are needed.
  • I added a regression test for bug fixes, or this PR is not a bug fix.
  • I validated failure modes / edge cases.
  • I updated docs or confirmed no docs impact.
  • CI checks for lint + tests + coverage are expected to pass.

Risk & Rollback

Docs Impact

  • Files updated: generated docs/architecture/INVENTORY.md and docs/examples/dex-lens-catalog-enriched-preview.json only where counts/headers drifted
  • If none, reason: n/a
Open in Web Open in Cursor 

@github-actions

Copy link
Copy Markdown

What this pull request touches

  • the task/meeting engine — feeds creating and updating tasks, processing meetings, and keeping that work connected.
  • tests — feeds catching regressions before contributors and users encounter them.

Gates that will judge this change

  • Personal-data gate: added lines must not expose real identities or personal vault content.
  • Change-aware gates: source changes are checked for tests, path-contract use, documentation drift, and touched-file coverage.
  • Tests and coverage: the Python, MCP, migration, hook, and script suites must remain healthy.
  • Safety and quality: security, lint, distribution, path consistency, and large-vault checks still apply.

Based on 11 changed files.

@davekilleen
davekilleen marked this pull request as ready for review September 22, 2026 12:26

@cursor cursor Bot left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

Approved. Cursor Bugbot was not running after the first poll, so that signal was skipped; remaining review state and applicable policies do not require human review. No reviewers were assigned.

Open in Web View Automation 

Sent by Cursor Approval Agent: Pull Request Router and Approver

chrisjackson-coding and others added 3 commits September 22, 2026 21:06
usage_log.md drives /dex-level-up: it records which Dex features a vault has
used so the skill can recommend the ones it has not. mark_feature_used() is
the documented way to record that, and it could not do it.

Three separate reasons, each of which alone would be enough:

1. It was never exposed as a tool. The only documented caller is a skill,
   and skills reach Python through MCP. The function has lived in
   analytics_helper.py unreachable from the place the checklist tells authors
   to call it from.

2. Its pattern could not match most of the file. The label matcher used
   [^(\\n]* around the feature name, which stops at the first bracket, so any
   entry written as "Daily planning (\`/daily-plan\`)" was unmatchable. On a
   real vault that is 37 of 61 remaining features.

3. It returned None whether it worked or not. A caller could not tell a
   successful tick from a no-op, so a miss looked exactly like a hit. That is
   why the drift was invisible: the log on the vault this was found on had not
   changed in twelve days while the features were in daily use.

This replaces the matcher with an ordered one (slash command, then exact
label, then label with the command stripped), returns a status instead of
None, refuses to guess when several entries match, and writes through a temp
file so an interrupted write cannot truncate the consent records that share
this file.

Adoption tracking is deliberately NOT gated on analytics consent, and there
is a test for that: it writes to the vault and sends nothing, and the
recommendations it feeds are useful whether or not a user shares anything.

The parsed feature map in load_usage_log() had no consumers, so the read side
was dead too. A test now covers the loop end to end.

Co-authored-by: davekilleen <davekilleen@users.noreply.github.com>
Review of #590: mark_feature_used wrote System/usage_log.md directly, which
breaks Dex's vault-mutation contract and is unsafe three ways. All three
reproduce against the old approach and are now covered by tests:

- a vault whose System directory is a symlink had the write land outside the
  vault entirely;
- a 0600 log became 0644, because write_text on a fresh temporary takes the
  umask and the rename carries it;
- the fixed .tmp sibling is the same path for both writers, so a feature tick
  and a consent update could each read, modify and write the whole file and
  silently lose the other's change.

Adds rewrite_usage_log() to core/lifecycle/service.py, modelled on the
existing analytics-receipt seam: whole-route symlink validation before the
file is read, a refusal on a symlinked target, bounded read, expected-SHA
guard with stale retry, and the existing mode re-stated in the plan so a
write can never loosen it.

Scoped by the contract rather than by the caller. The new usage-log operation
is authorised for exactly one path, so it cannot write anything else even if
a future caller asks it to, and the bounded-read limit is registered at both
engine sites.

update_consent now uses the same door, per the review: with two direct
writers the concurrency guarantee would not have been real.

The MCP helper keeps its matching and its five statuses. It decides the
outcome from a plain read so a no-op never opens a transaction, and its
transform re-matches against the text the transaction actually read, because
a retry may run it again after another writer has ticked the same box.

251 tests pass across usage tracking, the portable contract, the transaction
core, analytics wiring, instruction honesty and the lifecycle contract.
Making mark_feature_used reachable adds a fifth tool to
dex-analytics, which the capability discovery added in v1.97.0 pins
exactly: the boundary test asserted 131 tools and 4 on this server,
and the committed enriched example listed the old four by name.

Updated both, and renamed the test so its name still matches what it
asserts. The example is regenerated output, not a hand edit; the only
difference is the new tool appearing in the count, the summary
sentence and the example list.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>

Co-authored-by: davekilleen <davekilleen@users.noreply.github.com>
@cursor
cursor Bot force-pushed the cursor/usage-adoption-log-41dd branch from 3f42685 to 3a2e610 Compare September 22, 2026 21:09
@cursor cursor Bot changed the title Restack #590: make the feature-adoption log reachable after #568 Restack #590: make the feature-adoption log reachable after the learning stack Sep 22, 2026
@davekilleen
davekilleen merged commit f2dea3b into main Sep 22, 2026
14 of 15 checks passed
@davekilleen
davekilleen deleted the cursor/usage-adoption-log-41dd branch September 22, 2026 21:25
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