v0.9.0 - the brand-intelligence release
[0.9.0] - 2026-06-10
The brand-intelligence release: derived indexes that never lie (rich TOC
cache, empty rebuilds), multi-template profiles (extract --blend), the
cross-template drift report (compare-profiles), a guided authoring surface,
a local-corpus fidelity benchmark, and a 31-finding general-review hardening
wave on top.
Fixed
-
General-review wave (multi-agent, 31 confirmed findings). Engine: the
heading-less generation now collapses a bare multi-paragraph outline TOC's
FULL span to an empty field (the plain writer used to leave the template's
demo entries and orphan the end fldChar - a regression of the rich-TOC
delta); pptx and xlsx extraction now parse the themea:fontSchemelatin
typefaces instead of hardcodinglatin=null(the docx extractor already
did);schema.validatereturns problems instead of raising on a
hand-edited blend ledger with mixed-type entries; profile JSON/sidecar
writes are atomic (same-directory temp +os.replace), making the blend's
byte-identity-on-failure claim true under ENOSPC/kill; OOXMLunpack/
read_partreject decompression bombs (per-part and per-package declared
inflated-size floors); the corpus runner exits 1 on verify exceptions, not
just clean failures. Examples: the three builders now consume ONE complete
12-slot brand clrScheme from_brandlib(docx/pptx/xlsx had drifted apart
on five supporting slots - caught live bycompare-profiles- and the
shipped pair now reports zero theme drift, pinned by a strengthened CLI
test that replaced a tautological assertion). Docs: README test count and
blending/compare teaching, CONVENTIONS gains the engine verb surface and a
§16 blend/compare vocabulary, the Pages site's broken README anchor and
stale install command fixed, a real brand word in ROADMAP replaced with a
placeholder. -
The refreshed outline TOC cache is now a real Word-shaped TOC (REFLECTIONS
P3). The visible cache of a preserved or authored outline table of contents
was rewritten as flat plain-text entries: one style for every level, no
links, no page-number fields. The rewrite now authors deterministic
bookmarks on the generated headings (_TocBD000001sequential,
collision-scanned ids), harvests a per-level paragraph-style map from the
template's OWN cached entries (trailing-digit TOC style convention,
indentation-rank fallback, nearest-lower-level chain), and emits each entry
as hyperlink-to-bookmark + tab + nested dirtyPAGEREF, so previews show
the template's real per-level TOC styling and Word fills page numbers on
open. The bare-paragraph TOC path converges to the same multi-paragraph
shape. Fail-closed: a malformed cache falls back to the previous simple
rewrite atomically; documents without an outline TOC author zero bookmarks
and stay byte-identical (now pinned by a dedicated TOC-free frozen anchor;
the historical anchor was deliberately recomputed because the committed
fixture itself contains an outline TOC, so its cached-TOC bytes necessarily
changed shape). -
Template demo entries no longer survive in derived indexes the content did
not feed. A kept caption index (table-of-tables / table-of-figures) whose
sequence received no captions, and an outline TOC in a heading-less
generation, used to keep the template's cached demo entries (the "stale
derived index" defect class, visible in every preview renderer). Both caches
are now rebuilt EMPTY: the field code survives, dirty, so Word recomputes it
on open, but fabricated entries never reach the generated document. The
destructive-action floor is untouched: structure is still never removed
without corroboration; only the visible cache is honest now.
Added
- Local-corpus fidelity benchmark (REFLECTIONS P3). New
scripts/corpus_benchmark.pywalks a corpus of REAL templates that lives
outside the repository (and refuses one inside it), runs
extract -> verify -> brand-agnostic probe generate -> QA per template in a
throwaway directory, and writes a datedreport.{md,json}next to the
corpus with the LibreOffice-vs-Word caveat stated in the header. The probe
input is typed blocks only (no styles, colors, fonts), so the corpus
measures the engine without ever tuning it;documentation/DEVELOPMENT.md
documents the layout. CI smokes the runner on the synthetic example
template. - Authoring intelligence for the IntermediateDocument/GridDocument
(REFLECTIONS P3). The least-guarded stage (what the authoring agent puts
IN the input) now has a guided surface: PROFILE.md gains three
format-uniform sections rendered by the new sharedcommon/profilemd.py
(the role table on all three formats - pptx/xlsx previously shipped a
two-line stub - a "Brand palette roles" table naming the semantic color
tokens an author may reference, and "Authoring hints" that advertise
comprehended fragments when present); each skill's SKILL.md gains an
"Authoring the IntermediateDocument/GridDocument" section with role-first
composition rules (skeleton order, heading hierarchy the TOC regenerates
from, captions so derived indexes stay real, native objects on pptx, region
bounds and formula preservation on xlsx, color discipline, fragments before
re-derivation). Advisory by construction: nothing here adds engine
authority, the resolver remains the only author of values. - Multi-template profile blending (REFLECTIONS P3, the quality-ceiling
lift).extract --name X --template second.docx --blendfolds a SECOND
same-format template into an existing profile at the VALUE-fact level: it
fills captured facts the primary left unset, corroborates agreeing facts
with a bounded deterministic confidence boost, and keeps the primary's value
on every conflict. Artifact POINTERS (style ids, layouts, anchors,
numbering) never cross shells: generation still opens the PRIMARY shell and
the resolver still membership-validates everything against it, so the brand
guarantee is untouched. Fail-closed all-or-nothing transaction (a rejected
blend leaves profile.json byte-identical), sha-deduped and idempotent
(re-blending the same file is a no-op), secondary shells stored
content-addressed next to the primary with provenance, guarded by the new
blend_shell_provenanceQA check (donor tamper/drift = ERROR). Single-
template profiles serialize without one new key and both frozen generation
anchors are unmoved. Same-format only by design; cross-format stays the job
ofcompare-profiles. compare-profiles: the cross-template drift report (REFLECTIONS P3).
New read-only CLI verb that compares the BRAND-level facts of two saved
profiles: theme colors per slot, theme/captured fonts, semantic palette
roles, and off-theme usage (a raw hex in one profile that is a theme slot in
the other - the sharpest "one template is off-theme" signal). Structural
facts (styles, layouts, anchors) are never compared as drift: they are
per-shell by design; role coverage is reported as information only. Writes
nothing; exits 1 on brand-level drift so it can gate brand coherence in CI.
First live run immediately caught a real inconsistency between the shipped
docx and pptx example templates (five theme slots disagree) - queued for the
next example-template refresh.- Contributor onramp (REFLECTIONS P1).
CONTRIBUTING.mdexpanded from a
10-line stub to the full gate (dev setup, the three test lanes, the seven
non-negotiable rules, PR checklist, sized first contributions);
scripts/brandkit/README.mdcreated as the engine internals map (module
layout, the ten verbs' call paths, the two invariants, the recipe for a new
capture axis); the release checklist written down in
documentation/DEVELOPMENT.md; three sized "good first issue"s opened. - PLUGIN_WORKFLOW drift guard.
documentation/PLUGIN_WORKFLOW.mdnow
documents the full ten-verb CLI surface and the learning loop
(generation_report.json->learn/propose-overrides->--accept) in the
end-to-end diagram;tests/test_doc_drift.pyfails the build if a CLI verb
or acommands/slash command is missing from the document.