ADR-0008: Use distinct ImageMarker types for pending state
Status: accepted | Date: 2026-02-17
References: RFC-0002
Context
The codebase has two image-related concepts:
HtmlElement::Image/InlineFragment::InlineImage— resolved images with URLsHtmlElement::ImageMarker— pending images awaiting deferred upload
For block-level images, the distinction is explicit via types. However, inline images
use InlineFragment::InlineImage for both resolved and pending states, distinguishing
them by examining the src field at runtime:
#![allow(unused)]
fn main() {
// Current: runtime check to determine pending state
if !src.starts_with("http://") && !src.starts_with("https://") {
paths.push(PathBuf::from(src)); // pending
}
}
This violates the Rust principle of encoding invariants in types. The pending state is not visible in the type system.
Decision
Add InlineFragment::ImageMarker variant for pending inline images, mirroring the
block-level HtmlElement::ImageMarker:
#![allow(unused)]
fn main() {
enum InlineFragment {
// ...
InlineImage { src: String, alt: String, attrs: Attrs }, // resolved
ImageMarker { path: String, alt: String, attrs: Attrs }, // pending
}
}
Remove the display field from HtmlElement::ImageMarker since the block/inline
distinction is now encoded in the type itself (HtmlElement vs InlineFragment).
This creates a clean state machine:
- Block:
ImageMarker→ [upload] →Image - Inline:
InlineFragment::ImageMarker→ [upload] →InlineFragment::InlineImage
Consequences
Benefits:
- Type system enforces pending/resolved distinction at compile time
govctl checkvalidates no unresolved markers before serialize- Unified tracking logic for both block and inline markers
- Simpler format adapters (no runtime URL prefix checks)
Trade-offs:
- More enum variants to handle in match expressions
- Need recursive traversal for
InlineFragment::ImageMarker - Requires updates to all consumers of
InlineFragment
Affected files:
typub-html/src/types.rs— add variant, remove display fieldtypub-html/src/svg.rs— generate correct marker typestypub-assets-ast/src/lib.rs— recursive tracking and resolution- Adapter format modules — handle new variant