Skip to content

Use compact transcript citations and DeepSeek text analysis - #178

Draft
devhims wants to merge 18 commits into
mainfrom
feat/compact-transcript-citations
Draft

devhims wants to merge 18 commits into
mainfrom
feat/compact-transcript-citations

Conversation

@devhims

@devhims devhims commented Oct 10, 2026 •

Copy link
Copy Markdown
Owner

Problem / Motivation

Transcript citations point to broad windows, and repeated caption metadata makes context expensive. Strict claim limits and measurement-only facts can also truncate explanations or distort software versions.

What changed

Both transcript paths use flat numeric IDs and text. Citations resolve through transcript version and segment ID. Claims have no character cap; source captions retain a 16,000-character safety bound.

Timestamp tools return ten neighboring segments per side. Empty lookups provide citable coverage status. Spoken explanations require timed transcript citations; separate context blocks can cite metadata. The application computes whether a requested time exceeds the reported video duration.

Versions and dates retain complete source values, including build metadata, without dropping measurements. Overview repairs use application-held topic indices, without requiring repeated outline wording. Prose and table citation rules are visible in the schema.

flowchart LR
  Store[Versioned transcript, retained] --> Old[Before: copied lookup captions]
  Store --> Refs[After: version and segment references]
  Refs --> Link[Resolve original caption and timed link]
Loading

The original transcript remains the citation source. Search preserves phrase support and returns original captions. It fetches further candidates until twenty distinct matches are found or the index is exhausted. Transcript reads are cached across search pages. Caption indexes upgrade locally. Older indexes rebuild in batches of four passive reads; pending work is reported. Source records remain intact.

Deployment

This PR intentionally changes production text roles and final answers to DeepSeek with reasoning disabled. GLM remains for visuals. The next deployment applies that configuration.

Tests

Build, 1,675 unit tests and 397 Workers integration tests passed. Earlier live mixed-source and beyond-end answers passed. Remain draft: broader semantic citation and focused-answer issues remain documented in validation results. Nothing deployed.

@vercel

vercel Bot commented Oct 10, 2026 •

Copy link
Copy Markdown

The latest updates on your projects. Learn more about Vercel for GitHub.

Project Deployment Actions Updated
video2ctx-web Ready Ready Preview Oct 10, 2026 4:46pm UTC

devhims commented Oct 10, 2026

Copy link
Copy Markdown
Owner Author

Reviewed head 82b37a71d4ad1b3cda8a816eef794f17ea5d3ebe. One introduced regression:

[P2] Keep session-packet identity separate from stable segment identity

The new versioned segment IDs all begin with evidence:<assetVersion>:, but savePacket still extracts that prefix as its packet-content deduplication key. Consequently, every non-session: transcript retrieval or analysis for the same asset uses the same INSERT OR REPLACE key. A second timestamp lookup or focused analysis replaces the first saved packet, even when its excerpts and findings differ.

I reproduced this with the source-extracted versionEvidencePacket, savePacket, and evidenceForCitations methods, using an in-memory SQL mock and deterministic hash stub:

  • Base: save packets selecting segments 0 and 5 → two packets retained; segment 0 still resolves.
  • This head: same sequence → only the segment-5 packet remains; the segment-0 citation resolves to no session packet.

The runtime calls both methods in its normal persistence path. This loses earlier saved analysis/findings, and applyMemoryDelta then skips a finding whose citation was overwritten. Existing displayed answers and run audit records remain intact.

Please retain the stable segment citation IDs, but derive the session packet key independently from packet content or another distinct packet identity. A regression test should save two disjoint timestamp/analysis packets for one asset and verify both citations, findings, and evidence-backed memory remain available; also cover a full read followed by a narrow lookup.

Checks: reviewed the changed retrieval, model projection, finalization, response, and persistence paths. Five source-extracted timestamp selection checks passed. GitHub currently reports nine successful checks and one skipped deployment check. The reproduction above is mocked code validation, not a Workers integration or live model run; I couldn't rerun the local suite because shell execution stalled. The draft's documented live-model citation/coverage issues were not independently rerun.

devhims commented Oct 10, 2026

Copy link
Copy Markdown
Owner Author

Re-reviewed head b4a79d560073e67b5df5707a13fc07bccaafbfb5, including both follow-up commits.

The earlier packet-overwrite P2 is fixed. Independent source replay now preserves both disjoint retrieval/analysis packets, their findings, and both evidence-backed memories. Full-read → narrow lookup, same-packet replay, cross-run identity, deletion cleanup, and the ten-neighbor defaults also behaved correctly.

One new regression remains:

[P2] Deduplicate searchable captions before applying the result limit

Saving and indexing each distinct packet ID also creates another FTS copy of its captions, because indexPacket scopes replacement to the packet owner. Ordinary tool reads across different runs therefore accumulate rows with identical stable excerpt IDs. The search query limits results to 20 rows before searchEvidence deduplicates those IDs, so repeated passages can fill the entire candidate list and hide other matching passages.

Reproduction with the actual storage/search source and Node SQLite FTS5:

  • A six-caption transcript has matching text at 0s and 5s, with the shorter 0s caption ranking higher.
  • Read the 0s caption in 25 distinct runs, then read the 5s caption; search for their shared term.
  • Previous-head storage finds both passage times. This head returns only two copies of 0s; the distinct 5s match is absent. Its raw transcript index entry cannot rescue it because that entry competes under the same limit.

Please retain the distinct packets and findings, but deduplicate search candidates before the limit or maintain one searchable entry per stable excerpt. A regression should repeat an ordinary tool read across runs, then verify another lower-ranked matching passage remains discoverable. Saved session: reads already skip packet indexing; the affected path is run/tool-call packets.

Validation: source replay used mocked provider, R2, SDK-history, and billing boundaries, with real SQLite and repository schemas. Separately, Verify #400 passed; its logs confirm 1,616 unit tests and all 45 session-evidence integration tests, including both new packet-retention regressions. No live model or production run was performed; the draft's documented semantic citation/coverage limitations remain outside this re-review.

devhims commented Oct 10, 2026

Copy link
Copy Markdown
Owner Author

Re-reviewed head f35978eb1a2ad35f74ba08a31d0ebfd299a281c8, covering the original-asset citation refactor and search deduplication follow-up. No new actionable findings in these two commits.

The search-crowding P2 is fixed. Independent replay of 25 cross-run reads followed by a lower-ranked matching passage now returns both 0s and 5s exactly once, with clean indexes and seeded legacy duplicate rows. The previous head still reproduces the missing 5s result. All 26 lookup records remain available, and new canonical captions create no packet-owned FTS copies.

The earlier packet-overwrite fix also remains intact. Additional checks passed for:

  • Reference-only lookup storage with separately retained analysis findings; full-read → narrow lookup, packet replay, and evidence-backed memory.
  • Citation resolution with no lookup packet, exact original whitespace and long captions, and rejection of empty/out-of-range segment IDs.
  • Old/new version isolation after refresh, superseded warnings, legacy chunk search, and selective deletion of citations and dependent memory.
  • Missing original blobs producing no invented canonical text, legacy excerpts remaining readable, and deletion fencing an in-flight hydration.

I also reviewed the asynchronous finalization/recovery changes: run state and evidence generation are rechecked after citation hydration, before the synchronous answer/memory commit.

Validation: isolated replay of the repository source with real Node SQLite FTS5 and mocked provider, R2, SDK-history, and billing boundaries. I did not rerun the full local suite. Verify #402 passed; its logs confirm 1,616 unit tests and 359 Workers integration tests, including 49 session-evidence, 83 runtime, 25 memory-updater, and 85 catalog tests. No live model or production run was performed. The draft's documented live summary/citation-quality limitations remain outside this review.

devhims commented Oct 10, 2026

Copy link
Copy Markdown
Owner Author

Re-reviewed head 3da175f0878f3c232c412a02dc1c054687bcbcc0, covering both commits after f35978e. One edge-case regression remains:

[P2] Exclude omitted captions from search candidates before the limit

The new exact-segment size filter makes captions over 16,000 characters unavailable as evidence, but transcript indexing still uses legacy chunk mode. Those captions therefore retain searchable 2,000-character chunks with distinct IDs. They can fill the 20-candidate limit, after which every selected candidate resolves to an omitted segment and is discarded. The search returns no packets, including no oversized-caption warning, even when an ordinary matching caption is available.

Reproduced using the actual storage/search source and Node SQLite FTS5:

  • Store a two-caption transcript: a 56,000-character caption ('needle '.repeat(8000)) followed by 'needle ' + 'padding '.repeat(80).
  • Search for needle: all 20 candidates are chunks of the oversized caption; the result is { packets: [] }.
  • Remove only those unresolvable candidate rows in the test database: the normal caption at 1s is returned.
  • The prior head returned the oversized caption. Chunk crowding already existed; the new regression is that the size filter turns those indexed matches into an empty search result.

Please exclude unresolvable segments before applying the candidate limit, or continue collecting candidates after skipped ones, while preserving historical chunk offsets and the source-size cap. Cover both newly indexed transcripts and existing legacy index rows.

Other independent replay checks passed: passive citation reads and shared active/passive reads; targeted deserialization and memory validation; current/earlier-turn evidence reuse; storage-error fallback with 0 and 50 input warnings; unknown-only research citation rejection; cancellation, generation fencing, and duplicate-finalization protection. The earlier packet-retention and repeated-read search fixes remain intact.

Validation used source-extracted code, real SQLite, and mocked provider, R2, SDK-history, and billing boundaries. The full local suite was not rerun. Verify #404 passed; its platform logs confirm 1,620 unit tests and 369 Workers integration tests. No live model or production run was performed; the draft's documented semantic citation/coverage limitations remain outside this review.

@devhims devhims changed the title Use compact transcript IDs and timestamp context for citations Use compact transcript citations and DeepSeek text analysis Oct 10, 2026

devhims commented Oct 10, 2026

Copy link
Copy Markdown
Owner Author

Re-reviewed head 1bcef696008e8897dc0e095086e2c9d6c792ec13, covering the three commits after 3da175f.

The oversized-caption search P2 is fixed. Independent SQLite replay reproduces the empty result on the previous head and returns the usable matching caption on this head. An actual old-to-new index migration also passes, retains original packets/assets/blobs and historical citations/memory, and stays stable after reopening.

One new regression remains:

[P2] Validate literal boundaries in the original source, not only the cropped quote

The new literal validation checks that the quote is a source substring, but checks the version/date boundaries only inside that model-supplied quote. Cropping the quote can therefore turn part of a larger source literal into an apparently supported complete value.

Independent base/head analyst reproduction:

  • Source: Use Bootstrap 5.2.3.
  • Claim: Use Bootstrap 5.2.
  • Literal: value "5.2", quote "Use Bootstrap 5.2"
  • Also supply the same quote as a quantity with value 5.2, unit/basis null, and uncertainty null.
  • Previous head marks the finding unverified and adds a warning.
  • This head accepts the shortened literal, discards the duplicate numerical encoding, and returns uncertainty null with no warning.

The same cropped-quote bypass accepts year 201 from 2011, or suffix 2.3 from 5.2.3. Please check boundaries at the quote's matched location in the original supporting passage, so quote edges cannot manufacture token boundaries. Add regressions for both leading/trailing crops and retain valid complete literals and real measurements.

Other checks passed: earlier packet-retention/search-deduplication cases; the 16,000/16,001-character boundary and empty-segment identity; persisted untimed lookup status; mixed metadata/transcript declared and inline citation scopes; video-duration bounds; frozen-outline overview repairs; and the intentional DeepSeek text/GLM visual configuration.

Validation used extracted repository source, real Zod and SQLite, with mocked generation, provider, storage and SDK boundaries. The full local suite was not rerun. Verify #407 passed; its logs confirm 1,649 unit tests and 372 Workers integration tests, including 56 session-evidence tests. No live model or production run was performed. The documented focused React warning and broader semantic citation/coverage limitations remain outside this review.

…ptions

Unreadable transcripts are recorded in session_search_index_failures and
sorted behind untried versions, so missing blobs cannot hold every
four-slot indexing batch. Window search hits now return the shortest
caption run covering the query terms instead of all ten captions.

devhims commented Oct 10, 2026

Copy link
Copy Markdown
Owner Author

Re-reviewed head ff4a5cfb7942872d56e4f2c1c26681f300a47a2f, covering 6f9a348 and ff4a5cf. Two new search regressions are reproducible:

[P2] Deduplicate resolved matches before enforcing the search limit

The new windows have different starting IDs but can resolve to the same matching caption. The SQL query limits those starting IDs to 20, then covering-span reduction and seen discard duplicate captions without collecting more candidates.

Base/head reproduction: save seven 15-caption transcripts, each with alpha beta at caption 7 and filler elsewhere, plus an eighth transcript containing one longer caption, 'alpha beta ' + 'filler '.repeat(80). Search alpha beta. The previous head returns all eight videos. This head selects 20 candidates but returns only seven videos; overlapping windows crowd out the eighth, with pendingTranscripts: 0. Please refill after resolved-caption deduplication or enforce the limit on distinct resolved matches. Cover overlapping windows as well as repeated packet rows.

[P2] Preserve all FTS query terms when trimming a window

The JavaScript tokenizer retains underscores, while the default FTS5 tokenizer splits them. coveringSpan silently drops terms it cannot find using its own tokenizer.

Minimal base/head reproduction: captions ['foo_bar', 'foo'], query foo bar. Previously the result is the matching caption foo_bar. On this head, the overlapping window wins the rank comparison, trimming discards bar, and the result contains only foo. The matching evidence is lost. Use compatible tokenization, or retain the complete candidate when coverage of every FTS query term cannot be established.

The existing cropped-literal P2 also remains: replay still accepts 5.2 from 5.2.3, 201 from 2011, and 2.3 from 5.2.3 without warnings.

Other checks passed: actual format-2-to-3 migration with zero blob reads and unchanged source/packet/memory records; exact three-caption results across a window boundary with one blob read; four-read passive repair batches; failure rotation across reopening, recovery and unrelated-asset deferral; deletion fencing; empty/oversized-caption gaps; and previous packet-retention/search-deduplication regressions.

One migration scale caveat: format-2 conversion still rewrites every asset synchronously during construction. A local SQLite benchmark with 100 transcripts × 1,000 captions took about 21.6 seconds inside one transaction, issuing 120,632 SQL calls with zero blob reads. That is a local scaling observation, not measured Workers latency; bounding this conversion would avoid an unbounded first-access pause.

Validation used extracted repository source, real Zod and Node SQLite FTS5, with mocked provider, R2, SDK and generation boundaries. The full local suite was not rerun. Verify #409 passed; platform-check logs confirm 1,649 unit tests and 377 Workers integration tests, including 61 session-evidence tests. No live model, production run or deployment was performed.

Over-fetch FTS candidates and stop at 20 distinct results after
trimming, so overlapping windows that resolve to the same captions no
longer crowd other matches out of the limit. Window trimming now splits
words like the unicode61 index (underscore is a separator) and returns
the whole window whenever it cannot account for every query term.

devhims commented Oct 10, 2026

Copy link
Copy Markdown
Owner Author

Re-reviewed head f86b3941e302cdd2308fbaad8d544c465d2db334, covering 76660bb and f86b394 after ff4a5cf.

The overlapping-window crowding reproduction is fixed: independent base/head replay returns seven videos before and all eight now. The original foo bar query also correctly returns foo_bar. Two issues remain in this delta:

[P2] Preserve quoted-token phrase semantics when trimming

searchTokens still retains underscores, and each token is quoted in the FTS query. SQLite therefore interprets "foo_bar" as the adjacent phrase foo bar. The new folded tokenizer turns it into independent words, so a trimmed caption can contain every word while losing the actual phrase match.

Minimal end-to-end base/head reproduction:

  • Captions: ['foo x bar extra', 'foo_bar']
  • Query: foo_bar extra
  • Only the combined window satisfies the FTS query.
  • Previous head returns both original captions.
  • This head returns only foo x bar extra, discarding the caption containing the required phrase.

Please make candidate matching and trimming use the same token/phrase constraints, or retain the full candidate when that equivalence cannot be established. This is a remaining tokenizer-consistency case despite the original underscore example passing.

[P2] Cache transcript read results across search pages

The new cache tracks individual citation IDs, but each new page can request different IDs from the same transcript. read() removes its in-flight entry after completion, so these become fresh serial reads of the same blob.

Independent reproduction: index one transcript containing 1,000 one-second needle captions, remove its blob, then search needle. The previous head performs one blob read; this head performs 50 reads of that identical missing blob and 51 candidate queries before returning empty. Healthy overlap also repeats reads: the 20-video tail-overlap case performs 74 blob reads. With real storage latency, this amplification can consume the foreground search budget before a lower-ranked usable match is reached.

Please cache the version's read result, including an unavailable result, for the search operation while retaining deletion fencing and pagination. Add a per-version read-count assertion, rather than only checking that citation IDs are not requested twice.

The cropped-literal P2 also remains unchanged: current-head replay still accepts 5.2 from 5.2.3, 201 from 2011, and 2.3 from 5.2.3 with no warnings.

Other checks passed: 18/19/20-video refill and the twenty-result cap with 21/25/45 videos; continuation past unavailable-only pages; unique resolved IDs; whole-session and selective deletion during a later page; cross-boundary exact captions; empty/oversized gaps; packet retention, version isolation, evidence-backed memory, and in-flight deletion fencing.

Validation used extracted repository source, real Zod and Node SQLite FTS5, with mocked provider, R2, SDK, billing and generation boundaries. The full local suite was not rerun. Verify #411 passed for this exact head; platform-check logs confirm 1,649 unit tests and 385 Workers integration tests, including 69 session-evidence tests. No live model, production run, code change or deployment was performed. The draft's broader semantic citation/coverage limitations remain outside this review.

Search runs one ranked query capped at 200 candidates and resolves it in
batches of twenty, instead of re-running the FTS query per page until
exhaustion. Each transcript is read at most once per search through a
shared read cache, with bounded concurrency. An unreadable blob is
skipped instead of failing the search; if it filled the candidate limit
its rows are excluded and the query reruns, at most four times.

Indexing and search now report unreadable transcripts as
unavailableTranscripts, separately from pendingTranscripts, so the model
is no longer told to search again for sources that cannot be read.
Search also checks cancellation between batches.
Window trimming now asks SQLite where each query term matched, using
FTS5 highlight() on the window row, and maps those positions back to
captions. The returned run is the shortest that contains a complete
instance of every term, so Unicode punctuation, non-English text and
phrases that cross caption boundaries follow the index tokenizer
instead of falling back to whole ten-caption windows.

A one-word query containing an underscore is a phrase and now searches
windows, so cross-caption matches are found. Query tokens keep
combining marks, so Devanagari words are not split at vowel signs.

The per-search read cache remembers failed reads for the whole search
but retains at most four successful transcripts; evicted transcripts
may be reread. Search still continues until twenty distinct matches or
index exhaustion.

devhims commented Oct 10, 2026

Copy link
Copy Markdown
Owner Author

Re-reviewed head e9ab994def9c9d776406331381bf98d51be6deb1, covering 4132261, 5ced66b, and e9ab994 after f86b394.

The three previously reported reproductions are fixed:

  • Cropped 5.2 from 5.2.3, 201 from 2011, and suffix 2.3 now fail source-boundary validation. The analyst also retains the unverified warning when the model duplicates the bad literal as a unitless quantity.
  • Query foo_bar extra now returns both foo x bar extra and foo_bar, preserving the required phrase. Cross-caption phrases, Hindi, diacritics, and Unicode punctuation also passed independent replay.
  • Searching 1,000 captions from one missing transcript now performs one blob read and two candidate queries, versus 50 reads and 51 queries at f86b394, and reports the unavailable source. Searches continue past multiple unavailable owners and full stale-candidate pages to healthy matches.

One related literal-validation gap remains:

[P2] Reject build-metadata fragments before treating a version as verified

The source-position boundary regex still treats + as a boundary. A build suffix can therefore become a different supposedly supported version:

  • Source: Use version 1.2.3+7.
  • Model claim: Use version 7.
  • Literal: kind version, value "7", quote "7".
  • Also provide quantity 7, unit/basis null, quote "7", and uncertainty null.

Actual analyst replay on this head retains literal 7, removes its unitless quantity, and returns uncertainty: null with no warning. The full PR base 39c05e6 flags the same numeric claim as unverified with UNCERTAINTY_MISSING. This gap was already present at f86b394; it is a remaining issue introduced by this PR, not a new regression in these three follow-up commits. Cropping 1.2.3+build.7 to 1.2.3 also passes the current boundary check.

Please include build-metadata separators in version-token boundary validation and cover both prefix and suffix crops, including the unitless-quantity path. The complete literal 1.2.3+7 should remain valid; that positive control passes now.

Other checks passed: 18/19/20-result refill and the twenty-result cap with 21/25/45 videos; shared repair/resolution reads; failed reads surviving cache eviction; four-read concurrency; storage-error isolation; cancellation; selective and whole-session deletion during later resolution batches; packet retention, version isolation, exact captions, and evidence-backed memory. The successful-read cache is intentionally LRU-bounded to four, so evicted healthy transcripts can still be reread; only failed reads are retained for the entire operation.

Validation used actual repository source with real Zod and Node SQLite FTS5, mocking generation, provider, R2, SDK, and billing boundaries. The full local suite was not rerun. Verify #414 passed for this exact head; logs confirm 1,663 unit tests and 397 Workers integration tests, including 81 session-evidence tests. No live model, production run, code change, or deployment was performed. The draft's broader semantic citation/coverage limitations remain outside this review.

devhims commented Oct 10, 2026

Copy link
Copy Markdown
Owner Author

Re-reviewed head 9a201f0b3064c65bf7455eff2f7d55eba443b950 after e9ab994.

The previous + boundary reproduction is fixed. Independent base/head replay rejects both the cropped core and build suffix, and the analyst retains the unverified warning when either is duplicated as a unitless quantity. Complete numeric/named builds and prerelease-plus-build versions still pass.

[P2] Reject dotted named continuations before accepting a version prefix

The right-hand boundary still excludes only a dot followed by a digit. A dot followed by a named metadata component is therefore treated as a version boundary:

  • Source: Use version 1.2.3+build.alpha.
  • Model claim: Use version 1.2.3+build.
  • Literal: kind version, value and quote "1.2.3+build".
  • Duplicated quantity: value 1.2, unit/basis null, same quote, uncertainty null.

Actual analyst replay retains this incomplete literal, discards the unitless quantity, and returns uncertainty: null with no warnings or diagnostic issues. The full PR base 39c05e6 marks that numeric claim unverified. This also reproduces at e9ab994, so it is a remaining PR-introduced gap. The same issue accepts 1.2.3-alpha from 1.2.3-alpha.beta+build.7.

Please include dotted named version components in continuation validation while allowing ordinary sentence-ending periods. Cover both direct validation and the duplicated-quantity analyst path. The complete strings 1.2.3+build.alpha and 1.2.3-alpha.beta+build.7 should remain valid.

Other independent checks passed: repeated quote/value occurrences, fullwidth normalization, existing numeric version crops, date boundaries, complete date literals, unit-bearing measurement retention, mixed invalid-literal/valid-measurement salvage, and measurement conversion/unit rejection.

Validation used extracted repository source with real Zod and mocked generation, SDK and billing boundaries. The full local suite was not rerun. Verify #415 passed for this exact head; logs confirm 77 grounding tests, 1,675 unit tests and 397 Workers integration tests. No repository code changes, live-model test, production run or deployment. The draft's broader semantic citation/coverage limitations remain open.

This branch was successfully deployed

1 active deployment
Preview — 9a201f0b Deployed Oct 10, 2026 by vercel[bot]
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