Not on the page.
; + } + + return ( +- The Explain switch on For You keeps every card where it is and - folds it to its source and title, then says why the post is here: - one sentence for the reason, then the post's top topics and - source, each with less, more and block. Full explanation opens the - "Why am I seeing this?" view with every topic and the - score breakdown. Changes save as you tap, every card sharing a - topic or source updates at once, and Refresh feed swaps out what - you blocked. Less and more are new: today the API only has follow - and block. + Each card keeps its source and title and says why it is here: one + sentence for the reason, chips for what moved it up or down (tap + one to see the math and change that part of the policy), and the + post's topics and source with less, more and block. Full + explanation opens the "Why am I seeing this?" view with + the score breakdown.
+ The story runs a copy of {policyVersion}, the challenger
+ policy For You uses, over real posts. Every reason, chip, weight and
+ left-out group comes from that copy, so changing a control re-ranks
+ the page the same way the feed would. It simplifies four things:
+ reader response compares posts here instead of using the source
+ prior, the first tag is the main topic, topic similarity is tag
+ overlap instead of tag embeddings, and placement swaps are left out.
+
| Control | +Status | +Today | +Needs | +
|---|---|---|---|
| + {row.control} + | ++ + {statusLabel[row.status].label} + + | +{row.today} | +{row.needs} | +
- Every post now shows what put it here. Use{' '}
-
- - Your feed is still learning what you like. - {' '} - {popularCount} of these {staying.length} posts are popular picks. - Pick a few more topics and they'll make room for posts that fit - you. -
- -- {copy[item.reason]} + {name ? ( + <> + {lead} + {name} + {tail} + > + ) : ( + <> + {lead} + {tail} + > + )}
); }; -const kindLabel: Record+ #{best.tag} is a{' '} + {best.origin === InterestOrigin.Declared ? 'topic you follow' : 'topic learned from your reading'} + {interest?.strength && ( + <> + {' '} + ({strengthLabel[interest.strength].toLowerCase()},{' '} + {interest.evidence?.stories}{' '} + {interest.evidence?.stories === 1 ? 'story' : 'stories'}) + > + )} + . Its weight, {best.weight.toFixed(2)} + {best.role === TopicRole.Side && + `, counted at ${Math.round(best.roleWeight * 100)}% as a side topic`} + , lifts this post {formatMultiplier(decision.factors.match)}. +
++ You follow {sourceName}, so every post from it is + in and multiplied by {formatMultiplier(decision.factors.follow)}. +
++ Per view, readers upvoted and commented on this post{' '} + {formatMultiplier(decision.factors.base)} as much as + the typical post here. Well-liked posts also stay fresh longer. This + one is about other readers, so there is nothing to turn off. +
+ ); + break; + case FactorId.Age: + body = ( + <> ++ Posted {Math.round(decision.ageDays)} days ago. A post loses half + its pull every {params['age.half_life_days']} days + , stretched up to {params['age.max_stretch']}× for well-liked + posts. +
++ It was on your screen {decision.impressions}{' '} + {decision.impressions === 1 ? 'time' : 'times'} without a click. + Each view keeps{' '} + {Math.round(params['history.seen_factor_per_show'] * 100)}% of its + pull, and at {params['history.max_impressions_without_action']}{' '} + views it leaves. +
++ #{decision.slot?.waitingTag} had not been on your + first screen lately, so its first post gets a turn and jumps ahead + of topics you just saw. +
++ {decision.slot?.sourceCount}{' '} + {decision.slot?.sourceCount === 1 ? 'post' : 'posts'} from{' '} + {sourceName} already sit above it. Each one lowers the next by{' '} + {Math.round(params['diversity.source_repeat_discount'] * 100)}%. +
++ Posts on similar topics already sit above it, so it moves down to + mix the page. +
++ Its headline overlaps a post above it, so it is likely the same + story. +
++ Your topics and follows found fewer posts than a page, so popular + posts fill the rest. Following a few more topics replaces them. +
+
+ Everything that decides what For You shows you, and every knob
+ behind it. Ranked by {policyVersion}; your profile
+ updates within minutes of what you read.
+
{paramKey}
+ {isDefault ? (
+ Default
+ ) : (
+
+ )}
+
+ + Blocked topics are not interests. Posts with this topic never show. +
+ ); + } + const recency = interest.recency.toFixed(2); + let base: string; + if (row.status === RowStatus.Early) { + base = `1 story so far. It starts counting at 2 stories, or right away if you follow it.`; + } else if (interest.origin === InterestOrigin.Declared) { + const boostKey = interest.strength + ? `interests.declared_boost.${interest.strength}` + : undefined; + base = + interest.strength && boostKey && interest.strength !== Strength.EarlySignal + ? `${params['interests.base_weight'].toFixed(2)} for following + ${( + params[boostKey as 'interests.declared_boost.strong'] ?? 0 + ).toFixed(2)} (${strengthLabel[interest.strength].toLowerCase()}) × ${recency} freshness = ${interest.computedWeight.toFixed(2)}` + : `${params['interests.base_weight'].toFixed(2)} for following. Reading about it adds more.`; + } else { + const weightKey = `interests.inferred_weight.${interest.strength}` as + | 'interests.inferred_weight.strong' + | 'interests.inferred_weight.moderate'; + base = `${(params[weightKey] ?? 0).toFixed(2)} (${strengthLabel[ + interest.strength ?? Strength.Moderate + ].toLowerCase()}) × ${recency} freshness = ${interest.computedWeight.toFixed(2)}`; + } + const { control } = interest; + let adjustment: string | undefined; + if (control?.weight !== undefined) { + adjustment = `You set it to ${control.weight.toFixed(2)}.`; + } else if (control?.mode === TopicMode.Boosted) { + adjustment = `× ${params['interests.control_boost'].toFixed(2)} for More = ${interest.weight.toFixed(2)}`; + } else if (control?.mode === TopicMode.Demoted) { + adjustment = `× ${params['interests.control_demote'].toFixed(2)} for Less = ${interest.weight.toFixed(2)}`; + } else if (control?.mode === TopicMode.Muted) { + adjustment = 'Muted, so it counts as 0.'; + } + + return ( ++ {base} + {adjustment && {adjustment}} +
+ ); +}; + +const RowDetail = ({ row }: { row: ProfileRow }): ReactElement => { + const store = usePersonalization(); + const { interest } = row; + const isFollowed = row.status === RowStatus.Followed; + const isBlocked = row.status === RowStatus.Blocked; + + return ( ++ Learning from reading is off, so only followed topics count right now. +
+ )} ++ {incoming.length + ? `If you refreshed now, ${incoming.length} new ${ + incoming.length === 1 ? 'post comes' : 'posts come' + } in.` + : 'If you refreshed now, the same posts would show.'} +
++ {next.leftOut.length} posts were considered and left out. Each group + says why. +
+
+ {json}
+
+ {policyVersion}, the For You policy. A
+ post's score is reader response × topic match × follow ×
+ freshness × seen before; each page then mixes topics and sources and
+ gives waiting interests a turn.
+ >
+ }
+ actions={
+ {description}
++ {description} +
+ )} +
+ Each setting in the panel writes one retriever_config{' '}
+ value. Topic and per-source boosts show as the multiplier they give,
+ so a topic weight of 0.30 reads as ×1.30.
+
| Group | +Setting | +Key | +Default | +
|---|---|---|---|
| + { + paramGroups.find(({ group }) => group === meta.group) + ?.title + } + | ++ {meta.label} + | +
+ {meta.key}
+ |
+ + {formatParam(meta.format, defaultParams[meta.key])} + | +
- Everything that decides what For You shows you, and every knob
- behind it. Ranked by {policyVersion}; your profile
- updates within minutes of what you read.
+ Everything that shapes your For You feed, and how much each thing
+ counts. Change anything here and your feed follows.
{paramKey}
- {isDefault ? (
- Default
- ) : (
-
- )}
-
+ Add the daily.dev MCP server to Claude, Cursor, Codex or any MCP client. + Your agent can then read and change everything on this page. +
++ Every change it makes shows up here, and you can undo any of it.{' '} + + Setup guide + +
+- Blocked topics are not interests. Posts with this topic never show. -
- ); +const describeReading = (evidence: TopicEvidence): string => + evidence.stories === 1 + ? `You read 1 post about it ${formatWhen(evidence.daysSinceLastAction)}.` + : `You read ${evidence.stories} posts about it, the last one ${formatWhen( + evidence.daysSinceLastAction, + )}.`; + +const describeInterest = (interest: Interest): string => { + const { evidence } = interest; + const isFollowed = interest.origin === InterestOrigin.Declared; + if (!evidence) { + return isFollowed ? "You follow this. You haven't read about it yet." : ''; } - const recency = interest.recency.toFixed(2); - let base: string; - if (row.status === RowStatus.Early) { - base = `1 story so far. It starts counting at 2 stories, or right away if you follow it.`; - } else if (interest.origin === InterestOrigin.Declared) { - const boostKey = interest.strength - ? `interests.declared_boost.${interest.strength}` - : undefined; - base = - interest.strength && boostKey && interest.strength !== Strength.EarlySignal - ? `${params['interests.base_weight'].toFixed(2)} for following + ${( - params[boostKey as 'interests.declared_boost.strong'] ?? 0 - ).toFixed(2)} (${strengthLabel[interest.strength].toLowerCase()}) × ${recency} freshness = ${interest.computedWeight.toFixed(2)}` - : `${params['interests.base_weight'].toFixed(2)} for following. Reading about it adds more.`; - } else { - const weightKey = `interests.inferred_weight.${interest.strength}` as - | 'interests.inferred_weight.strong' - | 'interests.inferred_weight.moderate'; - base = `${(params[weightKey] ?? 0).toFixed(2)} (${strengthLabel[ - interest.strength ?? Strength.Moderate - ].toLowerCase()}) × ${recency} freshness = ${interest.computedWeight.toFixed(2)}`; + const reading = describeReading(evidence); + if (isFollowed) { + return `You follow this. ${reading}`; } - const { control } = interest; - let adjustment: string | undefined; - if (control?.weight !== undefined) { - adjustment = `You set it to ${control.weight.toFixed(2)}.`; - } else if (control?.mode === TopicMode.Boosted) { - adjustment = `× ${params['interests.control_boost'].toFixed(2)} for More = ${interest.weight.toFixed(2)}`; - } else if (control?.mode === TopicMode.Demoted) { - adjustment = `× ${params['interests.control_demote'].toFixed(2)} for Less = ${interest.weight.toFixed(2)}`; - } else if (control?.mode === TopicMode.Muted) { - adjustment = 'Muted, so it counts as 0.'; - } - - return ( -- {base} - {adjustment && {adjustment}} -
- ); + return interest.strength === Strength.EarlySignal && !interest.control + ? `${reading} It counts once you read 2.` + : reading; }; -const RowDetail = ({ row }: { row: ProfileRow }): ReactElement => { +const topicIcon = ( + +- Learning from reading is off, so only followed topics count right now. -
- )} -