Repository navigation
Conversation
Add runbook-steps.ts: a pure compiler that turns pack requirements, action_items (or the linked SOP) into 1-of-N steps anchored to the video timeline using only pack evidence - extractor-reported ranges, grounded-spec citations, transcript segments quoting named tool evidence or sharing distinctive vocabulary, chapters, and visual events. Steps without evidence keep timestamp_range null. Includes Step 0 prerequisites from stack.tools / stack checks, verification from grounded acceptance criteria or tool checks, RUNBOOK.md rendering, and time/hash lookups. Requirements and action_items gain optional start_s/end_s (no schema version bump). Fixture is the live pBsT6v-ciO8 pack slice. Co-authored-by: KK <kk-agent@users.noreply.github.com>
Ask Gemini for optional start_s/end_s on requirements and action_items (omit when not observed, never guess) and keep only finite, ordered, non-negative ranges in the parser. Pass bounded code_snippets through verifyIdentityPack so the browser pack can show code steps. No stored-pack schema version bump: existing packs keep working and derive anchors client-side. Co-authored-by: KK <kk-agent@users.noreply.github.com>
seekTo(seconds, { autoplay: false }) seeks and explicitly pauses so the
Step Runner can honor an 'Autoplay step clip' toggle. Default behavior
(seek + play) is unchanged; covered by a jsdom hook test with a stubbed
IFrame API.
Co-authored-by: KK <kk-agent@users.noreply.github.com>
Accept a bounded, zod-validated step context on POST /api/chat. When present (and only with a pack binding), the system prompt becomes identity + the active step + the transcript/visual evidence inside a 15s-padded window around the step's anchored range; whole-pack SOP and action lists stay out so one step's troubleshooting does not drag the full pack back into context. Steps without a verified timestamp fall back to the whole transcript and say so. Malformed step contexts fail closed (400) before any model call. Co-authored-by: KK <kk-agent@users.noreply.github.com>
StepRunner: 'Step n of N' stepper with Previous/Next/quick-jump, Step 0 prerequisites checklist, per-step card (action type, anchored time range with provenance, keyframe, quote, command/snippet with copy, inputs/ outputs, verification + local completion mark, troubleshoot hook). Selecting a step scrolls to top, writes #step-n, seeks the player to the anchored start (cue-only when 'Autoplay step clip' is off, pauses at the clip end when on), and reports the active step for chat re-grounding. Unanchored steps disable seek and say why. StudioRunbookPane switches between the runner and a copy/download RUNBOOK.md reference view. Co-authored-by: KK <kk-agent@users.noreply.github.com>
Wire the Step Runner into OneLoopStudio: compile the runbook from the selected pack (+ linked SOP), hand the runner a player slice only when the loaded video is the pack video, persist checked prerequisites and completed steps on the Video row, and re-ground the chat composer to the active step (chip + 'step' body field, clearable; Troubleshoot focuses the composer). StudioIdeOutput gains a first 'Runbook' tab that opens by default when a runbook exists; the seven extraction tabs are unchanged. Export ships the rendered RUNBOOK.md. A pack switch drops a stale #step-N hash while /studio#step-N deep links still restore the step. Co-authored-by: KK <kk-agent@users.noreply.github.com>
…seek Keep 'Step n of N' on one line at the default 340px Deliverables width (select on its own row, autoplay + progress on one row) and distinguish 'player still loading/failed' from 'player shows a different video' when seeking is disabled. Co-authored-by: KK <kk-agent@users.noreply.github.com>
Co-authored-by: KK <kk-agent@users.noreply.github.com>
|
The latest updates on your projects. Learn more about Vercel for GitHub.
|
🔍 PR Validation |
|
Important
This repository does not receive automatic reviews because it has fewer than 10 stars. ⚙️ Run configuration
Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out. Comment |
Codex Review SummaryThis comment shows the latest Codex review activity on this pull request.
ℹ️ About Codex in GitHubYour team has set up Codex to review pull requests in this repo. Reviews are triggered when you
Codex reacts with 👀 while any review is running, comments if it has suggestions, and reacts with 👍 once all reviews finish with no findings. |
|
Please add a See governance: #898 |
There was a problem hiding this comment.
💡 Codex Review
Here are some automated review suggestions for this pull request.
Reviewed commit: 7ffcb382c9
ℹ️ About Codex in GitHub
Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you
- Open a pull request for review
- Mark a draft as ready
- Comment "@codex review".
If Codex has suggestions, it will comment; otherwise it will react with 👍.
Codex can also answer questions or update the PR. Try commenting "@codex address that feedback".
| * grounded_spec candidate are copied verbatim. Nothing here is synthetic; | ||
| * tests that need an unanchored step add their own rows. | ||
| */ | ||
| export const PBST6V_VIDEO_ID = "pBsT6v-ciO8"; |
There was a problem hiding this comment.
Replace the noncanonical runbook fixture
The newly added runbook fixture and its dependent tests use pBsT6v-ciO8, but this repository requires all test fixtures to use auJzb1D-fag; replace the fixture data, identities, frame paths, and assertions with the canonical video so this suite follows the repository's locked test-data convention.
AGENTS.md reference: AGENTS.md:L93-L93
Useful? React with 👍 / 👎.
| if (candidate.explicitRange) { | ||
| range = candidate.explicitRange; | ||
| anchor = 'extracted'; |
There was a problem hiding this comment.
Preserve grounded verification for explicitly timed steps
When a requirement has extractor-provided start_s/end_s and also corresponds to a grounded-spec citation with acceptance criteria, this branch skips citation matching and leaves groundedIds empty. The later acceptance-criteria filter therefore discards the grounded verification and emits a generic comparison or stack check instead; resolve the matching grounded requirement independently while still allowing the explicit range to win as the timestamp anchor.
Useful? React with 👍 / 👎.
| currentTime >= end && | ||
| currentTime < end + CLIP_END_GRACE_SECONDS && | ||
| clipPausedForRef.current !== activeStep.id | ||
| ) { | ||
| clipPausedForRef.current = activeStep.id; | ||
| pause(); |
There was a problem hiding this comment.
Re-arm clip stopping when replaying the active step
After autoplay pauses a step once, clipPausedForRef remains set to that step ID. If the user clicks “Seek to” to replay the same step, the guard remains false when playback reaches the end again, so the video continues beyond the selected clip; clear or otherwise re-arm this marker whenever the active step is manually sought.
Useful? React with 👍 / 👎.
| const grounded = await resolveChatPackGrounding(packBinding, { | ||
| step: stepContext.status === 'ok' ? stepContext.step : null, | ||
| }); |
There was a problem hiding this comment.
Derive chat step context from the hosted pack
Any caller with a valid pack ID can submit an arbitrary schema-valid step, and this route forwards its client-supplied title, instructions, verification text, tools, and timestamp range directly into the system prompt without confirming that the step exists in the hosted pack. A forged request can therefore inject invented step evidence and select an unrelated transcript window while the response is presented as pack-grounded; resolve the step ID against a server-compiled runbook and reject mismatched client fields.
AGENTS.md reference: AGENTS.md:L72-L72
Useful? React with 👍 / 👎.
| const body: Record<string, unknown> = { query, history }; | ||
| if (videoId) body.video_id = videoId; | ||
| if (packId) body.pack_id = packId; | ||
| if (stepContext && (videoId || packId)) body.step = stepContext; |
There was a problem hiding this comment.
Clear prior-step history when changing chat scope
When the user chats about one step and then advances to another, the component sends the new stepContext together with the last ten messages from the previous step. The server includes that history in the model conversation, so prior out-of-window questions and answers can override or contaminate the new step-scoped grounding despite the prompt intentionally limiting evidence to the active window; reset or partition history when the active step identity changes.
Useful? React with 👍 / 👎.
|
|
||
| export function runbookStepToChatContext(step: RunbookStep, totalSteps: number): ChatStepContext { | ||
| return { | ||
| id: step.id, |
There was a problem hiding this comment.
Bound generated step IDs to the API schema
The compiler prefixes source IDs with rb- without imposing a length limit, but this serializer forwards the result unchanged while the server rejects IDs longer than 64 characters. A valid 64-character extractor ID therefore becomes a 67-character runbook ID, and every scoped chat or troubleshooting request for that step fails with step_context_invalid; generate a bounded stable ID or make the client and server limits consistent.
Useful? React with 👍 / 👎.
| if (selectionMountedRef.current && parseRunbookStepHash(window.location.hash) !== null) { | ||
| window.history.replaceState( | ||
| window.history.state, | ||
| '', | ||
| `${window.location.pathname}${window.location.search}`, | ||
| ); | ||
| } | ||
| selectionMountedRef.current = true; |
There was a problem hiding this comment.
Preserve the initial step hash during pack auto-selection
On a hard load of /studio#step-N, selectedVideoId initially has no value because the persisted store saves videos but not the selection. This effect marks selectionMountedRef on that empty render, so when the stored pack is auto-selected moments later it treats the first real selection as a pack switch and removes the hash before StepRunner can restore it; only arm hash clearing after an actual initial selection has been established.
Useful? React with 👍 / 👎.
| start_s: z.number().nullable().optional(), | ||
| end_s: z.number().nullable().optional(), |
There was a problem hiding this comment.
Drop malformed optional ranges without dropping the action
Adding start_s and end_s to the strict action-item parse means an otherwise valid action item is now discarded entirely whenever an extractor or older stored pack supplies either optional timestamp in a nonnumeric form. This contradicts parsePackTimeRange's contract to drop invalid ranges and regresses inputs that were accepted before these keys became schema fields; parse the core action independently and pass the raw optional bounds to parsePackTimeRange.
Useful? React with 👍 / 👎.
| completed={current.completedSteps.includes(activeStep.id)} | ||
| canSeek={canSeek} | ||
| seekBlockedReason={seekBlockedReason} | ||
| onSeek={() => { |
Canonical issue
Related to #2331 (Studio IDE rebuild). No open issue describes this cut and this agent token cannot create one (same blocker as #2436 / #2437), so there is no
Closes #Nyet — please link or open the canonical issue.Outcome
The Deliverables pane stops being a static reference and becomes a 1-of-N Step Runner modeled on the Pollen Robotics assembly guide: every step is anchored to the video timeline from pack evidence,
Nextseeks the player, a Step 0 prerequisites checklist precedes Step 1, a Full Runbook Markdown mode exportsRUNBOOK.md, and the chat is re-grounded to the active step's transcript window.Intent-vs-execution audit (see
apps/web/src/lib/step-runner-PLAN.md§0): extraction already produced time-anchored evidence (segments, chapters, visuals, keyframes, grounded-spec citations), but Studio presented it as text and nothing in the pane drove the player. This PR closes that gap at the presentation layer without inventing evidence.Scope
lib/runbook-steps.ts— pure compiler: requirements / action_items (or linked SOP) → steps withid,step_number,title,kind,timestamp_range | null,anchorprovenance,content_markdown,verification(+ source), inputs/outputs, snippet, keyframe. Anchors only from: extractorstart_s/end_s, validated grounded-spec citations, transcript segments quoting namedstack.toolsevidence or sharing distinctive vocabulary, chapters, visual events. Step 0 prerequisites fromstack.tools/ stack checks / explicit access & runtime mentions.RUNBOOK.mdrenderer.components/studio/StepRunner.tsx,StudioRunbookPane.tsx— stepper (Prev/Next/quick-jump,#step-nhash, scroll-to-top), Autoplay-step-clip toggle (cue-only seek when off, pause at clip end when on), "Playing: Step k" follow chip, per-step card, local completion notes, Troubleshoot hook, markdown copy/download.StudioIdeOutput— new first Runbook tab, default when a runbook exists; the seven extraction tabs are unchanged.StudioIdeChat+api/chat/route.ts+chat-pack-grounding.ts— bounded, zod-validatedstepbody field → identity + active step + transcript/visual evidence inside a 15s-padded window (whole-pack SOP/action lists omitted). Fails closed on malformed step or missing pack binding.use-youtube-player.ts—seekTo(seconds, { autoplay })(default unchanged).start_s/end_son requirements and action_items ("omit when not observed — never guess"); client citation now carries boundedcode_snippets. NoVIDEO_PACK_STRUCTURE_SCHEMA_VERSIONbump (would force a paid re-extract of every stored pack); stored packs derive anchors client-side.Video.runbookProgress(local notes),RUNBOOK.mdin Export.Risk
Verification
Head SHA:
7ffcb382ccd apps/web && npx vitest run src/lib/__tests__/runbook-steps.test.ts src/components/studio/__tests__/StepRunner.test.tsx src/components/__tests__/OneLoopStudio.runbook.test.tsx src/lib/__tests__/chat-pack-grounding.test.ts src/app/api/__tests__/chat-pack-grounding-route.test.ts src/lib/__tests__/use-youtube-player.test.ts src/lib/__tests__/emit-video-pack.test.ts src/lib/__tests__/video-pack-extractor.test.ts src/lib/__tests__/action-surface.test.ts→ all greennpx vitest run→ 173 files, 1563 passed, 28 skipped (pre-existing opt-ins)npx tsc --noEmitexit 0 ·npx eslinton touched files exit 0 ·npx next buildexit 0POST /api/chat, memory pack store seeded with the livepBsT6v-ciO8pack, real Vercel AI Gateway call → 200 in 1086 ms: "The speaker says, 'Step one: search up SeaDance 2.5, find any provider,' at 4:07–4:14 in the video."Fixture is a verbatim slice of the live
pBsT6v-ciO8pack (GET returned 200 on 2026-10-17); no synthetic rows except where a test needs an unanchored step.Production evidence
UI + API contract change; preview on Vercel
v0-uvaiafter CI. Not a production E2E. Two things could not be exercised in the agent VM and are environment limits, not code: the YouTube embed returned Error 153 onhttp://localhost(embed needs an https referer; CSP already allows youtube.com), and the production-mode proxy guard returned 503 "distributed rate limiting is not configured" (no Upstash credentials here). Live Gemini extraction of the new optionalstart_s/end_swas not run (noGOOGLE_API_KEY); the parser path is unit-tested.studio-step-runner-walkthrough.mp4
Runbook tab opens on Step 0 prerequisites
Step 1 card with anchored range, kind, verification
Full Runbook Markdown view
Agent handoff
AGENTS.md; it was explicitly requested, so Loop should confirm authorization before merge.To show artifacts inline, enable in settings.