Skip to content

Book ↔ App consistency audit — May 2026

A read-only audit comparing every concrete claim the Intelligent Book makes against the running prototype. Each finding is classified as drift (book wrong), drift (app wrong), or OK (matches). Run after commits 21a93c5 (sims quality pass), e439b6d (learning graph upgrades), edb7ae1 (book↔app framing), and 252797c (Part II styling-rule reference).

Scope

Check Compared Verdict
C1 Numeric constants book S1/S4/S5/S6/Ch04 ↔ history_tool.py, color_tool.py, styling_agent.py OK
C2 Occasion taxonomy book S3/Ch04 ↔ OCCASION_TAG_MAP OK (5 canonical tags)
C3 Required pieces book S3/S5 ↔ REQUIRED_PIECES drift (book wrong) — D1
C4 Seven-step labels book Ch 03 ↔ styling_agent.run_agent step names drift (book wrong) — D2
C5 Forbidden-token list book S8 ↔ fit_tool.FORBIDDEN_TOKENS drift (book wrong) — D3
C6 Reasoning-trail phrases book S6/S7/Ch08 ↔ live styling_agent.py strings OK (verified literals)
C7 Reasoning-Graph entity count book Reasoning-Graph chapter ↔ graph/schema.md ↔ runtime graph_tool._NODE_STYLES OK (9 entities)
C8 Schema relation count book chapter + graph/schema.md header ↔ relations table drift (file wrong) — D4
C9 Rule-slug coverage every RULES entry in rule_refs.py ↔ Part II / Part I citations OK (already protected by tests/test_rule_refs.py)
C10 Live reasoning graph parity graph_tool.py vs. the book's improved Learning Graph viewer Improvement target (not a drift)

Verified matches (no action)

C1 · Numeric constants

Claim in book Code Match
Freshness floor 0.4 history_tool.get_freshness returns max(0.4, min(1.0, …)) ✓
Frequency penalty caps at 4 wears 0.25 × min(worn_count, 4) / 4 ✓
Recency window 3 days if (t - d).days < 3 ✓
Color base score 60 score = 60 (color_tool.score_outfit_colors line 100) ✓
Color tiers +8 / +4 / −10 lines 110–117 ✓
Color clamp 0–100 max(0, min(100, score)) line 120 ✓
Accessory cap 2 accessories_sorted[:2] line 904 ✓
Outerwear injection <60°F if isinstance(temp, …) and temp < 60 line 919 ✓

C2 · Occasion taxonomy

The five canonical tags work / gym / dinner / formal / casual are the only values OCCASION_TAG_MAP resolves to. The book is correct.

C6 · Reasoning-trail phrases

The verbatim phrases the book claims the agent emits all exist:

  • "would round out your wardrobe" — styling_agent.py:1280
  • "you haven't worn '' in N days — bringing it back today" — styling_agent.py:545-546
  • Rule-slug tags [<pack>#R<N>] — emitted via rule_refs.cite().

C7 · Reasoning Graph entities

9 entity types declared in graph/schema.md match the 9 styled in graph_tool._NODE_STYLES (User, FitProfile, CalendarEvent, WeatherSnapshot, WardrobeItem, OutfitRecommendation, WardrobeGap, ShoppingSuggestion, Feedback). Same nine appear in docs/sims/knowledge-graph/index.md.

C9 · Rule-slug coverage

Every slug in rule_refs.RULES resolves to a real ## R<N> heading (enforced by tests/test_rule_refs.py). Every active slug is cited at least once in either Part I, Part II, or a MicroSim Linked-Concept block.


Drift findings

D1 · REQUIRED_PIECES — gym entry (book S3 wrong)

The Part-II chapter book/S3-occasion-and-context.md prints the table as pseudocode:

REQUIRED_PIECES = {
    "work":    {"top", "bottom"},
    "gym":     {"top", "bottom"},        # activewear-tagged   ← wrong
    "dinner":  {"top", "bottom"},
    "formal":  {"dress"},
    "casual":  {"top", "bottom"},
}

The actual code (styling_agent.py:63–69):

REQUIRED_PIECES = {
    "work":   ["top", "bottom"],
    "dinner": ["top", "bottom"],
    "gym":    ["activewear", "activewear"],   ← code reality
    "formal": ["dress"],
    "casual": ["top", "bottom"]
}

The code treats gym as needing two activewear pieces, not a generic top+bottom. The book's pseudocode flattens that to top/bottom with a comment, which is wrong.

Action: book wrong; fix S3 pseudocode and the explanatory sentence.

D2 · Step 6 label (book Ch 03 wrong)

book/03-agent-workflow.md line 27 prints:

6. Check Wardrobe Gaps       ← detect missing required pieces

The agent emits "Check for Wardrobe Gaps" at styling_agent.py:1144 (step6 = {"step": 6, "name": "Check for Wardrobe Gaps", …}). One missing word.

Action: book wrong; add "for".

D3 · Forbidden-token list (book S8 wrong)

Book S8 lists 8 tokens:

flaw, fix, hide, minimize, correct, problem area, slimming, shameful

fit_tool.FORBIDDEN_TOKENS actually contains 17 entries across more root concepts:

FORBIDDEN_TOKENS = {
    "flaw", "flaws",
    "fix",
    "hide",
    "minimize", "minimise",
    "correct",  "corrective",
    "problem area", "problem-area", "problem_area", "problem zone",   ← extra concept
    "trouble area", "trouble-area",                                    ← extra concept
    "slimming", "slimmer",
    "shameful",
}

The book's S8 chapter discusses the 8 root concepts but doesn't acknowledge that the code enforces two additional concepts ("trouble area," "problem zone") and several variant spellings (minimise, slimmer, corrective, flaws).

Action: book wrong; update S8 to either (a) reflect the full list, or (b) note that the runtime list extends beyond the 8 root concepts with additional families + spelling variants.

D4 · Schema relation count (file wrong)

graph/schema.md line 6 says:

"The graph is intentionally minimal — 9 entity types, 14 relation types."

The actual relations table on lines 30–46 lists 17 relations:

has_fit_profile, owns, has_event, sees_weather,
prefers_color_palette, prefers_silhouette,
has_occasion_type, requires_layer_for,
matches_occasion, is_appropriate_for_season,
recommends, addresses_event, flags_gap,
suggests_to_buy, was_rejected_with, excludes_from_pool,
cites_step

The Reasoning-Graph chapter (docs/sims/knowledge-graph/index.md) inherits the same wording.

Action: file wrong; update schema.md and the chapter to "17 relation types."


Improvement target (not a drift)

C10 · Live Reasoning Graph in the app

graph_tool.py (the pyvis renderer that powers the live-run graph inside Streamlit) is mature: per-entity styles, semantic node-size encoding (wear count, outfit-piece count), curved edges, body-positive hover tooltips, an explicit LEGEND_DICT documented in code.

What it lacks, compared to the recently-improved docs/sims/learning-graph/main.html:

  1. Force-directed layout by default. McCreary's pattern is that a provenance graph should open hierarchical (top-down) so the User → Event → Outfit → Items chain reads at a glance. Wearly's live graph currently opens in forceAtlas2Based and lets physics converge, which makes the first frame look like a blob.
  2. No back-link to the abstract schema. A first-time viewer of the live graph has no path to "this is one instance of a well-defined schema — here's the schema."

These aren't drift; they're upgrades that bring the app's runtime graph to parity with the book's interactive Learning Graph.


Summary

Class Count Items
Verified matches (no action) 6 C1, C2, C6, C7, C9, parts of C5
Drift, book wrong 3 D1, D2, D3
Drift, file wrong 1 D4
Drift, app wrong 0 —
Improvement target 1 C10

Healthy state. No runtime behavior drift was found. The four drift items are all on the documentation side and are small enough to fix in one commit. The improvement target is a clean upgrade with no removed behavior.

The runtime contracts — body-positive language, freshness floor, color-score formula, accessory cap, outerwear threshold, occasion taxonomy — all hold. The agent does what the book says it does. The book's published numbers and named phrases are correct.

The drifts are exactly the kind that creep in when documentation is written before code stabilizes (D1, D2 are recent — Part II shipped two days ago) or when the documented list intentionally simplifies the implementation (D3 — book says 8 root concepts because that's the teachable unit; code has 17 entries because variants get caught).


Audit performed by reading: history_tool.py, color_tool.py, fit_tool.py, styling_agent.py, graph_tool.py, rule_refs.py, graph/schema.md, all book/*.md chapters, docs/sims/*/index.md, and the test suite. No code was changed during the audit.