fix: recover selection features lost from main by the PR #13 merge#18
Merged
Conversation
Context sensing previously ranked personas against a static whole-repo file-extension census, which a file-count-dominant language can swamp. sense() now also consults the active git working set (staged, unstaged, and untracked changes via `git status --porcelain`) and boosts those languages above the census, so selection favors what is being edited right now: a polyglot repo where you are editing Rust no longer ranks a JavaScript-heavy persona first. Best-effort and dependency-free. A non-git directory or a missing git binary yields no boost and prior behavior is unchanged. The boost weight (1.5) sits between the census ceiling (1.0) and the prose sentinel (2.0), so it never overrides an explicit prose-writing signal. Dependency-manifest parsing (dep names to task tokens) is the next increment; it needs toml/serde_json on the currently serde-only crate. cargo test -p frameshift-orchestrator: 77 passed, 0 failed (6 new); clippy -D warnings clean.
Local rustfmt wraps the success arm into a block; CI rustfmt collapses it onto one line. A two-statement block with a named stdout binding is stable across both rustfmt versions and reads clearer.
Context sensing now parses root manifests (Cargo.toml, package.json) for dependency names and exposes them as ContextSignal.context_tokens. The policy scores them as a small capped additive bonus when they match a persona's keywords, so framework-level signals (axum vs actix, react vs vue) sharpen selection. Dependency-free line-based parsing keeps the orchestrator crate serde-only. The bonus is deliberately kept out of the lexical IDF channel: folding dependency names into task_tokens would inflate the IDF denominator with high-weight non-matching deps and dilute genuine task-token matches. As an independent additive term (cap 0.12) it can only raise a persona that matches project dependencies, never redistribute the primary weights. cargo test -p frameshift-orchestrator: 84 passed, 0 failed (7 new); clippy -D warnings clean.
ContextSignal.frameworks (cargo/npm/go/python, detected from marker files) was populated by context sensing but never read by the scorer. Route it through the existing capped context-signal bonus alongside dependency tokens, so a persona whose keywords name a project's build framework gets the same small boost. No new fields, no weight change. cargo test -p frameshift-orchestrator: 85 passed, 0 failed (1 new); clippy -D warnings clean.
`frameshift use <name>` activated a persona but never recorded a preference, so the orchestrator's bias machinery never learned from manual choices. After a successful activation, record the persona into the shared automate-prefs.json (the same store `select`, the daemon, and the `prefs` command read), nudging future automatic selection toward personas the user actually picks. Best-effort: a preferences load/save failure warns but does not fail the command, since activation has already succeeded. cargo test -p frameshift-cli use_persona: 2 passed; clippy and fmt clean.
The catalog `total_downloads` counter shown on the marketplace was never
incremented by any route: the download handler only recorded a `pack_downloads`
event (which feeds the 7-day Trending ranking), while the counter that backs
`total_downloads` is bumped exclusively by `increment_download_counter`, which
no handler called. As a result every pack reported 0 total downloads.
Wire `increment_download_counter` into `download_pack_bytes` alongside the
existing `record_download` call, as a best-effort step that warns and continues
on failure so a download the client already received is never failed. Document
why the signed `/dl/{hash}` path cannot increment the counter (it has only the
content hash, not name/version; the official client uses the direct route).
Add an integration test asserting a successful download increments the counter.
…ing scaffold Two sharpen-arc slices for automate-mode persona selection. A1 -- daemon learns from manual overrides. evaluate_and_apply now compares the SwitchController's tracked auto-pick against the on-disk active marker before deciding. When they diverge (the user switched by hand), it rewards the chosen persona and decays the rejected auto-pick via Preferences::record_override, persists the shared automate-prefs.json, and re-baselines the controller through the new SwitchController::adopt_active so the same override is not re-learned on every tick. A new SwitchController::active_persona exposes the tracked pick. A2 phase 1 -- dependency-free semantic scoring scaffold. A new embed module defines the Embedder trait plus cosine_similarity/semantic_similarity. The scorer gains a semantic ScoreComponents channel: rank_with_embedder folds a cosine bonus (task text vs persona text, scaled by SEMANTIC_WEIGHT) additively into the blend, and select_with_embedder threads an optional embedder through selection. rank/select keep their signatures and delegate with no embedder, so the semantic channel is 0.0 by default and there is zero behavior change. A real embedding engine and model distribution are phase 2, deferred pending sign-off. clippy -D warnings clean; 92 orchestrator + 13 daemon tests pass, including a manual-override regression test and semantic-channel tests with a mock embedder.
Ports the remaining feat/land-m3 content that the PR #13 merge dropped: symlink-safe project walk, case-insensitive anti-keyword matching, capped streaming audit-log load, atomic preferences save, and honoring min_confidence/switch_margin in SwitchPolicy and SwitchController.
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.
Summary
The PR #13
-s oursmerge took feat/intelligent-selection wholesale, but the stacked feat/land-m3 branch (PRs #10/#11) was never merged into it, so main silently lost a full layer of shipped, previously CI-green work. This PR recovers it on top of current main without touching the newer PR #15/#16 surfaces (registry install, telemetry endpoint, memory health, publish metadata).Recovered (cherry-picks from feat/land-m3)
frameshift userecords preference feedback (learn-from-use)download_pack_bytesincrementstotal_downloadsagainRecovered (ported, final commit)
M3 hardening that the merge also dropped: symlink-safe project walk, case-insensitive anti-keyword matching, capped streaming audit-log load, atomic preferences save, and honoring
min_confidence/switch_marginin the switch controller.Verification
scripts/preflight.shgreen: rustfmt, clippy -D warnings, full workspace test suite (64 binaries, 0 failures), cargo audit with the documented ignores.🤖 Generated with Claude Code