fix(tier-truth): sell only reachable Signal features — Blind Spots + Knowledge Gaps - #473
Merged
Merged
Conversation
…stack The last behavioral scoring path left after the v19 demotion (AD-029), found by the post-merge verification sweep: build_negative_stack injected 0.30 Bayesian suppression priors from auto-detected anti_topics rows whose confidence is pure dismissal count (rejection_count/10) — five dismissals could auto-ban a topic to x0.30 composite authority via negative_stack_prior. Inert on the live corpus (anti_topics has 0 rows, priors byte-identical, hence NO PIPELINE_VERSION bump — precedent and probe documented in scoring/mod.rs), but structurally live. The negative stack now builds from competing-tech inference over the actual dependency graph only. Explicit topic suppression remains user-authored exclusions, which hard-filter upstream. blind_spots' duplicate anti-topic feed removed with it. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_016puYGGmj3oHxmcKBbJ5vXq
The promise described a mechanism AD-029 removed, was never measurable
("all risk, no demonstrated lift" — 7 explicit feedback signals against a
200k-item corpus), and post-v19 left ~100 instances of self-contradicting
copy, several asserting dead mechanisms inside Score Autopsy — live
INV-023 violations. Pre-launch (public, unadvertised) is the only cheap
moment; after launch this is a retraction.
New canonical (propagated from CLAUDE.md through every surface):
"4DA reads the internet for developers — privately, locally. Your
codebase decides what''s relevant." "Yesterday''s noise becomes tomorrow''s
signal" SURVIVES, re-attributed to corpus re-judging (verdict epochs +
re-examination) — it is true and implemented. The 92%/98% benchmark stays
as body copy with methodology. "Compound knowledge" survives only in the
framework''s dev-process sense.
- Governance first: AD-030 (with re-claim criteria: a /calibrate-measured
lift, published) + amendments to AD-017/025/026/028 — all four decisions
survive, only rationales rewrite (AD-028''s lifetime honesty now rests on
the cost structure: zero marginal cost + offline 2099 key)
- P0: in-app strings that asserted dead mechanisms rewritten or deleted
("will be penalized in relevance scoring", "Boosted because you''ve shown
interest", "scoring corrections applied", the "Learned" badge, learned
factor rows + affinity chips — the anti factor also had inverted
magnitude/multiplier semantics and rendered a false penalty on every item)
- "Compound Intelligence" tab renamed "Personal, Not Aggregate" — its
content (per-user, inspectable, local-only) was always a privacy story
- 13 locales: 45 stale keys purged per locale, regenerated from corrected
English via i18n:fill; generator scripts purged first so nothing
re-injects (apply-translations.cjs carried 12 hardcoded copies)
- Ship-locked surfaces: installer shortDescription/longDescription,
homepage JSON-LD (incl. the Offer), npm MCP README (lands on next
publish)
- Site + docs: 22 files rewritten under the house rule (present-tense
verifiable statements; improvement attributed to engine updates and the
user''s codebase, never engagement); signal.njk''s 16 compounding claims
reframed on the analysis layer; the refund-adjacent trial claim deleted;
framework §7 kept as a dev-process thesis with scoring-accuracy claims
stripped across all three mirrored copies
- New public post: site/src/writing/retiring-a-claim-we-could-not-measure
— the incident record as an engineering story, ending on the re-claim bar
- Enforcement: scripts/check-retired-claims.cjs (+9 tests) wired into
test:scripts and validate; historical-record files allowlisted;
retired-ok escape hatch for quoting the claim as history
Verified: guard clean repo-wide; translation parity 0 errors across 13
languages; tsc clean; frontend suite green; Rust 4,419 green; fmt clean.
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_016puYGGmj3oHxmcKBbJ5vXq
…uilt onto current main) Merges origin/worktree-promise-retirement-ad030 (PR #419) with conflicts resolved in favour of current main's newer facts: - locale ui.json files: main's structure kept; #419's 312 reworded values and 130 deleted affinity-surface keys ported per-leaf (its 752 key additions dropped — those surfaces were deleted from en by #421) - README/index.njk/signal.njk/SETUP-GUIDE/LICENSE-ACTIVATION: main's newer copy (93% figure, Precision Ledger, BYOK rationale) kept, retired phrases replaced with the canonical line - Developer DNA kept OUT of paid-feature lists (AD-025/026 tier truth) - apply-translations.cjs / missing-keys.json / BadgeRow.tsx stay deleted (deleted on main since #419's base) - CLAUDE.md + package.json deliberately untouched: claimed by live peer lanes (#466, agent-a875) — gate wiring + tagline follow in-branch once those claims release Co-Authored-By: Claude Fable 5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01MMarGhXjbKyNJzsm3JG1jw
- 92% -> 93% / 98% -> 98.9% / 215 -> 245-item corpus (the current measured benchmark, #460) in COMPARISON.md and the retirement post - RELEASE-NOTES-v1.0.0 tier table + closing line matched to AD-025/026 tier truth (DNA, Signal Chains, Score Autopsy are free; the paid set is Blind Spots, Knowledge Gaps, Standing Queries, Semantic Shifts, cross-project intelligence) - retirement post added to /writing index (retired-ok teaser quote) and sitemap - two Rust doc comments un-mangled; engagement_telemetry header no longer claims facets influence scoring (INV-023) Co-Authored-By: Claude Fable 5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01MMarGhXjbKyNJzsm3JG1jw
The last 2 retired-claim violations in the repo. The tagline mandate now teaches the canonical description and points at the enforcement gate instead of restating the retired phrases. Deferred from #469 because this file was claimed by the #466 lane; that lane is merged and its worktree reaped. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01MMarGhXjbKyNJzsm3JG1jw
…Knowledge Gaps Verified against the live code: of the features sold on /signal, README, LICENSE-ACTIVATION, SETUP-GUIDE, RELEASE-NOTES and the Terms, only Blind Spots (with AI assessment) and Knowledge Gaps have a reachable UI. Removed from every sales surface: Standing Queries (backend exists, no creation UI — only a Brief listener that can never fire), Semantic Shifts / cross-project intelligence / Project Health comparison (commands registered, zero frontend callers), Attention Report + the attention dashboard (backend command deleted as a ghost in #421; the settings.attention locale keys are orphans), Decision Health, Trust Ledger analytics, and the Precision Ledger (unbuilt in both layers). Also corrects tier misattribution the same surfaces carried: Score Autopsy, Developer DNA and Signal chain analysis are FREE (AD-025/026) and now sit in the Free column/card, not the Signal one. The Terms' Signal-tier list (site/src/terms.njk + docs/legal/TERMS-OF-SERVICE.md) was internally inconsistent — §3.2 sold channels/DNA as paid while §4.5 said they stay free; both now state the true paid set. Legal wording otherwise untouched — flag for counsel review. Backend + gating for the unreachable features are KEPT; each returns to the sales surfaces when its UI ships. Site builds clean; retired-claims gate green. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01MMarGhXjbKyNJzsm3JG1jw
runyourempire
enabled auto-merge (squash)
August 16, 2026 14:19
runyourempire
added a commit
that referenced
this pull request
Aug 16, 2026
…AD-029/AD-030 arc) (#474) Implements the **v20a-1 dead-code removal** for the AD-029/AD-030 arc: deletes every learned-affinity surface that is STRUCTURALLY DEAD (provably unreachable or provably no-op), and nothing that is live. −1,620 lines, +107. ## Proof classes (what made each removal behavior-neutral) - **Pinned inputs** — pipeline_v2 pins `affinity_mult=1.0` / `anti_penalty=0.0`, so these could never produce output: the learned-axis strength branch in `compute_signal_strength_bonus` (both conditions structurally unreachable), the `_anti_mult` dead binding, the `LearnedPreference` explanation factor (`learned_weight = max(0.0, 1.0−1.0)`, never fires — variant removed from `FactorKind` in Rust + the FE mirror), and `probes_engine`'s `ax_learned` condition (probe report now lists only the four axes that can actually fire). - **Empty-map reads** — the AD-029 quarantined loader returns an empty `topic_affinities` map, so these always saw nothing: `compute_affinity_multiplier` + `compute_anti_penalty` (whole `scoring/affinity.rs` deleted), the `channel_render` multiplier + always-"Not yet learned" `affinity_summary` prompt line, the explanation-confidence affinity contribution, the two dead `semantic/embeddings.rs` loops, and the frontend `learnedAffinities`/`antiTopics`/`lastLearnedTopic` store state with its 500 ms refresh round-trip feeding nothing. `ctx.feedback_boosts` was a hardcoded empty map → the `feedback_boost` computation always yielded 0.0; the then-unread field was deleted with its writers. - **Phantom schema** — two PRE-EXISTING bugs, now deleted rather than shipped broken: `weekly_digest::collect_topics` queried a nonexistent `ace_topic_affinities` table (real table: `topic_affinities`) — `top_topics` empty since the day it was written; `developer_dna::get_blind_spots` filtered on a phantom `weight` column (real: `affinity_score`) — prepare failed, `blind_spots` always `[]`. (The real Blind Spots feature in `blind_spots.rs` is untouched.) - **Unreachable / zero callers** — gate's learned axis never confirms (`learned_confirmed = false`); dead commands `ace_get_single_affinity` + `get_learning_stats` (handler + registration + CommandMap types + victauri allowlist entry + ghost-backlog entry); the persona-posterior READ side (`get_dominant_persona`, `get_persona_topic_boosts`, drift detection + `posterior_snapshots`); `stability_detector`'s three unused query fns (+ their orphaned private helper); the monitoring FROZEN threshold auto-tune "would have done" log block; simulation affinity-injection arms (persona_data*, enrichment, feedback_sim, enriched_lifecycle, ace_validation). ## Deliberately KEPT - Capture/writers: `ace/behavior/tracking.rs`, decay, engagement telemetry, interactions, persona-posterior WRITE side (`update_posterior`, `seed_from_taste_test`). - The AD-029 quarantined loader + its guard test (`ace_context_quarantines_topic_affinities`) — the quarantine itself. - Learned Preferences panel, `preference_commands.rs`, stability-detector core, EngagementPulse, `get_engagement_summary`, `tech_radar` overlay_affinities, `standing_queries_suggestions`, `get_top_engaged_topics`, `data_export`, mcp-4da-server. - **`affinity_mult` / `anti_penalty` / `feedback_boost` FIELDS in `ScoreBreakdown`, still pinned 1.0/0.0/0.0** — stored `score_breakdown` JSON in user databases carries them; the serialized struct is unchanged. - `ace_get_topic_affinities` / `ace_get_anti_topics` commands (live readers of real rows): their only FE caller was the dead store refresh, so they are now backlogged in `ghost-command-backlog.json` with reviewed reasons rather than deleted. - anomaly.rs / sovereign profile / contradiction & skill-gap boosts — v20a-2 (INV-023) territory, untouched. ## DSL Removed only the two verified orphans: `semantic_boost.affinity_clamp` and `engagement_weights.affinity_w` (generated constants with zero src references; DSL validation is per-param, no required-key checks, and `scoring_dsl.rs` tests use their own inline SAMPLE_DSL — no test churn). The remaining affinity/feedback constants (AFFINITY_THRESHOLD, FEEDBACK_SCALE, FEEDBACK_CAP_RANGE, SIGNAL_NORMALIZATION_AFFINITY_RANGE, SIGNAL_NORMALIZATION_FEEDBACK_STRENGTH, AFFINITY_MULT_RANGE, AFFINITY_EFFECT, ANTI_PENALTY_MAX) stay in the DSL: they generate into `scoring_config` under its existing module-wide `#![allow(dead_code)]`, and removing them would cascade beyond the two verified orphans. ## NO PIPELINE_VERSION bump Every removed path was provably emitting nothing (pinned 1.0/0.0 inputs or empty-map reads), so stored scores cannot differ and a corpus re-stamp would be a no-op. Simulation/version-comparison suites confirm: all asserted precision numbers unchanged. ## Skipped (fleet coordination) `src-tauri/src/commands.rs` (inventory item 3: score-autopsy `learned_affinities` build+emit, the pinned "Learned Affinity" / "Anti-Topic Penalty" components, and `score_tuning_snapshot`'s mislabeled `feedback_interaction_count` field) — the file is claimed by worktree-agent-a01f9610ade32c536, so per protocol its changes were skipped. Verified compile-safe: commands.rs references only the kept pinned breakdown fields and the kept quarantined map, none of the deleted symbols. The FE side of the autopsy (render block, interface field, `autopsy.learnedPreferences` en-only locale key) IS removed — the backend's extra JSON field is simply ignored. ## Observation (not fixed here) `context_engine.rs` carries a duplicate `topic_affinities` CREATE TABLE schema alongside the canonical one in `ace/db.rs` — a schema-drift hazard of exactly the class that produced the two phantom-schema bugs deleted above. ## Verification - `cargo fmt` clean; `cargo test --lib` **4372 passed / 0 failed / 8 ignored**; `cargo clippy --lib -- -D warnings` clean - `pnpm install --frozen-lockfile`; `pnpm run i18n:types` (no diff); `pnpm run typecheck` clean; `pnpm run test` **1242 passed / 0 failed** (111 files) - `npx eslint` clean on all touched TS files - `node scripts/check-file-sizes.cjs` — no errors (48 pre-existing warnings) - `node scripts/check-retired-claims.cjs` — OK - `node scripts/ghost-commands.cjs` — 0 new ghosts, 0 unregistered, 0 stale backlog - `node scripts/validate-commands.cjs` — 383/383/383 consistent - No new `#[allow(dead_code)]` - Rebased onto origin/main (690ced1) before push; no file overlap with #473 🤖 Generated with [Claude Code](https://claude.com/claude-code) https://claude.ai/code/session_01MMarGhXjbKyNJzsm3JG1jw Co-authored-by: Claude Fable 5 <noreply@anthropic.com>
runyourempire
added a commit
that referenced
this pull request
Aug 16, 2026
runyourempire
added a commit
that referenced
this pull request
Aug 16, 2026
runyourempire
added a commit
that referenced
this pull request
Aug 19, 2026
… key-in-logs, +6 (#495) ## What this is Wave 2 of the licensing-pipeline hardening audit (Wave 1 = #494, merged+deployed). A deeper adversarial sweep — **three parallel hunters (site / app / frontend) + direct analysis** — found several more issues across the whole pipeline. Every confirmed finding here is fixed and test-covered; two items requiring an app release or a product decision are documented for the operator (not code-fixable this pass). ## Fixed & verified ### Server (Cloudflare Pages) - **H1 (HIGH) — session-lookup returned ANY customer's key with no payment check.** `GET ?session_id=` trusted a session id minted at *creation* (pre-payment) and resolved the customer by *buyer-typed email*, so starting a checkout with a victim's email and abandoning it (no payment) let an attacker read that victim's offline-verifiable key. Now: gate on `sessionProvesPurchase` (status complete / paid), bind to `session.customer` (never an email list), and time-box the session id to 24h (`sessionWithinWindow`). Pure predicates unit-tested. - **M4 (MED) — no `charge.dispute.closed` handler.** A *won* dispute left a paying monthly subscriber terminal forever (the isTerminal guard then blocks every renewal). `handleDisputeClosed` restores `active` on `status === 'won'`, only from the exact `chargeback` state. - **M3 (MED) — `notify.js` unauthenticated + unmetered** → unbounded Stripe customer creation. LICENSE_KV per-IP limiter (20/hr), fail-open, separate key namespace. - **CSP + no-referrer (L6/L7)** — strict CSP (`default-src 'none'`, `connect-src 'self'`) on the two key-bearing pages so an injected script can't exfiltrate the key, and the session-id credential never leaks in a Referer. - **checkout.js** writes `signal_tier` (was legacy `streets_tier`) — hygiene. ### App (Rust) - **Key-in-production-logs (MED)** — the full `fourda://activate?key=<SECRET>` was logged at info/warn across 9 sites and written to the `security_events` DB, so the bearer key landed in `data_dir/logs/*.log` in cleartext (support bundles, cloud-synced folders). New `utils::redact_deep_link` (byte-safe vs hostile UTF-8) masks the `key=` value everywhere. - **Expiry never enforced + settings.json tamper (MED)** — `has_license_key_available` returned true for any non-empty key, so an *expired* `4DA-` key kept granting Signal forever (a cancelled monthly subscriber never downgraded) and pasting `tier:"signal"`+garbage unlocked Signal. New `key_is_usable` verifies signature **and** expiry. Makes Terms §4.5 true for subscriptions for the first time. - **Recovery auto-activated an unverified key (F3)** — removed (the live server never returns a key here; it was dead + dangerous if `4da.ai` were repointed). - **Forgeable Keygen cache (F2)** — the doc comments claimed it was cryptographic; it isn't (bare SHA-256). Corrected the claims + added a named adversarial test pinning the real honesty-box behaviour. - **Trial 45-vs-14 lie** — `start_trial` now reports the real value from `get_trial_status`. - **Terms §5.3** reworded from the impossible "the licence is deactivated" to the enforceable "the licence terminates; continued use is not permitted." ## Verified - **Rust**: 25 license tests + 22 url tests pass (6 new), `cargo fmt` + `clippy --lib` clean, no size breaches. - **Site**: 64 lib tests pass (session-predicate + revoked-matrix added). ## Documented for the operator (not code-fixable this pass) - **Deep-link activation consent (MED)** — a website can silently swap a paying user's licence for the attacker's own valid key (DoS/griefing). The fix is a UI consent flow, and the project's verification rule requires UI/entitlement changes to be tested against the running app; deferred as a focused, live-verified follow-up with the design ready (email-match refusal + confirmation modal). This is the top open security item. - **Lease-client arc** — real lifetime-refund revocation + killing the monthly re-paste. Needs an app release + a NETWORK.md/ADR decision. - **Signal-feed "isPro" gate** — per tier-truth #473 that feed is free-floor, so this is a vestigial sales-tease, NOT a data leak (all actually-sold features enforce server-side). Product call, not a patch. 🤖 Generated with [Claude Code](https://claude.com/claude-code) https://claude.ai/code/session_01RuQRKzs6RawLs5zxxNPBYp --------- Co-authored-by: Claude Fable 5 <noreply@anthropic.com>
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.
Closes the standing 08-12 audit flag (SIGNAL FEATURES SOLD WITH NO UI) — and it was worse than flagged. Verified against the live code: of everything sold on /signal, README, LICENSE-ACTIVATION, SETUP-GUIDE, RELEASE-NOTES and the Terms, only Blind Spots (with AI assessment) and Knowledge Gaps have a reachable UI.
Removed from every sales surface: Standing Queries (no creation UI — only a Brief listener that can never fire), Semantic Shifts / cross-project intelligence / Project Health comparison (commands registered, zero frontend callers), Attention Report + attention dashboard (backend deleted as ghosts in #421;
settings.attention.*locale keys are orphans), Decision Health, Trust Ledger analytics, Precision Ledger (unbuilt in both layers).Tier misattribution also fixed: Score Autopsy, Developer DNA, Signal chain analysis are FREE (AD-025/026) — moved to the Free card/column. The Terms were internally inconsistent (§3.2 sold channels/DNA as paid; §4.5 said they stay free) — both now state the true paid set. Legal wording otherwise untouched — flag
site/src/terms.njk+docs/legal/TERMS-OF-SERVICE.mdfor counsel review.Backend + gating for the unreachable features are KEPT; each returns to the sales surfaces when its UI ships. Site builds clean; retired-claims gate green. Needs a site redeploy after merge.
🤖 Generated with Claude Code
https://claude.ai/code/session_01MMarGhXjbKyNJzsm3JG1jw