Make the buddy the tutor along the onboarding path - #267
DavidLeuter wants to merge 23 commits into
Conversation
…nto prototype/buddy-blueprint-tutor
The buddy could not be reached from the one page it has most to say about. A hire stuck on a step, or on a question they had now got wrong twice, was looking at the only page in the product with nobody to ask — while a mentor sat in a dock that knew nothing about any of it. - `AskTheBuddy` on the phase, on every open step and on every unpassed question, plus the step detail page. The same mechanism the board cards use: the surface seeds a question, the mentor answers it with its own tools, so no surface needs action machinery of its own. - The question modal hands off too, and closes on the way out — the dock renders under the modal, so opening it behind would have looked like nothing happening. Loudest under a wrong answer, which is where a second guess used to be the only thing on offer. - The "no phases were generated" screen offers the conversation next to the retry. Generating again is the wrong hope when the corpus was what was thin; talking it through can actually produce something, and the mentor can offer to put the result on the path. - Openings live in `buddyDrafts.ts`, in the hire's voice, pre-filled rather than sent, quoting a long title rather than pasting it. - The path-changing actions announce themselves (`announceBuddyPathChanged`), so a step completed in the conversation is not still open on the page behind the dock. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Four of the six things testing turned up were on this side. - **Links are clickable and stay in the app.** The mentor is handed each item's path, so "want to take #3?" arrives as a link; `BuddyMarkdown` renders an app path through the router instead of opening a new tab, which would reload the SPA and lose the conversation. A question has no route of its own, so `?question=<id>` opens its modal and `?phase=<id>` selects a phase — derived from the URL rather than copied into state, so a link works whether it arrives on a fresh mount or on a click from the dock, and it stops winning as soon as the hire closes the modal or picks another phase. - **Items carry the number the buddy uses**, from one rule (`itemNumbers`) that matches the Kotlin one: steps in position order, then questions. Not `position` itself — the two kinds carry their own, so a hire counting down one visible list would have been right while the data disagreed. - **The step page refreshes itself** when the buddy changes something on it. Ticking a line off in the dock left the checklist behind it unchanged — the hire's own click looking like it had done nothing. Silent: the page is already on screen, and a spinner over it is a worse answer than a stale tick box. - `complete_task` wired through the proposal payloads. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
- **The member's path is normalised where it comes off the wire.** A phase without `questions` took the whole team page down with a TypeError: three surfaces read it because the type promised it, and the endpoint did not deliver. The backend now sends it, and the default here means no caller downstream has to defend itself against the same shape drift again. - **The badge says who added a step**: the buddy, the hire, or a PM. It used to call all three "Custom step by PM", which is the one of the three that matters — it is what the team requires — so a step agreed to in a chat was arriving as an instruction from above. - **Numbers in the graph view and on the step page**, from the same `itemNumbers` rule as the list. A number the buddy uses and the hire cannot see on the page they are looking at is worse than no number; the step page pays one path read for it, because a step cannot know its own place among its siblings. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
The origin badge also sits on the team page, where "You added this" and "Added with your buddy" read as being about the reviewer. The reviewer view now says "Added by the hire" and "Added with the buddy". Also formats the branch's onboarding files with Prettier. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Picking a suggestion filled the composer but left focus on the chip, so Enter sent nothing. Both composers now take the caret whenever text arrives from outside rather than from typing -- chips, hand-offs from "Ask your buddy", any of them. A step or question link from the buddy now opens the item's phase, scrolls to its card and lights it up briefly, instead of opening a question modal. Starting the step or answering the question stays the hire's own click. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
request_skip's reason rides the proposal and the confirm payload like every other action field, and the proposal shows it in full under the button, since it goes to the PM in the hire's name. Confirming refreshes the path and the step page, which now picks up the pending reason too. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
waits_on_ids and unlocks_ids ride the proposal and the confirm payload like the other action fields, so a step the buddy adds lands connected in its phase graph. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
The class string had the space inside the interpolated value, which the Tailwind Prettier plugin trims when it sorts, and the className test caught it. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
The onboarding is the path on the Onboarding page. The board carried a second one: a "Your path here" rail from joining to a first accepted contribution that announced when "onboarding ended", and a "Build my path" button that copied the path's steps into checklists once, matched by title, and then drifted from it. - Removed the path-to-first-contribution card and rail, and their moment labels. - Removed "Build my path", pathToCards, useGeneratedPathCards and applyPlan, and the card blueprints it read (a localStorage placeholder with no editor). Cards it already made stay; their invisible title markers are still stripped (layout/cardNames.ts). - The current-task card no longer tells a picked task from a handed one: nothing hands out tasks any more. - The empty board points at the Onboarding page instead. - Test fixtures moved off Task 0 and the removed card kind. Refs #311 Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
They measure joining to a first accepted contribution and review waits, not onboarding progress, which is the path. Only visible wording changes; the route and file names still say onboarding. Refs #311 Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Dev has moved a long way: PageShell chrome, lazy routes with page transitions, react-query for the hire's onboarding status, the Hire Setup rework, chat filters. This branch carries the blueprint path and the buddy that tutors along it, so the resolutions keep dev's structure and this branch's onboarding: - AppRouter takes dev's lazy/transition version, with the blueprint pages added in the same shape (dev has no /blueprints yet). - OnBoardingPage keeps this branch's page (graph view, per-question modal, buddy links) inside dev's PageShell, and invalidates the dashboard's status query where it used to refresh the path alone. - OnBoardingItemPage is dev's PageShell rewrite with this branch's work re-applied: the step's number, "ask your buddy about this step", the refresh after a buddy action, and "next" resolved from the shared resolver, which knows questions rather than phase checks. - Phase checks and the review pool are gone here -- the blueprint replaced them with per-phase questions -- so dev's PhaseCheckModal, ReviewCheckModal and review-pool reads are not carried over. - ChatComposer keeps both sides: dev's filter popover and this branch's focus handling for a value set from outside. - The PM metrics page keeps its "contribution metrics" wording on top of dev's react-query refactor. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Two things the hire or the PM was asked to take on trust. Asking the buddy to flag something to the PM produced a button that said "Flag this to your PM" and nothing else. The question it composed -- the whole of what lands in that person's inbox, in the hire's name -- was already on the proposal and simply never rendered. A skip request has shown its reason under the button since it existed; this is the same rule applied to the other action that leaves the product. The Task-0 toggle, meanwhile, still told a PM the task would be "handed to a new hire as their very first task". It is not handed to anybody any more: the flag is a note on the pool entry, and hires claim their own work. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Keeps both sides: the path tutor from #311 and what dev brought in (team-mode buddy, board checklist actions, PATH_STEP card, the reworked onboarding journey). Task 0, the ramp and the path-to-first-contribution card stay retired; dev code that still reached for them was adapted. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
The buddy writes `/onboarding?step=`, `?question=` and `?phase=` links into its replies. The journey rework (#228) only knew `/onboarding/:stepId`, so these fell through to the overview. They are now an arrival like the others, with one difference kept on purpose: a link lands instead of starting. The owning phase opens in the list, the row scrolls into view and lights up once, and nothing is unfolded or started -- following a link is finding something, starting it is the hire's own click. The handled parameter is dropped from the address, and following the same link again lands again. Refs #311 Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
The buddy names items "#3" and a hire answers "let's do 3". The reworked list and phase graph showed no numbers, so neither side could point at anything. Both now carry `itemNumbers` -- steps first, then questions, the rule `BuddyPathTools` numbers by. The list reads in graph order, so the numbers are labels rather than a count down it. Also keeps the link highlight working: the Tailwind Prettier plugin trimmed the space after `app-link-highlight` and glued it to the next class, so it now sits in its own interpolation at the end. Refs #311 Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
The step page, the question dialog and the old phase header each had a way into the conversation, and the journey rework (#228) replaced all three. The ways in come back where the things now live: - A step still open offers "Stuck? Ask your buddy about this step". - A question offers the material before an attempt (louder on one already answered wrong), and right after a wrong answer offers to go through it -- the buddy is not given the answer, so it never promises one. - The phase header offers a walkthrough, and an empty phase offers to work out with the buddy what it should contain; so does the screen shown when no phase could be generated. Each only pre-fills the composer; the hire sends it. Refs #311 Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
The dock confirms path actions (tick a step or a line off, answer, add a step, request a skip) over whatever page is open, and announces it with `announceBuddyPathChanged`. After the journey rework nothing listened any more, so the page behind the dock kept showing the old state. - The onboarding page re-reads the path; an open step re-reads its tasks and status. - The board's "where you are" strip reads the path again. - `useBuddyPathSync`, mounted once in the app, marks the board and the onboarding status queries stale, which covers the PATH_STEP cards and the dashboard's next-step card. Refs #311 Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
The step origin badge says "You added this" to the hire. The journey rework's member view reused it without `viewer="reviewer"`, so a PM read a hire's own step as one they had added themselves. Refs #311 Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
The buddy links a step with a pending skip request to `/onboarding/<id>` so the hire can change or withdraw the reason, which lives in the unfolded step. The journey page starts a waiting step when it unfolds it, so following that link began the very step the hire asked to skip. A step with a pending skip is now opened without being started; its own "Start" button still starts it. Refs #311 Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
A dead question link now says it was a question, the reduced-motion link highlight goes away like the animated one instead of staying for good, and the linkedCardId and DependencySource doc comments sit where they belong. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
PR Review — Make the buddy the tutor along the onboarding path (#267)Head 🔴 BlockingNone. 🟠 Should fix before merge
🟡 Minor
🔵 Nits (non-blocking)
✅ Checked and sound
Verdict: approve after 1–3. 4 and 5 are small and worth doing in the same pass. |
- Scroll to a linked card once the list has slid in, and only once per link - Clear the link highlight when it has played or the phase changes; key rows by item so a link no longer remounts an open step, and let the pulse end with `backwards` - Keep a half-typed skip reason or feedback comment when the buddy changes the path, and skip the second step read when the path catches up - Keep the item open when a link points at it; let go of an open graph item on a link - Hold back starting a skip-pending step only for `/onboarding/<id>` arrivals - Reject `/\host` links; offer the buddy for every empty phase, not just the first - PenLine icon for hire-added steps, drop an unneeded `questions` fallback, fix a stale comment Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
daniilperkin
left a comment
There was a problem hiding this comment.
Reviewed cbbe63b7 against dev (0fdb2cdd) — source diff read in full, cross-repo contract checked by hand (CI proves nothing here, it runs against current dev).
Retirement is clean. PATH_TO_FIRST_CONTRIBUTION, BoardPathNotes, momentLabels, pathToCards, useGeneratedPathCards, card-blueprints/ have zero remaining references in src/ and tests/; the kind is gone from BoardCardKind, so every exhaustive map/switch is compiler-checked. The single Build my path hit is the comment in cardNames.ts describing the retired generator.
Wire contract matches backend #261 exactly: POST /api/v1/onboarding/me/buddy/actions (hasRole('USER')), camelCase request fields (stepId, questionId, phaseId, onboardingTaskId, answer, description, reason, waitsOnIds, unlocksIds), snake_case stream fields, and the five action names byte-identical to BuddyActionType. The same DTO on dev carries a subset, i.e. the actions genuinely do not exist there yet.
Merge order: backend #261 first — merged alone against dev, the path actions would vanish silently and confirm would be rejected. AI #208 is behaviour-only (persona/prompt, step budget) and order-independent. Task-0 endpoint, reviewer path reads and phase questions are unchanged. origin on step responses is optional and StepOriginBadge falls back, so it degrades rather than crashes.
Two points worth deciding, neither a blocker:
useBuddyPathSyncinvalidates the board only forBUDDY_PATH_ACTIONS. Confirmable board-writing actions (claim_goal, the checklist actions) still don't announce, so the stale-card symptom this PR fixes for path actions remains for those — pre-existing and one-line fixable, but it is the same class of bug.BuddyMarkdownis also used for GitHub issue excerpts (CorpusIssueBrowser.tsx:434), so the new root-relative in-app-link rule now renders an external text's/…link as an SPA navigation instead of a new tab.
Also: the branch conflicts with the current dev tip in exactly one file, BuddyComposer.tsx — #184's caret/dino handoff and this PR's external-draft caret rule overlap, so it needs a backmerge before merging. I can do that pass and resolve it by keeping both behaviours.
Approving on the code as reviewed; the ordering constraint above is the thing to respect at merge time.
Summary
The onboarding page and the buddy now point at the same things: buddy links land on the right step, question or phase, items carry the numbers the buddy uses, every step, question and phase can open the buddy, and the page refreshes after a confirmed buddy action. The board's second onboarding (path card, "Build my path", card blueprints) is gone.
Refs SprintStartProject/Wiki#311
Changes
Onboarding page
/onboarding?step=…,?question=…,?phase=…open the phase, scroll to the item and highlight it briefly. They don't unfold or start anything. The highlight respects reduced motion.#nnumbers in the list and on graph nodes (itemNumbers), the same numbers the buddy uses.buddyDrafts)./onboarding/<id>isn't started while a skip request on it is pending.Buddy
complete_step,complete_task,answer_question,add_path_step,request_skip). The confirm shows the skip reason and the message a flag sends to the PM.announceBuddyPathChangedrefreshes the onboarding page, the open step and the board's path strip.useBuddyPathSyncinvalidates the cached statuses and the board.ChatComposer.Step origin
StepOriginBadgereads the neworigin: "Added with your buddy", "You added this", "Custom step by PM". Reviewers see "the hire" / "the buddy" instead of "you".Retired from the board
PATH_TO_FIRST_CONTRIBUTIONcard,BoardPathNotesandmomentLabels.pathToCards,useGeneratedPathCards), the local-storage card blueprints and the "team" filter.chosenon the current-task card, since nothing hands out a Task 0 any more.Wording
Testing
npm run lint,npm run format:check,npm run build: greennpm run test: 2972 passedNotes
originand the moved Task 0 endpoint. Merge together.Related PRs
🤖 Generated with Claude Code