Skip to content

feat(dreaming): add dreaming#1442

Open
paulbockewitz wants to merge 4 commits into
mvanhorn:mainfrom
paulbockewitz:feat/dreaming
Open

feat(dreaming): add dreaming#1442
paulbockewitz wants to merge 4 commits into
mvanhorn:mainfrom
paulbockewitz:feat/dreaming

Conversation

@paulbockewitz

@paulbockewitz paulbockewitz commented Jul 5, 2026

Copy link
Copy Markdown
Contributor

dreaming

Every Dreaming Spanish and French tracking feature in one offline-first, agent-native CLI: roadmap math, transcript concordance, and bulk hour-logging.

API: dreaming | Category: education | Press version: 4.24.0
Spec: Hand-authored from the internal Netlify Functions API (no official spec)

Publication Path

New print. (Supersedes closed PR #1279: its branch base predated ~1,200 commits on main, which made the changed-CLI Govulncheck selection scan 304 unrelated modules and fail on pre-existing stale go.mod files elsewhere. This PR is rebuilt on current main and includes the fix for the greptile review finding on next ordering — unrated videos now sort last.)

CLI Shape

$ dreaming-pp-cli --help
Dreaming CLI — Every Dreaming Spanish and French tracking feature in one offline-first CLI - roadmap math, catalog search, and bulk hour-logging

Highlights (not in the official API docs):
  • next   Get the next unwatched videos tuned to where you are on the fluency roadmap, sorted by fine-grained difficulty.
  • external import   Import a backlog of outside listening/watching hours from a CSV in one command instead of dozens of web-form clicks.
  • diet   See whether the difficulty of what you actually watch is trending up over a window - the real signal that you're ready to level up.
  • roadmap   The whole L1-L7 ladder with comprehensible-input advisories (speaking, reading, native milestones) and personalized calendar ETAs in one view.
  • transcript   Fetch a video's captions as clean, timestamp-free plain text (and cache the cue-level transcript).
  • concordance   Search every cached transcript for a word, phrase, regex, or verb-tense pattern and get each hit in context with the video, level, guide, and timestamp.

Agent mode: add --agent to any command for JSON output + non-interactive mode.
Health check: run 'dreaming-pp-cli doctor' to verify auth and connectivity.
See README.md or the bundled SKILL.md for recipes.

Usage:
  dreaming-pp-cli [command]

Available Commands:
  agent-context          Emit structured JSON describing this CLI for agents
  api                    Browse all API endpoints by interface name
  auth                   Manage authentication for Dreaming
  completion             Generate the autocompletion script for the specified shell
  concordance            Search every cached transcript for a word, phrase, regex, or verb-tense pattern (KWIC)
  day-watched-time       List per-day on-platform watch time
  diet                   See whether the difficulty of what you actually watch is trending up over a window
  doctor                 Check CLI health
  download               Resolve a video's downloadable stream (prints the URL; --exec downloads via ffmpeg)
  export                 Export data to JSONL or JSON for backup, migration, or analysis
  external               external subcommands: import
  feedback               Record feedback about this CLI (local by default; upstream opt-in)
  help                   Help about any command
  import                 Import data from JSONL file via API create/upsert calls
  inspect-external-video Resolve a YouTube URL for external-time logging
  migrate                Copy your external-time log to another account or language (requires a destination token)
  next                   Get the next unwatched videos tuned to where you are on the fluency roadmap, sorted by fine-grained difficulty.
  plan                   Back-solve the daily minutes needed to hit an hours target or level by a date
  playlist               List your watched-video playlist
  profile                Named sets of flags saved for reuse
  roadmap                The whole L1-L7 ladder with comprehensible-input advisories and personalized ETAs
  search                 Full-text search across synced data or live API
  sign-in                Exchange email/password for a bearer token
  stats                  Show input-hours analytics: totals, rolling averages, streak, and best day
  sync                   Sync API data to local SQLite for offline search and analysis
  transcript             Fetch a video's captions as clean, timestamp-free plain text (and cache the cue-level transcript).
  user                   Get your account stats (hours, daily goal, subscription)
  version                Print version
  video                  Get a single video's metadata, captions, and stream sources
  videos                 List the video catalog
  which                  Find the command that implements a capability
  workflow               Compound workflows that combine multiple API operations

Flags:
      --agent                   Set all agent-friendly defaults (--json --compact --no-input --no-color --yes)
      --allow-partial-failure   Downgrade response-body partial-failure (e.g. partialFailureError) to a warning instead of a non-zero exit
      --compact                 Return only key fields (id, name, status, timestamps) for minimal token usage
      --config string           Config file path
      --csv                     Output as CSV (table and array responses)
      --data-source string      Data source for read commands: auto (live with local fallback), live (API only), local (synced data only) (default "auto")
      --deliver string          Route output to a sink: stdout (default), file:<path>, webhook:<url>
      --dry-run                 Show request without sending
  -h, --help                    help for dreaming-pp-cli
      --human-friendly          Enable colored output and rich formatting
      --idempotent              Treat already-existing create results as a successful no-op
      --ignore-missing          Treat missing delete targets as a successful no-op
      --json                    Output as JSON
      --max-age duration        Maximum acceptable age of local-store data before a stderr hint suggests sync; 0 disables (default 30m0s)
      --no-cache                Bypass response cache
      --no-color                Disable colored output
      --no-input                Disable all interactive prompts (for CI/agents)
      --plain                   Output as plain tab-separated text
      --profile string          Apply values from a saved profile (see 'dreaming-pp-cli profile list')
      --quiet                   Bare output, one value per line
      --rate-limit float        Max requests per second (0 to disable)
      --select string           Comma-separated fields to include in output (e.g. --select id,name,status)
      --timeout duration        Request timeout (default 1m0s)
  -v, --version                 version for dreaming-pp-cli
      --yes                     Skip confirmation prompts (for agents and scripts)

Use "dreaming-pp-cli [command] --help" for more information about a command.

Novel Commands

Command Name Description
next Roadmap-aware next-video picker Get the next unwatched videos tuned to where you are on the fluency roadmap, sorted by fine-grained difficulty.
external import CSV bulk external-hours import Import a backlog of outside listening/watching hours from a CSV in one command instead of dozens of web-form clicks.
diet Difficulty-progression readiness analysis See whether the difficulty of what you actually watch is trending up over a window - the real signal that you're ready to level up.
roadmap Unified fluency-ladder roadmap The whole L1-L7 ladder with comprehensible-input advisories (speaking, reading, native milestones) and personalized calendar ETAs in one view.
transcript Caption / transcript fetch Fetch a video's captions as clean, timestamp-free plain text (and cache the cue-level transcript).
concordance Corpus concordance (KWIC) search over all transcripts Search every cached transcript for a word, phrase, regex, or verb-tense pattern and get each hit in context with the video, level, guide, and timestamp.

What This CLI Does

Dreaming's web app shows your hours but won't plan, search, or bulk-import for you, and the community's features are scattered across a dozen browser extensions and scripts. This CLI unifies them into one agent-native tool backed by a local SQLite mirror of your catalog, daily series, and external-hours log - so next picks your next video offline, external import clears a CSV backlog in one shot, and roadmap lays out the whole L1-L7 fluency ladder with personalized ETAs.

The Hero Feature - search Dreaming videos by content.

It also builds a searchable transcript corpus: transcript sync caches cue-level captions, concordance does keyword/phrase/regex/verb-tense KWIC search across them (each hit links to the video), and the corpus can be exported/imported so a complete corpus is built once and shared (impersonal data only). Example: search for video content related to what you are learning - specific tenses like Subjunctive or phrases like "lo que".

The CLI and skill will also download a video by ID or search the catalog by name and download it via ffmpeg/yt-dlp.

Manuscripts

Validation Results

Check Result
Manifest PASS
Phase 5 PASS
go mod tidy PASS
govulncheck (this CLI only, reachable findings) PASS
go vet PASS
go build PASS
--help PASS
--version PASS
Manuscripts PRESENT

Gaps

  • .printing-press.json has no description or spec_url field (description above is from the README/SKILL; the API has no official spec to link).
  • category was set at publish time: the v4.27.1 binary's category enum does not yet include education, though the library tree does — packaged via --category other with the correct education module path, then corrected in the manifest.

🤖 Generated with Claude Code

paulbockewitz and others added 2 commits July 4, 2026 20:26
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
…enerate-skills.yml

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
@github-actions

github-actions Bot commented Jul 5, 2026

Copy link
Copy Markdown
Contributor

@greptileai review

Auto-nudge from greptile-policy-gate.yml because no Greptile Review check appeared for e9c58196cc111e3ea3cab0743769d20b92f955c8 after 185s. This usually means the PR is over Greptile auto-review size cap; manual triggers bypass it.

…food dump

Add .manuscripts/20260618T050021Z-649b15eb/ (acceptance proof + research
provenance pointer to the 20260617-233018 print run) to satisfy the
publish-package completeness gate. Remove dogfood-live-raw.txt, which
leaked local user paths — same call the previous publish made.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
@github-actions

github-actions Bot commented Jul 5, 2026

Copy link
Copy Markdown
Contributor

@greptileai review

Auto-nudge from greptile-policy-gate.yml because no Greptile Review check appeared for 1c1acf0b8c1b087d8656d4c54c12e9f75df6fab7 after 185s. This usually means the PR is over Greptile auto-review size cap; manual triggers bypass it.

@greptile-apps

greptile-apps Bot commented Jul 5, 2026

Copy link
Copy Markdown
Contributor

Greptile Summary

This PR adds a new dreaming CLI under library/education/dreaming — a comprehensive offline-first tool for tracking Dreaming Spanish/French fluency progress with roadmap planning, transcript corpus search, and bulk external-hours import.

  • Novel commands: next (roadmap-aware video picker), diet (difficulty-trend analysis), roadmap (full L1-L7 ladder with ETAs), concordance (KWIC transcript search), external import (CSV bulk-import), transcript sync/export/import (corpus management).
  • Architecture: Local SQLite store mirroring the API (videos, playlist, external-time, transcript cues) with FTS5 indexes; agent-native JSON output and MCP server wiring throughout.

Confidence Score: 5/5

Safe to merge; all novel commands are additive, the previous PR empty-resource bug in workflow archive is fixed, and no regressions touch existing library code.

The new CLI is self-contained under library/education/dreaming and makes no changes to shared library infrastructure. Previously flagged issues (http corpus fetch, FTS5 single-token quoting, CSV line counter, empty workflow resources) are either addressed in this rebuild or carry over from the prior review. The two remaining new findings are rounding imprecision for negative JSON output values and a misleading last-0-days human output, neither of which affects data correctness or command reliability.

library/education/dreaming/internal/cli/roadmap.go (round1/round2 helpers used across plan, roadmap, and diet JSON output) and library/education/dreaming/internal/cli/diet.go (window=0 human output).

Important Files Changed

Filename Overview
library/education/dreaming/internal/cli/roadmap.go L1-L7 fluency ladder with ETA projection; round1/round2 rounding helpers are incorrect for negative float inputs.
library/education/dreaming/internal/cli/diet.go Difficulty-trend analysis using thirds-of-window averaging; --window 0 / --window all produces a confusing 'in the last 0 days' human output.
library/education/dreaming/internal/cli/plan.go Back-calculation of daily minutes to reach a target; JSON hours_remaining field uses round1 which rounds negative values incorrectly.
library/education/dreaming/internal/cli/concordance.go FTS5/regex/tense KWIC search; single-token FTS5 special-char handling and regex-vs-tense precedence issues remain (flagged in prior review).
library/education/dreaming/internal/cli/external_import.go CSV bulk-import with adaptive rate limiting; line-counter off-by-one and asymmetric error handling on zero-duration rows were flagged in prior review.
library/education/dreaming/internal/cli/transcript_corpus.go Corpus export/import with SHA-256 content hashing and more-complete-wins merge rule; http:// acceptance in openCorpusSource flagged in prior review.
library/education/dreaming/internal/cli/next.go Roadmap-aware video picker using parameterized SQL; sorts unrated videos last correctly; no injection risk.
library/education/dreaming/internal/cli/transcript.go VTT fetch, cue caching, and transcript sync with fast-abort on auth errors and adaptive rate limiting; logic is sound.
library/education/dreaming/internal/cli/channel_workflow.go workflow archive/status commands; now correctly calls defaultSyncResources() (prior empty-slice bug fixed in this PR rebuild).
library/education/dreaming/internal/cli/dreaming_domain.go Shared domain helpers (VTT parsing, tense presets, level bands, ETA math); well-tested and logically clean.

Flowchart

%%{init: {'theme': 'neutral'}}%%
flowchart TD
    subgraph Offline["Offline-First Data Layer (SQLite)"]
        DB[(data.db)]
    end
    subgraph Sync["Data Ingestion"]
        SYNC[sync] -->|upsert resources| DB
        TSYNC[transcript sync] -->|ReplaceTranscript| DB
        TIMPORT[transcript import] -->|mergeCorpus more-complete-wins| DB
        EXIMPORT[external import CSV] -->|POST /externalTime| API[(Dreaming API)]
    end
    subgraph Read["Read Commands"]
        NEXT[next] -->|level band query| DB
        DIET[diet] -->|playlist x videos join| DB
        ROADMAP[roadmap] -->|user stats| DB
        PLAN[plan] -->|user stats| DB
        CONC[concordance] -->|FTS5 / regex| DB
        TSCRIPT[transcript] -->|GET /video| API
        TSCRIPT -->|cache cues| DB
    end
    subgraph Export["Corpus Sharing"]
        TEXPORT[transcript export] -->|gzip JSON| FILE[corpus.json.gz]
        FILE -->|transcript import| TIMPORT
    end
    SYNC -->|GET paginated| API
Loading
%%{init: {'theme': 'base', 'themeVariables': {"darkMode": true, "background": "#0d1117", "primaryColor": "#21262d", "primaryTextColor": "#e6edf3", "primaryBorderColor": "#8b949e", "lineColor": "#8b949e", "textColor": "#e6edf3", "edgeLabelBackground": "#161b22", "actorBkg": "#21262d", "actorBorder": "#8b949e", "actorTextColor": "#e6edf3", "actorLineColor": "#8b949e", "signalColor": "#8b949e", "signalTextColor": "#e6edf3", "noteBkgColor": "#373320", "noteBorderColor": "#d4a72c", "noteTextColor": "#f0e6c0", "labelBoxBkgColor": "#21262d", "labelBoxBorderColor": "#8b949e", "labelTextColor": "#e6edf3", "loopTextColor": "#e6edf3", "activationBkgColor": "#30363d", "activationBorderColor": "#8b949e"}}}%%
flowchart TD
    subgraph Offline["Offline-First Data Layer (SQLite)"]
        DB[(data.db)]
    end
    subgraph Sync["Data Ingestion"]
        SYNC[sync] -->|upsert resources| DB
        TSYNC[transcript sync] -->|ReplaceTranscript| DB
        TIMPORT[transcript import] -->|mergeCorpus more-complete-wins| DB
        EXIMPORT[external import CSV] -->|POST /externalTime| API[(Dreaming API)]
    end
    subgraph Read["Read Commands"]
        NEXT[next] -->|level band query| DB
        DIET[diet] -->|playlist x videos join| DB
        ROADMAP[roadmap] -->|user stats| DB
        PLAN[plan] -->|user stats| DB
        CONC[concordance] -->|FTS5 / regex| DB
        TSCRIPT[transcript] -->|GET /video| API
        TSCRIPT -->|cache cues| DB
    end
    subgraph Export["Corpus Sharing"]
        TEXPORT[transcript export] -->|gzip JSON| FILE[corpus.json.gz]
        FILE -->|transcript import| TIMPORT
    end
    SYNC -->|GET paginated| API
Loading

Reviews (3): Last reviewed commit: "fix(dreaming): workflow archive syncs de..." | Re-trigger Greptile

Comment thread library/education/dreaming/internal/cli/channel_workflow.go
Comment on lines +92 to +97
switch {
case flagRegex != "" || flagTense != "":
pattern := flagRegex
if flagTense != "" {
pattern = tensePresets[flagTense]
}

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.

P2 When both --tense and --regex are provided, the regex pattern is silently discarded with no warning. A user who specifies --regex "\bhab(ía|ían)\b" --tense imperfect will see only the tense preset results — their explicit regex is dropped without any feedback, which is confusing and hard to diagnose.

Suggested change
switch {
case flagRegex != "" || flagTense != "":
pattern := flagRegex
if flagTense != "" {
pattern = tensePresets[flagTense]
}
switch {
case flagRegex != "" || flagTense != "":
if flagRegex != "" && flagTense != "" {
fmt.Fprintln(cmd.ErrOrStderr(), "warning: --tense overrides --regex when both are specified")
}
pattern := flagRegex
if flagTense != "" {
pattern = tensePresets[flagTense]
}

Fix in Codex Fix in Claude Code Fix in Cursor Fix in Conductor


// openCorpusSource returns a reader for a local path or an https:// URL.
func openCorpusSource(ctx context.Context, src string) (io.ReadCloser, error) {
if strings.HasPrefix(src, "http://") || strings.HasPrefix(src, "https://") {

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.

P2 security The openCorpusSource function accepts plain http:// URLs in addition to https://, allowing corpus data to be fetched over an unencrypted channel. A network observer can inject arbitrary JSON into the response, causing crafted cue text to be merged persistently into the local SQLite store.

Suggested change
if strings.HasPrefix(src, "http://") || strings.HasPrefix(src, "https://") {
if strings.HasPrefix(src, "https://") {

Fix in Codex Fix in Claude Code Fix in Cursor Fix in Conductor

Comment on lines +190 to +192
if seconds <= 0 {
return nil, fmt.Errorf("CSV line %d: non-positive duration", line)
}

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.

P2 A row with a zero or negative duration aborts the entire import with an error, whereas a row with a missing date is silently skipped. This asymmetry means a single summary row with 0 minutes fails the whole run and discards all previously valid parsed rows.

Suggested change
if seconds <= 0 {
return nil, fmt.Errorf("CSV line %d: non-positive duration", line)
}
if seconds <= 0 {
continue // skip rows with zero/negative duration (e.g. summary/note rows)
}

Fix in Codex Fix in Claude Code Fix in Cursor Fix in Conductor

@greptile-apps

greptile-apps Bot commented Jul 5, 2026

Copy link
Copy Markdown
Contributor

Greptile Summary

This PR introduces a full-featured offline-first CLI (dreaming-pp-cli) for tracking Dreaming Spanish/French learning: catalog browsing, roadmap analytics, difficulty-progression analysis, bulk CSV external-time import, and a KWIC transcript concordance backed by a local SQLite store. It also ships an MCP bridge (dreaming-pp-mcp) so agents can drive all commands via the Model Context Protocol.

  • Novel commands (next, diet, roadmap, plan, concordance, transcript) add offline analytics powered by a SQLite mirror synced via dreaming-pp-cli sync; all commands support --agent JSON mode.
  • external import bulk-logs outside listening hours from a CSV instead of one web-form entry at a time, with --preview dry-run support.
  • Transcript corpus (transcript sync + concordance) builds a searchable FTS5 caption corpus across cached videos for keyword/regex/verb-tense KWIC search.

Confidence Score: 4/5

The new CLI module is self-contained and additive; no existing library code is modified. The two concrete issues found are limited to user-facing error messaging quality, not data integrity.

The concordance command passes single-word FTS5 queries unescaped, so a query like * or (foo hits the user with a raw SQLite error instead of a helpful message. The CSV import line counter is off by one for format errors, making malformed-CSV debugging harder than it should be. Both issues affect command usability but not the integrity of synced data or the accuracy of roadmap/diet analytics. The novel command test files are all skipped stubs, leaving SQL query paths and CSV parsing logic without any automated coverage.

library/education/dreaming/internal/cli/concordance.go (FTS5 query escaping), library/education/dreaming/internal/cli/external_import.go (CSV line counter), and the three novel-command test stubs (next_test.go, diet_test.go, external_import_test.go).

Important Files Changed

Filename Overview
library/education/dreaming/internal/cli/concordance.go KWIC concordance search; FTS5 single-word queries are passed unescaped, so special-character inputs produce cryptic SQLite errors rather than user-friendly messages.
library/education/dreaming/internal/cli/external_import.go CSV bulk-import of external time; line counter in the CSV read-error path is off by one (reports previous line number when the CSV reader itself returns an error).
library/education/dreaming/internal/cli/next.go Roadmap-aware next-video picker; SQL is correctly parameterized, unrated-last ordering is in place, test stub needs implementation.
library/education/dreaming/internal/cli/diet.go Difficulty-trend analysis using direct SQL via db.DB(); logic is sound, test stub needs implementation.
library/education/dreaming/internal/cli/dreaming_domain.go Shared domain helpers (VTT parsing, roadmap levels, tense presets); well-tested in dreaming_domain_logic_test.go.
library/education/dreaming/internal/cli/roadmap.go L1-L7 ladder with ETA projection; rounding helpers look correct, related-language scaling is straightforward.
library/education/dreaming/internal/store/transcripts.go FTS5 transcript store with write-mutex-guarded ReplaceTranscript; SQL is parameterized, schema is created lazily via EnsureTranscriptSchema.
library/education/dreaming/internal/cli/download.go ffmpeg/yt-dlp execution uses exec.CommandContext with args as a slice (no shell expansion); safe. Verify-mode guard prevents network calls during testing.
library/education/dreaming/internal/store/store.go Generated SQLite store with migration locking, WAL mode, backfill columns, and FTS5 content schema; schema versioning logic is robust.
library/education/dreaming/internal/cli/dreaming_data.go Shared data helpers for user stats, daily input merging, and streak calculation; correctly handles the watch_time float64 storage quirk with NullFloat64 scan.

Sequence Diagram

%%{init: {'theme': 'neutral'}}%%
sequenceDiagram
    participant User
    participant CLI as dreaming-pp-cli
    participant Store as SQLite Store
    participant API as Dreaming API

    Note over CLI,Store: Offline-first flow for next, diet, roadmap

    User->>CLI: dreaming-pp-cli next --limit 5
    CLI->>Store: Open local DB (WAL mode)
    Store-->>CLI: Store handle
    CLI->>Store: "SELECT COUNT(*) FROM videos"
    alt catalog empty
        CLI-->>User: Error: run sync first
    else catalog populated
        CLI->>Store: loadUser() from user table
        alt user row missing
            CLI->>API: GET /user (live fetch, best-effort)
            API-->>CLI: "{user:{...}}"
            CLI->>Store: UpsertUser()
        end
        Store-->>CLI: "dreamingUser{TotalHours, ...}"
        CLI->>CLI: levelForHours() then videoLevelBands()
        CLI->>Store: SELECT videos WHERE level IN (?) ORDER BY difficulty ASC
        Store-->>CLI: []nextVideo
        CLI-->>User: Table / JSON output
    end

    Note over CLI,Store: Concordance search flow

    User->>CLI: dreaming-pp-cli concordance entonces
    CLI->>Store: TranscriptStats()
    alt corpus empty
        CLI-->>User: Error: run transcript sync first
    else corpus present
        CLI->>Store: SearchTranscriptFTS(ftsQuery(entonces), filter)
        Store-->>CLI: []ConcordanceHit
        CLI-->>User: TIMESTAMP / LEVEL / GUIDE / VIDEO / CONTEXT / URL
    end

    Note over CLI,API: external import bulk flow

    User->>CLI: dreaming-pp-cli external import backlog.csv
    CLI->>CLI: parseExternalCSV(path)
    loop each row
        CLI->>API: POST /externalTime (rate-limited)
        API-->>CLI: 200 OK / 429 rate-limited
    end
    CLI-->>User: Imported N/M entries (K failed)
Loading
%%{init: {'theme': 'base', 'themeVariables': {"darkMode": true, "background": "#0d1117", "primaryColor": "#21262d", "primaryTextColor": "#e6edf3", "primaryBorderColor": "#8b949e", "lineColor": "#8b949e", "textColor": "#e6edf3", "edgeLabelBackground": "#161b22", "actorBkg": "#21262d", "actorBorder": "#8b949e", "actorTextColor": "#e6edf3", "actorLineColor": "#8b949e", "signalColor": "#8b949e", "signalTextColor": "#e6edf3", "noteBkgColor": "#373320", "noteBorderColor": "#d4a72c", "noteTextColor": "#f0e6c0", "labelBoxBkgColor": "#21262d", "labelBoxBorderColor": "#8b949e", "labelTextColor": "#e6edf3", "loopTextColor": "#e6edf3", "activationBkgColor": "#30363d", "activationBorderColor": "#8b949e"}}}%%
sequenceDiagram
    participant User
    participant CLI as dreaming-pp-cli
    participant Store as SQLite Store
    participant API as Dreaming API

    Note over CLI,Store: Offline-first flow for next, diet, roadmap

    User->>CLI: dreaming-pp-cli next --limit 5
    CLI->>Store: Open local DB (WAL mode)
    Store-->>CLI: Store handle
    CLI->>Store: "SELECT COUNT(*) FROM videos"
    alt catalog empty
        CLI-->>User: Error: run sync first
    else catalog populated
        CLI->>Store: loadUser() from user table
        alt user row missing
            CLI->>API: GET /user (live fetch, best-effort)
            API-->>CLI: "{user:{...}}"
            CLI->>Store: UpsertUser()
        end
        Store-->>CLI: "dreamingUser{TotalHours, ...}"
        CLI->>CLI: levelForHours() then videoLevelBands()
        CLI->>Store: SELECT videos WHERE level IN (?) ORDER BY difficulty ASC
        Store-->>CLI: []nextVideo
        CLI-->>User: Table / JSON output
    end

    Note over CLI,Store: Concordance search flow

    User->>CLI: dreaming-pp-cli concordance entonces
    CLI->>Store: TranscriptStats()
    alt corpus empty
        CLI-->>User: Error: run transcript sync first
    else corpus present
        CLI->>Store: SearchTranscriptFTS(ftsQuery(entonces), filter)
        Store-->>CLI: []ConcordanceHit
        CLI-->>User: TIMESTAMP / LEVEL / GUIDE / VIDEO / CONTEXT / URL
    end

    Note over CLI,API: external import bulk flow

    User->>CLI: dreaming-pp-cli external import backlog.csv
    CLI->>CLI: parseExternalCSV(path)
    loop each row
        CLI->>API: POST /externalTime (rate-limited)
        API-->>CLI: 200 OK / 429 rate-limited
    end
    CLI-->>User: Imported N/M entries (K failed)
Loading

Fix All in Codex Fix All in Claude Code Fix All in Cursor Fix All in Conductor

Reviews (2): Last reviewed commit: "fix(dreaming): complete manuscripts for ..." | Re-trigger Greptile

Comment on lines +159 to +168
func ftsQuery(q string) string {
q = strings.TrimSpace(q)
if q == "" {
return q
}
if strings.ContainsAny(q, " \t") {
return `"` + strings.ReplaceAll(q, `"`, `""`) + `"`
}
return q
}

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.

P2 FTS5 special characters in single-word queries produce cryptic SQLite errors. A user query like *, (foo, or -bar is passed directly to FTS5 as an unquoted token, which the engine rejects with a raw parse error (fts5: syntax error near "*") rather than a helpful message. Multi-word inputs are correctly phrase-quoted, but single-word inputs bypass all escaping. Wrapping single tokens in double quotes the same way multi-word phrases are handled fixes this.

Suggested change
func ftsQuery(q string) string {
q = strings.TrimSpace(q)
if q == "" {
return q
}
if strings.ContainsAny(q, " \t") {
return `"` + strings.ReplaceAll(q, `"`, `""`) + `"`
}
return q
}
func ftsQuery(q string) string {
q = strings.TrimSpace(q)
if q == "" {
return q
}
// Always phrase-quote: wrapping in double-quotes makes FTS5 treat the
// input as a literal phrase regardless of whether it is a single word or
// multiple words. This prevents FTS5 special characters (*, -, +, (, ),
// ^, AND, OR, NOT, NEAR) from being interpreted as operators and causing
// a cryptic "fts5: syntax error" instead of a user-friendly no-results.
return `"` + strings.ReplaceAll(q, `"`, `""`) + `"`
}

Fix in Codex Fix in Claude Code Fix in Cursor Fix in Conductor

Comment on lines +159 to +168
line := 1
for {
rec, err := r.Read()
if err == io.EOF {
break
}
if err != nil {
return nil, fmt.Errorf("CSV line %d: %w", line, err)
}
line++

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.

P2 The line counter is incremented only after a successful r.Read(), so when the CSV reader itself returns an error (malformed quoting, unexpected field count, etc.) the error message cites the previous row's number. For example, a malformed first data row (file line 2) is reported as "CSV line 1". Moving the increment before the error check fixes the off-by-one.

Suggested change
line := 1
for {
rec, err := r.Read()
if err == io.EOF {
break
}
if err != nil {
return nil, fmt.Errorf("CSV line %d: %w", line, err)
}
line++
line := 1
for {
line++
rec, err := r.Read()
if err == io.EOF {
break
}
if err != nil {
return nil, fmt.Errorf("CSV line %d: %w", line, err)
}

Fix in Codex Fix in Claude Code Fix in Cursor Fix in Conductor

Comment on lines +8 to +9
func TestNovelNextCommandTODO(t *testing.T) {
t.Skip("TODO: implement table-driven tests for next")

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.

P2 Novel command tests are all empty stubs. The three most complex novel commands — next, diet, and external import — each ship with a test file containing only t.Skip("TODO"). The dreaming_domain_logic_test.go covers shared helpers well, but the command-level SQL paths (level-band query, difficulty ordering, trend analysis, CSV row parsing/validation) have no coverage. A parseExternalCSV unit test in particular would have caught the line-counter off-by-one noted separately. This pattern also appears in diet_test.go and external_import_test.go.

Note: If this suggestion doesn't match your team's coding style, reply to this and let me know. I'll remember it for next time!

Fix in Codex Fix in Claude Code Fix in Cursor Fix in Conductor

paulbockewitz added a commit to paulbockewitz/printing-press-library that referenced this pull request Jul 5, 2026
…hardcoded empty list

resources was []string{}, so every archive run iterated nothing and
reported 'Archived 0 items across 0 resources'. Fall back to
defaultSyncResources() exactly like the sync command. Verified live:
archive now syncs 4 resources.

Addresses greptile review on mvanhorn#1442.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
…hardcoded empty list

resources was []string{}, so every archive run iterated nothing and
reported 'Archived 0 items across 0 resources'. Fall back to
defaultSyncResources() exactly like the sync command. Verified live:
archive now syncs 4 resources.

Addresses greptile review on mvanhorn#1442.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
@github-actions

github-actions Bot commented Jul 5, 2026

Copy link
Copy Markdown
Contributor

@greptileai review

Auto-nudge from greptile-policy-gate.yml because no Greptile Review check appeared for 5cb5ac4ab5400aca562c2e706c8f5f9c0fa37418 after 184s. This usually means the PR is over Greptile auto-review size cap; manual triggers bypass it.

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