Skip to content

fix(skills): resolve the blueprint id from a qualified blueprint: field - #3337

Open
miguel-heygen wants to merge 3 commits into
mainfrom
fix/blueprint-qualifier
Open

fix(skills): resolve the blueprint id from a qualified blueprint: field#3337
miguel-heygen wants to merge 3 commits into
mainfrom
fix/blueprint-qualifier

Conversation

@miguel-heygen

@miguel-heygen miguel-heygen commented Aug 18, 2026

Copy link
Copy Markdown
Collaborator

What

The frame-packet builder now parses the blueprint: field into the blueprint id it names, instead of using the raw field as a filename. A blueprint that resolves to no file is a named error rather than a silently empty section.

Why

references/visual-design.md documents blueprint: as the id plus a (Reproduce) / (Adapt) qualifier, and prints dataviz-countup (Adapt) as its worked example. The resolver passed that raw value straight to join(animationDir, "blueprints", ${blueprint}.md), so a qualified blueprint looked for <id> (Adapt).md. That file cannot exist, and selectedFile() returns "" for a missing path.

The result: every packet shipped without the one document the frame was designed against, and the run still exited 0 with nothing on stderr. On a storyboard whose only difference was the documented qualifier, packets dropped from 17836 bytes to 648 bytes with no ## Selected blueprint section, and the CLI still printed ✓ frame packets: 1 bounded packet(s).

compose (Adapt) missed the compose check the same way, so it went looking for compose (Adapt).md.

This affects product-launch-video, faceless-explainer, pr-to-video and general-video, which all delegate to the shared builder.

How

blueprintId(block) parses the field once, so no caller resolves a raw field value against the blueprints directory. The qualifier is direction for the frame worker, not part of the filename.

A blueprint with no file now throws, naming the frame, the id and the path. That matches how the builder already treats a missing src and an oversize packet, and it means a typo fails the run instead of quietly producing a packet with no motion guidance.

The docs are correct as written and are unchanged; the resolver was the side that was wrong.

Test plan

Three cases added to frame-packets.test.mjs: a qualified id resolves to a byte-identical blueprint body across (Adapt), (Reproduce) and the bare form; a qualified compose still selects nothing; a blueprint with no file throws and leaves no partial output.

The existing tests used bare ids only, which is how the documented form escaped them. Verified the two new behavioural cases fail on the parent commit and pass here.

  • Unit tests added/updated
  • Manual testing performed
  • Documentation updated (if applicable)

Review notes

Two follow-up commits, both from making the failure visible.

1. Absent library vs bad id. Throwing on any unresolvable blueprint was too broad. hyperframes-animation installs on demand, so an absent blueprints/ directory is a skill that isn't installed yet, not a frame naming a bad id. The second commit splits them: an absent library warns and inlines nothing, exactly as an absent rules/ already does in knownRuleIds; a present library with no file for this id still throws.

2. Two dead blueprint references, surfaced by CI. The new error caught two ids that have never existed in hyperframes-animation/blueprints/:

  • skills/faceless-explainer/references/story-design.md — the frame template taught messaging-multi-phase, so an agent copying it verbatim tagged a blueprint that resolves to nothing. This is the bug reaching users through the docs, not just a fixture.
  • skills/pr-to-video/scripts/workflow-guardrails.test.mjs — the diff-excerpt fixture used number-lockup.

Both now point at dataviz-countup, which the faceless-explainer skill already uses in its own visual-design template and tests, and which matches the pr-to-video frame's own counting-dynamic-scale rule. A sweep of every blueprint: value across skills/ finds no others.

miguel-heygen and others added 3 commits August 18, 2026 19:47
…ield

visual-design.md documents `blueprint:` as the id plus a `(Reproduce)` /
`(Adapt)` qualifier, and prints `dataviz-countup (Adapt)` as its worked example.
The packet builder used that raw field as a filename, so a qualified blueprint
looked for `<id> (Adapt).md`, found nothing, and inlined an empty string:
`selectedFile()` returns "" for a missing path. Every packet shipped without the
one document the frame was designed against, and the run still exited 0 with
nothing on stderr. `compose (Adapt)` missed the `compose` check the same way.

Parse the field into the id it names, once, so no caller resolves a raw field
value against the blueprints directory. A blueprint that resolves to no file is
now a named error rather than an empty section, matching how the builder already
treats a missing `src` and an oversize packet.

The existing tests only used bare ids, which is how the qualified form escaped;
they now cover both, and the missing-file case.

One owner: product-launch-video, faceless-explainer, pr-to-video and
general-video all delegate to frame-packets-core.mjs.

Co-Authored-By: anikam13 <22992075+anikam13@users.noreply.github.com>
Self-review catch on the previous commit. hyperframes-animation installs on
demand, so its blueprints/ directory can legitimately be missing — that is a
skill that isn't installed yet, not a frame naming a bad id. Throwing there
turned a silent degrade into a hard failure for a valid setup.

Distinguish the two: an absent blueprints/ warns and inlines nothing, exactly
as an absent rules/ already does in knownRuleIds; a present library that has no
file for this id still throws, because that is a typo or an unstripped
qualifier.

Co-Authored-By: anikam13 <22992075+anikam13@users.noreply.github.com>
CI surfaced these once an unresolvable blueprint stopped being silent. Both
named ids that have never existed in hyperframes-animation/blueprints/:

- faceless-explainer's frame template taught `messaging-multi-phase`, so an
  agent copying the template verbatim tagged a blueprint that resolves to
  nothing. dataviz-countup is what the same skill already uses in its own
  visual-design template and tests.
- pr-to-video's diff-excerpt guardrail fixture used `number-lockup`. The test is
  about diff excerpting and the id was incidental; the frame's own
  `counting-dynamic-scale` rule makes dataviz-countup the natural real shape.

A sweep of every `blueprint:` value across skills/ finds no others.

Co-Authored-By: anikam13 <22992075+anikam13@users.noreply.github.com>
miga-heygen
miga-heygen previously approved these changes Aug 19, 2026

@miga-heygen miga-heygen left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Approve — parsing is correct. The regex \s*\([^)]*\)\s*$ strips trailing parenthesised qualifiers cleanly; compose null-return is case-insensitive; the absent-library vs bad-id split mirrors the existing knownRuleIds pattern. Four test cases cover bare, qualified, compose-qualified, missing-file-throws, and uninstalled-library-warns — comprehensive. Dead reference fixes (messaging-multi-phasedataviz-countup, number-lockupdataviz-countup) are confirmed valid by the sweep. No issues.

— Miga

@miga-heygen
miga-heygen dismissed their stale review August 19, 2026 20:28

Stamp removed — was posted prematurely

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants