Skip to content

feat(terminal-demo): constrain and compose VHS tapes - #580

Merged
ss-o merged 1 commit into
mainfrom
feature-458
Aug 30, 2026
Merged

feat(terminal-demo): constrain and compose VHS tapes#580
ss-o merged 1 commit into
mainfrom
feature-458

Conversation

@ss-o

@ss-o ss-o commented Aug 30, 2026

Copy link
Copy Markdown
Member

Summary

  • add internal/tape: a data-only parser for behavior-only VHS tapes and a canonical composer for the trusted presentation header
  • accept only the reviewed V1 interaction subset of VHS v0.11.0 grammar and reject every other directive, including Output, Set, Source, Require, Env, Screenshot, Copy, Paste, Hide, Show, and every per-directive @ timing override
  • originate every central control (output destination, shell, geometry, font, theme, framerate, typing speed, cursor blink) from typed configuration, never from tape text
  • enforce the immutable limits.V1() bounds for tape bytes, directive count, typed bytes, wait patterns, key repeats, and sleep/wait totals
  • add committed valid and invalid tape fixtures, exercised by fixture-driven tests

Refs #458

Contract boundaries

Parsing is data-only: it never invokes a shell, VHS, the filesystem, the environment, or the network, and it never matches a wait pattern. Regular expressions are compiled solely to validate syntax. Source line numbers are preserved for sanitized structured diagnosis.

Every rejection uses the existing sanitized boundary failure.InvalidContract / failure.StageTape / failure.RuleTapeInvalid with public exit code 2. No public class, stage, rule, or exit code was added or renamed. The structured field carries only a bounded schema-owned category and line number; a test asserts that neither Error() nor the field leaks tape source text, patterns, commands, or output paths.

Compose requires the exact approved presentation config and independently revalidates each directive, so a caller that constructs a Directive without Parse cannot bypass the contract. Kind is a closed enum.

Base reconciliation

The written plan and Task 3 brief name base bd6234ac4e5ab6eebc109c76ce9d21672144da5d on an isolated feature-458 worktree. That state no longer exists: PR #460 merged on 2026-07-25 as 6f6b825b, no feature-458 branch survived on origin, and bd6234ac:tools/readme-terminal-demo differs from origin/main:tools/readme-terminal-demo across 9 files. Building on the recorded base would have discarded the merged review fixes, so this work is based on current origin/main, which contains bd6234ac as an ancestor. No Task 1-2 behavior changed.

Verification against real VHS v0.11.0

The composed golden tape was fed to the actual VHS v0.11.0 lexer and parser in the pinned Go image: 0 parse errors, 18 commands, Ctrl+"L" resolving to args L, and each Wait@10s / Wait+Line@10s / Wait+Screen@10s carrying its fixed timeout. Upstream source confirms the assumptions encoded here: lexer.readString performs no escape interpretation and cannot span a newline, and readRegex uses the odd-backslash delimiter rule.

Defects found and fixed during TDD

  1. Sub-millisecond sleeps parsed successfully but could not be emitted as a VHS time token, so a parse/compose round trip would truncate them. Sleep must now be a whole number of milliseconds.
  2. Compound durations such as 1m30s are rejected during composition. VHS parseTime accepts exactly one number plus one unit and would misparse the compound Go duration form.

Verification

All commands ran through the pinned scripts/in-go-image.sh wrapper (Go 1.26.5, linux/amd64); host Go was never an acceptance path.

  • go test ./internal/tape -count=1: PASS, 14 top-level tests
  • go test ./internal/tape -run 'TestParseRejects|TestComposeGolden' -count=1: PASS, 59 rejection subtests, byte-stable golden
  • go test ./... -count=1: PASS, including internal/sandbox
  • go vet ./...: clean
  • gofmt -l .: clean
  • go mod tidy -diff: reports only the pre-existing Goldmark pin reserved by the approved plan for later README verification; this change introduces no module drift

Status

This is a draft implementation PR. Task 4 and later repository opening, fixture staging, README validation, rendering, render/verify orchestration, workflow and image publication, pilots, merge, release, and pattern promotion remain outstanding and maintainer-gated. No image publication, release tag, merge, pilot rollout, or pattern promotion has occurred.

@ss-o
ss-o marked this pull request as ready for review August 30, 2026 19:04
@ss-o
ss-o requested a review from a team as a code owner August 30, 2026 19:04
@ss-o
ss-o merged commit 947b60d into main Aug 30, 2026
5 checks passed
@ss-o
ss-o deleted the feature-458 branch August 30, 2026 19:06
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.

1 participant