towishy_Owen-Graphite/dev/scripts/fp_diff_summary.py

72 lines
2.3 KiB
Python
Raw Normal View History

#!/usr/bin/env python3
v3-rewrite [S3.1]: cascade pivot (no @layer) + base modules + v3 fingerprint baseline Major architectural decision: v3 drops @layer for theme content. CSS Cascade Layers spec says unlayered styles always defeat layered styles, and Obsidian core CSS (app.css) is unlayered. Wrapping the theme in @layer would require !important to win against core, defeating the v3 goal of reducing !important usage. Therefore v3 theme rules stay UNLAYERED and rely on (1) file @import order, (2) selector specificity, (3) remaining !important only where Obsidian core itself uses !important. Updated docs/v3/design-spec.md: replaced the @layer cascade section with a Cascade Strategy section explaining file-order + specificity. Added a decision log entry for the pivot and a S11 polish note clarifying that !important reduction is deferred from S3 to S11 (strangler pattern: correctness first via fingerprint diff = 0, then audit-driven reduction). Updated src/entry.css: removed layer() annotations from @import statements; expanded the file header to document the cascade strategy decision. Tokens import remains first, base modules now active, surfaces/chrome/etc. stay commented placeholders for S4+. Updated scripts/bundle_v3.py: removed @layer wrapping logic. Bundler now emits a plain depth-first concatenation of @import targets. Resulting dist/theme-v3.css is 1223 lines (up from 455 at S2) with !important=332 (mirrors dev/02 + dev/03 sources exactly, will reduce in S11 polish). Added src/base/10-base-workspace.css - copied verbatim from dev/02-base-workspace.css (118 lines, 14 !important). Provides workspace pane backgrounds, ribbon/tab colors, nav-folder/nav-file title colors, button surfaces, readable-line-width sizing, .markdown-rendered base typography (font-family, font-size from --ogd-body-size token, word-break). Added src/base/12-reading-content.css - copied verbatim from dev/03-reading-content.css (567 lines, 313 !important). Provides reading view editorial number kicker h1-h4, h2 gradient underline pill, base table structure (border-collapse, th/td padding, first-column accent), blockquote padding strip-back. Updated dev/v3/golden-rig/obsidian-harness.html: added a URL parameter switcher (?build=v3) so capture scripts can toggle between theme.css (v2 baseline) and dist/theme-v3.css (v3 candidate) without editing the file. Default remains theme.css. Updated scripts/capture_computed_fingerprint.py: added --build {v2,v3} flag. v3 output goes to docs/v3/computed-fingerprint-v<version>-v3-<theme>.json. Records the build value inside the JSON for traceability. Added scripts/fp_diff_summary.py - prints a per-element diff count between baseline and candidate fingerprints. Used to track S3-S6 closure progress against the 949 starting diff. Added scripts/fp_diff_inspect.py - prints every property diff for a single fingerprint element. Used to locate specific computed-style drift when the per-element count is high. Light fingerprint baseline gap measurement: pre-S3 949 mismatches (v3 was only tokens). After S3.1 base modules activated: 616 mismatches (35 percent closure). Remaining 616 are expected — h1 glassy surface comes from dev/10b + 10d (S5 surfaces / S6 chrome), nav/overlay/popover from S6, callout/table from S5, cm-* from S4 live preview. Captured docs/v3/computed-fingerprint-v2.30.14-v3-{light,dark}.json baselines for the v3 build after S3.1. validate_theme.py: still passes against v2.30.14 (theme.css unchanged at 16190 lines / 5816 !important / 37 Style Settings).
2026-05-16 02:15:28 +00:00
"""Summarize the v3 fingerprint diff by element.
Reads both the v2.30.14 baseline and the freshly captured v3 candidate from
`dev/WIKI/DOCS/v3/computed-fingerprint-v<version>-*.json` and prints a per-element
v3-rewrite [S3.1]: cascade pivot (no @layer) + base modules + v3 fingerprint baseline Major architectural decision: v3 drops @layer for theme content. CSS Cascade Layers spec says unlayered styles always defeat layered styles, and Obsidian core CSS (app.css) is unlayered. Wrapping the theme in @layer would require !important to win against core, defeating the v3 goal of reducing !important usage. Therefore v3 theme rules stay UNLAYERED and rely on (1) file @import order, (2) selector specificity, (3) remaining !important only where Obsidian core itself uses !important. Updated docs/v3/design-spec.md: replaced the @layer cascade section with a Cascade Strategy section explaining file-order + specificity. Added a decision log entry for the pivot and a S11 polish note clarifying that !important reduction is deferred from S3 to S11 (strangler pattern: correctness first via fingerprint diff = 0, then audit-driven reduction). Updated src/entry.css: removed layer() annotations from @import statements; expanded the file header to document the cascade strategy decision. Tokens import remains first, base modules now active, surfaces/chrome/etc. stay commented placeholders for S4+. Updated scripts/bundle_v3.py: removed @layer wrapping logic. Bundler now emits a plain depth-first concatenation of @import targets. Resulting dist/theme-v3.css is 1223 lines (up from 455 at S2) with !important=332 (mirrors dev/02 + dev/03 sources exactly, will reduce in S11 polish). Added src/base/10-base-workspace.css - copied verbatim from dev/02-base-workspace.css (118 lines, 14 !important). Provides workspace pane backgrounds, ribbon/tab colors, nav-folder/nav-file title colors, button surfaces, readable-line-width sizing, .markdown-rendered base typography (font-family, font-size from --ogd-body-size token, word-break). Added src/base/12-reading-content.css - copied verbatim from dev/03-reading-content.css (567 lines, 313 !important). Provides reading view editorial number kicker h1-h4, h2 gradient underline pill, base table structure (border-collapse, th/td padding, first-column accent), blockquote padding strip-back. Updated dev/v3/golden-rig/obsidian-harness.html: added a URL parameter switcher (?build=v3) so capture scripts can toggle between theme.css (v2 baseline) and dist/theme-v3.css (v3 candidate) without editing the file. Default remains theme.css. Updated scripts/capture_computed_fingerprint.py: added --build {v2,v3} flag. v3 output goes to docs/v3/computed-fingerprint-v<version>-v3-<theme>.json. Records the build value inside the JSON for traceability. Added scripts/fp_diff_summary.py - prints a per-element diff count between baseline and candidate fingerprints. Used to track S3-S6 closure progress against the 949 starting diff. Added scripts/fp_diff_inspect.py - prints every property diff for a single fingerprint element. Used to locate specific computed-style drift when the per-element count is high. Light fingerprint baseline gap measurement: pre-S3 949 mismatches (v3 was only tokens). After S3.1 base modules activated: 616 mismatches (35 percent closure). Remaining 616 are expected — h1 glassy surface comes from dev/10b + 10d (S5 surfaces / S6 chrome), nav/overlay/popover from S6, callout/table from S5, cm-* from S4 live preview. Captured docs/v3/computed-fingerprint-v2.30.14-v3-{light,dark}.json baselines for the v3 build after S3.1. validate_theme.py: still passes against v2.30.14 (theme.css unchanged at 16190 lines / 5816 !important / 37 Style Settings).
2026-05-16 02:15:28 +00:00
count of mismatching properties. Useful for tracking S3-S6 closure progress.
Usage:
python dev/scripts/fp_diff_summary.py
python dev/scripts/fp_diff_summary.py --theme dark
v3-rewrite [S3.1]: cascade pivot (no @layer) + base modules + v3 fingerprint baseline Major architectural decision: v3 drops @layer for theme content. CSS Cascade Layers spec says unlayered styles always defeat layered styles, and Obsidian core CSS (app.css) is unlayered. Wrapping the theme in @layer would require !important to win against core, defeating the v3 goal of reducing !important usage. Therefore v3 theme rules stay UNLAYERED and rely on (1) file @import order, (2) selector specificity, (3) remaining !important only where Obsidian core itself uses !important. Updated docs/v3/design-spec.md: replaced the @layer cascade section with a Cascade Strategy section explaining file-order + specificity. Added a decision log entry for the pivot and a S11 polish note clarifying that !important reduction is deferred from S3 to S11 (strangler pattern: correctness first via fingerprint diff = 0, then audit-driven reduction). Updated src/entry.css: removed layer() annotations from @import statements; expanded the file header to document the cascade strategy decision. Tokens import remains first, base modules now active, surfaces/chrome/etc. stay commented placeholders for S4+. Updated scripts/bundle_v3.py: removed @layer wrapping logic. Bundler now emits a plain depth-first concatenation of @import targets. Resulting dist/theme-v3.css is 1223 lines (up from 455 at S2) with !important=332 (mirrors dev/02 + dev/03 sources exactly, will reduce in S11 polish). Added src/base/10-base-workspace.css - copied verbatim from dev/02-base-workspace.css (118 lines, 14 !important). Provides workspace pane backgrounds, ribbon/tab colors, nav-folder/nav-file title colors, button surfaces, readable-line-width sizing, .markdown-rendered base typography (font-family, font-size from --ogd-body-size token, word-break). Added src/base/12-reading-content.css - copied verbatim from dev/03-reading-content.css (567 lines, 313 !important). Provides reading view editorial number kicker h1-h4, h2 gradient underline pill, base table structure (border-collapse, th/td padding, first-column accent), blockquote padding strip-back. Updated dev/v3/golden-rig/obsidian-harness.html: added a URL parameter switcher (?build=v3) so capture scripts can toggle between theme.css (v2 baseline) and dist/theme-v3.css (v3 candidate) without editing the file. Default remains theme.css. Updated scripts/capture_computed_fingerprint.py: added --build {v2,v3} flag. v3 output goes to docs/v3/computed-fingerprint-v<version>-v3-<theme>.json. Records the build value inside the JSON for traceability. Added scripts/fp_diff_summary.py - prints a per-element diff count between baseline and candidate fingerprints. Used to track S3-S6 closure progress against the 949 starting diff. Added scripts/fp_diff_inspect.py - prints every property diff for a single fingerprint element. Used to locate specific computed-style drift when the per-element count is high. Light fingerprint baseline gap measurement: pre-S3 949 mismatches (v3 was only tokens). After S3.1 base modules activated: 616 mismatches (35 percent closure). Remaining 616 are expected — h1 glassy surface comes from dev/10b + 10d (S5 surfaces / S6 chrome), nav/overlay/popover from S6, callout/table from S5, cm-* from S4 live preview. Captured docs/v3/computed-fingerprint-v2.30.14-v3-{light,dark}.json baselines for the v3 build after S3.1. validate_theme.py: still passes against v2.30.14 (theme.css unchanged at 16190 lines / 5816 !important / 37 Style Settings).
2026-05-16 02:15:28 +00:00
"""
import argparse
import json
from collections import Counter
from pathlib import Path
ROOT = Path(__file__).resolve().parents[2]
v3-rewrite [S3.1]: cascade pivot (no @layer) + base modules + v3 fingerprint baseline Major architectural decision: v3 drops @layer for theme content. CSS Cascade Layers spec says unlayered styles always defeat layered styles, and Obsidian core CSS (app.css) is unlayered. Wrapping the theme in @layer would require !important to win against core, defeating the v3 goal of reducing !important usage. Therefore v3 theme rules stay UNLAYERED and rely on (1) file @import order, (2) selector specificity, (3) remaining !important only where Obsidian core itself uses !important. Updated docs/v3/design-spec.md: replaced the @layer cascade section with a Cascade Strategy section explaining file-order + specificity. Added a decision log entry for the pivot and a S11 polish note clarifying that !important reduction is deferred from S3 to S11 (strangler pattern: correctness first via fingerprint diff = 0, then audit-driven reduction). Updated src/entry.css: removed layer() annotations from @import statements; expanded the file header to document the cascade strategy decision. Tokens import remains first, base modules now active, surfaces/chrome/etc. stay commented placeholders for S4+. Updated scripts/bundle_v3.py: removed @layer wrapping logic. Bundler now emits a plain depth-first concatenation of @import targets. Resulting dist/theme-v3.css is 1223 lines (up from 455 at S2) with !important=332 (mirrors dev/02 + dev/03 sources exactly, will reduce in S11 polish). Added src/base/10-base-workspace.css - copied verbatim from dev/02-base-workspace.css (118 lines, 14 !important). Provides workspace pane backgrounds, ribbon/tab colors, nav-folder/nav-file title colors, button surfaces, readable-line-width sizing, .markdown-rendered base typography (font-family, font-size from --ogd-body-size token, word-break). Added src/base/12-reading-content.css - copied verbatim from dev/03-reading-content.css (567 lines, 313 !important). Provides reading view editorial number kicker h1-h4, h2 gradient underline pill, base table structure (border-collapse, th/td padding, first-column accent), blockquote padding strip-back. Updated dev/v3/golden-rig/obsidian-harness.html: added a URL parameter switcher (?build=v3) so capture scripts can toggle between theme.css (v2 baseline) and dist/theme-v3.css (v3 candidate) without editing the file. Default remains theme.css. Updated scripts/capture_computed_fingerprint.py: added --build {v2,v3} flag. v3 output goes to docs/v3/computed-fingerprint-v<version>-v3-<theme>.json. Records the build value inside the JSON for traceability. Added scripts/fp_diff_summary.py - prints a per-element diff count between baseline and candidate fingerprints. Used to track S3-S6 closure progress against the 949 starting diff. Added scripts/fp_diff_inspect.py - prints every property diff for a single fingerprint element. Used to locate specific computed-style drift when the per-element count is high. Light fingerprint baseline gap measurement: pre-S3 949 mismatches (v3 was only tokens). After S3.1 base modules activated: 616 mismatches (35 percent closure). Remaining 616 are expected — h1 glassy surface comes from dev/10b + 10d (S5 surfaces / S6 chrome), nav/overlay/popover from S6, callout/table from S5, cm-* from S4 live preview. Captured docs/v3/computed-fingerprint-v2.30.14-v3-{light,dark}.json baselines for the v3 build after S3.1. validate_theme.py: still passes against v2.30.14 (theme.css unchanged at 16190 lines / 5816 !important / 37 Style Settings).
2026-05-16 02:15:28 +00:00
def main() -> int:
parser = argparse.ArgumentParser(description=__doc__)
parser.add_argument("--theme", choices=["light", "dark"], default="light")
parser.add_argument(
"--baseline",
type=Path,
default=None,
help="Baseline fingerprint JSON. Defaults to v2.30.14 baseline for the chosen theme.",
)
parser.add_argument(
"--candidate",
type=Path,
default=None,
help="Candidate fingerprint JSON. Defaults to v2.30.14 v3 build for the chosen theme.",
)
args = parser.parse_args()
baseline_path = args.baseline or (
ROOT / "dev" / "WIKI" / "DOCS" / "v3" / f"computed-fingerprint-v2.30.14-{args.theme}.json"
v3-rewrite [S3.1]: cascade pivot (no @layer) + base modules + v3 fingerprint baseline Major architectural decision: v3 drops @layer for theme content. CSS Cascade Layers spec says unlayered styles always defeat layered styles, and Obsidian core CSS (app.css) is unlayered. Wrapping the theme in @layer would require !important to win against core, defeating the v3 goal of reducing !important usage. Therefore v3 theme rules stay UNLAYERED and rely on (1) file @import order, (2) selector specificity, (3) remaining !important only where Obsidian core itself uses !important. Updated docs/v3/design-spec.md: replaced the @layer cascade section with a Cascade Strategy section explaining file-order + specificity. Added a decision log entry for the pivot and a S11 polish note clarifying that !important reduction is deferred from S3 to S11 (strangler pattern: correctness first via fingerprint diff = 0, then audit-driven reduction). Updated src/entry.css: removed layer() annotations from @import statements; expanded the file header to document the cascade strategy decision. Tokens import remains first, base modules now active, surfaces/chrome/etc. stay commented placeholders for S4+. Updated scripts/bundle_v3.py: removed @layer wrapping logic. Bundler now emits a plain depth-first concatenation of @import targets. Resulting dist/theme-v3.css is 1223 lines (up from 455 at S2) with !important=332 (mirrors dev/02 + dev/03 sources exactly, will reduce in S11 polish). Added src/base/10-base-workspace.css - copied verbatim from dev/02-base-workspace.css (118 lines, 14 !important). Provides workspace pane backgrounds, ribbon/tab colors, nav-folder/nav-file title colors, button surfaces, readable-line-width sizing, .markdown-rendered base typography (font-family, font-size from --ogd-body-size token, word-break). Added src/base/12-reading-content.css - copied verbatim from dev/03-reading-content.css (567 lines, 313 !important). Provides reading view editorial number kicker h1-h4, h2 gradient underline pill, base table structure (border-collapse, th/td padding, first-column accent), blockquote padding strip-back. Updated dev/v3/golden-rig/obsidian-harness.html: added a URL parameter switcher (?build=v3) so capture scripts can toggle between theme.css (v2 baseline) and dist/theme-v3.css (v3 candidate) without editing the file. Default remains theme.css. Updated scripts/capture_computed_fingerprint.py: added --build {v2,v3} flag. v3 output goes to docs/v3/computed-fingerprint-v<version>-v3-<theme>.json. Records the build value inside the JSON for traceability. Added scripts/fp_diff_summary.py - prints a per-element diff count between baseline and candidate fingerprints. Used to track S3-S6 closure progress against the 949 starting diff. Added scripts/fp_diff_inspect.py - prints every property diff for a single fingerprint element. Used to locate specific computed-style drift when the per-element count is high. Light fingerprint baseline gap measurement: pre-S3 949 mismatches (v3 was only tokens). After S3.1 base modules activated: 616 mismatches (35 percent closure). Remaining 616 are expected — h1 glassy surface comes from dev/10b + 10d (S5 surfaces / S6 chrome), nav/overlay/popover from S6, callout/table from S5, cm-* from S4 live preview. Captured docs/v3/computed-fingerprint-v2.30.14-v3-{light,dark}.json baselines for the v3 build after S3.1. validate_theme.py: still passes against v2.30.14 (theme.css unchanged at 16190 lines / 5816 !important / 37 Style Settings).
2026-05-16 02:15:28 +00:00
)
candidate_path = args.candidate or (
ROOT / "dev" / "WIKI" / "DOCS" / "v3" / f"computed-fingerprint-v2.30.14-v3-{args.theme}.json"
v3-rewrite [S3.1]: cascade pivot (no @layer) + base modules + v3 fingerprint baseline Major architectural decision: v3 drops @layer for theme content. CSS Cascade Layers spec says unlayered styles always defeat layered styles, and Obsidian core CSS (app.css) is unlayered. Wrapping the theme in @layer would require !important to win against core, defeating the v3 goal of reducing !important usage. Therefore v3 theme rules stay UNLAYERED and rely on (1) file @import order, (2) selector specificity, (3) remaining !important only where Obsidian core itself uses !important. Updated docs/v3/design-spec.md: replaced the @layer cascade section with a Cascade Strategy section explaining file-order + specificity. Added a decision log entry for the pivot and a S11 polish note clarifying that !important reduction is deferred from S3 to S11 (strangler pattern: correctness first via fingerprint diff = 0, then audit-driven reduction). Updated src/entry.css: removed layer() annotations from @import statements; expanded the file header to document the cascade strategy decision. Tokens import remains first, base modules now active, surfaces/chrome/etc. stay commented placeholders for S4+. Updated scripts/bundle_v3.py: removed @layer wrapping logic. Bundler now emits a plain depth-first concatenation of @import targets. Resulting dist/theme-v3.css is 1223 lines (up from 455 at S2) with !important=332 (mirrors dev/02 + dev/03 sources exactly, will reduce in S11 polish). Added src/base/10-base-workspace.css - copied verbatim from dev/02-base-workspace.css (118 lines, 14 !important). Provides workspace pane backgrounds, ribbon/tab colors, nav-folder/nav-file title colors, button surfaces, readable-line-width sizing, .markdown-rendered base typography (font-family, font-size from --ogd-body-size token, word-break). Added src/base/12-reading-content.css - copied verbatim from dev/03-reading-content.css (567 lines, 313 !important). Provides reading view editorial number kicker h1-h4, h2 gradient underline pill, base table structure (border-collapse, th/td padding, first-column accent), blockquote padding strip-back. Updated dev/v3/golden-rig/obsidian-harness.html: added a URL parameter switcher (?build=v3) so capture scripts can toggle between theme.css (v2 baseline) and dist/theme-v3.css (v3 candidate) without editing the file. Default remains theme.css. Updated scripts/capture_computed_fingerprint.py: added --build {v2,v3} flag. v3 output goes to docs/v3/computed-fingerprint-v<version>-v3-<theme>.json. Records the build value inside the JSON for traceability. Added scripts/fp_diff_summary.py - prints a per-element diff count between baseline and candidate fingerprints. Used to track S3-S6 closure progress against the 949 starting diff. Added scripts/fp_diff_inspect.py - prints every property diff for a single fingerprint element. Used to locate specific computed-style drift when the per-element count is high. Light fingerprint baseline gap measurement: pre-S3 949 mismatches (v3 was only tokens). After S3.1 base modules activated: 616 mismatches (35 percent closure). Remaining 616 are expected — h1 glassy surface comes from dev/10b + 10d (S5 surfaces / S6 chrome), nav/overlay/popover from S6, callout/table from S5, cm-* from S4 live preview. Captured docs/v3/computed-fingerprint-v2.30.14-v3-{light,dark}.json baselines for the v3 build after S3.1. validate_theme.py: still passes against v2.30.14 (theme.css unchanged at 16190 lines / 5816 !important / 37 Style Settings).
2026-05-16 02:15:28 +00:00
)
baseline = json.loads(baseline_path.read_text(encoding="utf-8"))
candidate = json.loads(candidate_path.read_text(encoding="utf-8"))
b = baseline["elements"]
c = candidate["elements"]
per_element: Counter[str] = Counter()
for elem in set(b) | set(c):
bp = b.get(elem, {})
cp = c.get(elem, {})
for prop in set(bp) | set(cp):
if bp.get(prop) != cp.get(prop):
per_element[elem] += 1
total = sum(per_element.values())
print(f"baseline: {baseline_path.relative_to(ROOT)}")
print(f"candidate: {candidate_path.relative_to(ROOT)}")
print(f"Total diffs: {total}")
print(f"Elements with diffs: {len(per_element)} / {len(set(b) | set(c))}")
print()
print(f"{'element':<32} {'diff count':>10}")
for elem, n in per_element.most_common():
print(f"{elem:<32} {n:>10}")
return 0
if __name__ == "__main__":
raise SystemExit(main())