Documentation
¶
Overview ¶
Package media implements the deterministic media-file extractor described in Phase K (uiux-research/phase-k-media-contract.md) and PHILOSOPHY § 1's carve-out 1.
Scope (PHILOSOPHY § 1 + § 6):
- Per-trace, per-NAMED-FIELD transform of base64 / data-URL payloads into derived files on disk. No synthesis, no inference of media that isn't already explicitly carried by a documented protocol field.
- The JSONL line on disk remains the source of truth; extracted files are a redundant cache that exists for fast viewer reads and zip-export bundling.
Non-interference (PHILOSOPHY § 2):
- Extract() runs after writer.appendOne has flushed the JSONL line. Any failure logs a WARN and returns the partial slice so the writer pipeline keeps moving. We never return a non-nil error from Extract.
Skip rules per Phase K § 2 (and operator clarification 2026-05-30):
- body_b64 is the unparseable-fallback container, NOT an attachment. Extractor skips it entirely.
- http(s):// and gs:// / file: URL-only references are not fetched.
- Empty / whitespace base64 strings are silently skipped.
Package owns four files: media.go (public surface), walk.go (generic JSON walker), protocols.go (per-protocol field tables), decode.go (base64 + data-URL + mime helpers). Tests are walk_test.go and protocols_test.go.
Index ¶
Constants ¶
This section is empty.
Variables ¶
This section is empty.
Functions ¶
This section is empty.
Types ¶
type Config ¶
type Config struct {
// DataDir is the same `${data_dir}` the writer uses. Extracted files
// live under ${DataDir}/${YYYY-MM-DD}/${keyhash[:8]}/media/${trace_id}/.
DataDir string
}
Config is the extractor's runtime configuration. Wired by main from the process-level config object; the extractor itself never reads YAML/env.
type Extractor ¶
type Extractor struct {
// contains filtered or unexported fields
}
Extractor is the public type. Construct via New, call Extract per trace. Safe for concurrent use across goroutines (no shared mutable state beyond the underlying filesystem).
func New ¶
New constructs an Extractor. cfg.DataDir must be non-empty for files to be written; with an empty DataDir Extract() still walks the bodies and returns metadata but writes no files (test-friendly).
func (*Extractor) Extract ¶
Extract walks t.Req.Body and t.Resp.Body, identifies media-bearing fields per the documented protocols, decodes their base64 payloads, writes the files under ${DataDir}/${date}/${keyhash[:8]}/media/${trace_id}/, and returns the list of MediaFile records.
Per PHILOSOPHY § 2 the function never returns an error. Per-file failures (mkdir denied, ENOSPC, malformed base64, …) are logged at WARN and the corresponding MediaFile is omitted from the returned slice. The writer pipeline must keep moving regardless.
body_b64 is skipped unconditionally; URL-only image references are skipped (no remote fetch). See package doc for the full skip-list.
type MediaFile ¶
type MediaFile struct {
// Idx is the 0-based ordinal across BOTH sides of the trace, request
// media first (document order) then response media.
Idx int `json:"idx"`
// Side is "req" or "resp".
Side string `json:"side"`
// SourceField is the dotted/bracketed JSON path inside the side body
// where this media was found. Examples:
// "messages[0].content[0].image_url.url"
// "contents[1].parts[3].inlineData.data"
SourceField string `json:"sourceField"`
// MimeType is the protocol-declared mime if present, else inferred from
// a data: URL header, else "application/octet-stream".
MimeType string `json:"mimeType"`
// Extension is the lower-case extension derived ONLY from MimeType
// (no leading dot). Never inferred from a filename.
Extension string `json:"extension"`
// Size is the decoded byte length of the written file.
Size int64 `json:"size"`
// Filename is the path relative to the per-key media dir; full disk
// path is `${DataDir}/${date}/${keyhash[:8]}/${Filename}`.
// Format: `media/${trace_id}/${idx}.${ext}`.
Filename string `json:"filename"`
}
MediaFile mirrors the struct in Phase K § 3 exactly. JSON tags are the shape the SQLite mirror / viewer API expect.