Why: write_artifact/fs_write_file accept string content only, so models
physically cannot emit ZIP containers; every ".docx" artifact written to
date was plain text masquerading as Word (the meeting-notes docx preview
exploded in JSZip). The system advertised docx as a first-class delivery
format without a serialization path behind it.
Evidence: new internal/tools/docx.go serializes markdown to a minimal
OOXML package (PK-magic zip, word/document.xml, pStyle HeadingN) that
ingest.parseDocx round-trips; write_artifact gains format=docx (name
ending .docx auto-upgrades) and rejects xlsx/pptx/doc/xls string writes
with actionable guidance; fs_write_file gains the same guard;
runmgr.WriteArtifact now extracts index text via ingest instead of
stuffing binary bytes into the knowledge index; mock #doc demo emits a
real docx when the user names docx/word. go vet clean; go test ./...
18 packages pass, including new docx_test.go (magic, roundtrip, guards).
Impact: write_artifact contract gains an optional format param
(backwards compatible); binary-Office extensions now fail fast instead
of silently producing unopenable files. Frontend fallback for stock
fake-docx artifacts ships separately (feature/preview-sniff-fallback).
Refs: .task/feature-docx-generation.md