Context
#14033's first vertical slice (tickets only; PR/Discussion follow). TicketSource.extract() writes ONE whole-file chunk per issue-*.md (body + all comments combined). A growing multi-comment ticket trends toward the embedding cap → dropped / blind-byte-split (the #13999 metadata-without-vector class on the no-hard-skip path). Per-element chunks keep every element small.
The Fix
- Pure
splitTicketArchiveMarkdown(content) → [{kind:'body'|'comment', ordinal, content}]. Boundaries (V-B-A'd across 711 archive files — 709 carry ## Timeline): frontmatter + title + body until ## Timeline; each comment delimited by `^### @ - # TicketSource per-element chunking (body + each comment as separate chunks) — #14033 tickets vertical
Context
#14033's first vertical slice (tickets only; PR/Discussion follow). TicketSource.extract() writes ONE whole-file chunk per issue-*.md (body + all comments combined). A growing multi-comment ticket trends toward the embedding cap → dropped / blind-byte-split (the #13999 metadata-without-vector class on the no-hard-skip path). Per-element chunks keep every element small.
The Fix
- Pure
splitTicketArchiveMarkdown(content) → [{kind:'body'|'comment', ordinal, content}]. Boundaries (V-B-A'd across 711 archive files — 709 carry ## Timeline): frontmatter + title + body until ## Timeline; each comment delimited by (comment bodies may contain ##/###, so split ONLY on the ## Timeline boundary + the author-timestamp delimiter, never on all headings). No ## Timeline (2/711) → body-only.
- Wire
TicketSource.extract() to emit per-element chunks: issue-<id>#body + issue-<id>#comment-<n> (stable names → idempotent re-ingestion), preserving type/kind/source per element + a per-element hash.
Acceptance Criteria
Out of Scope
PullRequestSource (review-cycles) + DiscussionSource (threads) — separate #14033 follow-up slices (different formats).
Contract Ledger Matrix
| Consumed surface |
Field |
Change |
Consumer impact |
Fallback / semantics |
TicketSource.extract() emitted KB chunks |
name |
per-element issue-<id>#body / #comment-<n> (was issue-<id>) |
KB re-ingestion: one ticket → N element chunks. name is descriptive metadata + the embedding-input prefix — V-B-A'd NOT a lookup/join key (DatabaseService/VectorService store it; nothing queries by it), so retrieval granularity improves with no name-keyed breakage. |
stable per-element names → idempotent; old whole-file chunk's hash drops on re-ingest, new per-element hashes added |
| same |
hash |
per-element content hash (was whole-file) |
re-ingestion replaces the one whole-file chunk with N element chunks |
content-fingerprint per element |
Related
- #14033 (parent — tickets vertical; PR/Discussion follow); #14039 (v13.1 epic); #14000 (over-cap drop class this complements). Design provenance: #14033 issuecomment-4806524346.
Authored-by: @neo-opus-vega (Vega, Claude Opus 4.8)
Context
#14033's first vertical slice (tickets only; PR/Discussion follow).
TicketSource.extract()writes ONE whole-file chunk perissue-*.md(body + all comments combined). A growing multi-comment ticket trends toward the embedding cap → dropped / blind-byte-split (the #13999 metadata-without-vector class on the no-hard-skip path). Per-element chunks keep every element small.The Fix
splitTicketArchiveMarkdown(content)→[{kind:'body'|'comment', ordinal, content}]. Boundaries (V-B-A'd across 711 archive files — 709 carry## Timeline): frontmatter + title + body until## Timeline; each comment delimited by `^### @Context
#14033's first vertical slice (tickets only; PR/Discussion follow).
TicketSource.extract()writes ONE whole-file chunk perissue-*.md(body + all comments combined). A growing multi-comment ticket trends toward the embedding cap → dropped / blind-byte-split (the #13999 metadata-without-vector class on the no-hard-skip path). Per-element chunks keep every element small.The Fix
splitTicketArchiveMarkdown(content)→[{kind:'body'|'comment', ordinal, content}]. Boundaries (V-B-A'd across 711 archive files — 709 carry## Timeline): frontmatter + title + body until## Timeline; each comment delimited by (comment bodies may contain##/###, so split ONLY on the## Timelineboundary + the author-timestamp delimiter, never on all headings). No## Timeline(2/711) → body-only.TicketSource.extract()to emit per-element chunks:issue-<id>#body+issue-<id>#comment-<n>(stable names → idempotent re-ingestion), preservingtype/kind/sourceper element + a per-element hash.Acceptance Criteria
## Timeline→ correct elements.extract()emits per-element chunks with stableissue-<id>#body/#comment-<n>names;type:'ticket'+sourcepreserved per element.extract()per-element emission.Out of Scope
PullRequestSource(review-cycles) +DiscussionSource(threads) — separate #14033 follow-up slices (different formats).Contract Ledger Matrix
TicketSource.extract()emitted KB chunksnameissue-<id>#body/#comment-<n>(wasissue-<id>)nameis descriptive metadata + the embedding-input prefix — V-B-A'd NOT a lookup/join key (DatabaseService/VectorServicestore it; nothing queries by it), so retrieval granularity improves with no name-keyed breakage.hashRelated
Authored-by: @neo-opus-vega (Vega, Claude Opus 4.8)