13 Commits
Author SHA1 Message Date
4faae6696c Add adversarial tests for verify-semantic-motion.py and verify-sequence-oauth.py (#69)
CI / Plugin Package & Version Gate (push) Failing after 52s
CI / Python 3.9 Compatibility (push) Successful in 13s
CI / Lint & Verify (ubuntu-latest, Python 3.11) (push) Successful in 29s
Deploy gallery to GitHub Pages / build (push) Canceled after 0s
Deploy gallery to GitHub Pages / deploy (push) Canceled after 0s
CI / Lint & Verify (ubuntu-latest, Python 3.12) (push) Successful in 2m56s
CI / Lint & Verify (macos-latest, Python 3.11) (push) Canceled after 0s
CI / Lint & Verify (macos-latest, Python 3.12) (push) Canceled after 0s
CI / Lint & Verify (windows-latest, Python 3.11) (push) Canceled after 0s
CI / Lint & Verify (windows-latest, Python 3.12) (push) Canceled after 0s
* Add adversarial tests for verify-semantic-motion.py and verify-sequence-oauth.py

Every other verify-*.py in scripts/ has a matching test-verify-*.py
(verify-docs-sync, verify-geometry, verify-motion, verify-plugin-package),
and CONTRIBUTING.md lists both verify-semantic-motion.py and
verify-sequence-oauth.py as required PR gates, but neither had a dedicated
test file exercising its own pass/fail behavior.

- test-verify-semantic-motion.py: asserts the shipped SKILL.md /
  semantic-patterns.md / animation.md and the policy-trace animated example
  pass verify_markdown()/verify_example(), plus adversarial cases for a
  missing semantic-pattern router link, a missing pattern name, and a
  duplicate HTML/SVG id in the example.
- test-verify-sequence-oauth.py: CLI smoke-tests the shipped repo (expects
  ALL GATES PASSED) and an adversarial case that removes the dashed-return
  marker from the OAuth 401 response in a temporary copy of the repo tree
  (verify-sequence-oauth.py resolves paths from its own __file__, so the
  adversarial run executes the copied script against the copied tree).

Also wires both new tests into CONTRIBUTING.md's gate table and combined
validation command, following the exact pattern used for the existing
test-verify-*.py gates. (CI workflow wiring left out of this PR since it
touches .github/workflows/ci.yml — happy to add in a follow-up if useful.)

* Address review feedback on PR #69

- Wire test-verify-semantic-motion.py and test-verify-sequence-oauth.py
  into .github/workflows/ci.yml so CONTRIBUTING's new gates actually run
  in CI, with matching step-summary rows.
- Bump .claude-plugin/plugin.json and .codex-plugin/plugin.json in sync
  to 2.5.7 so scripts/verify-plugin-package.py origin/main passes again.
- Simplify test-verify-sequence-oauth.py's adversarial fixture to copy
  only the files verify-sequence-oauth.py's main() reads before the
  dashed-return check (type-sequence.md + cold-cache/oauth example
  trios), instead of shutil.copytree of the whole repository.

* Re-bump plugin manifests above current main

The prior 2.5.7 bump was superseded by subsequent merges of main into
this branch (main itself advanced past it to 2.6.5). Re-run
bump-plugin-version.py so the branch is strictly above upstream main
again (2.6.6), per @philyuchkoff's review: the diff had settled back
to no version delta at all.

---------

Co-authored-by: alvinhui <alvinhui@users.noreply.github.com>
Co-authored-by: Cathryn Lavery <50469282+cathrynlavery@users.noreply.github.com>
2026-08-25 01:57:59 -05:00
648c2a5978 feat(scatter): add bubble variant for three-value comparisons (#141)
* feat(scatter): add bubble variant for three-value comparisons

Bubble chart as a Scatter variant per the issue #62 triage: x and y on
shared zero-based linear scales, bubble AREA proportional to the third
value (r = K*sqrt(size)), one accent bubble, ink-opacity ramp as ink-mass
compensation, largest-first paint order.

scripts/verify-bubble.py derives both axis scales and the area constant
from the set itself (Theil-Sen, leave-one-out) and holds every bound
label and tick against the mark it describes; test-verify-bubble.py
exercises both polarities. Bindings are bubble-specific (data-size,
data-name, data-tick) rather than data-series, so verify-slopegraph.py
never claims a bubble file and neither checker needs scope carve-outs.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>

* fix(bubble): report a bubble whose peers cannot describe a scale

A bubble holding the only distinct value on an axis was skipped by the
leave-one-out residual test — its own fit is degenerate, and the full-set
fit passes through wherever it was drawn, so a wrong coordinate shipped
clean. Report it as unverifiable instead of skipping it.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>

* chore: bump to 2.6.3 and register bubble gates

Ridgeline (#143) landed on 2.6.2, colliding with this branch's bump, so
re-bump past it. Also add the bubble gate commands to the maintainer
policy's local_commands, matching what ridgeline registered.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>

* chore: bump to 2.6.5

The mermaid fix (#131) landed on 2.6.4, colliding with this branch's
bump again. Re-bump past it.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>

---------

Co-authored-by: 0xDarkMatter <0xDarkMatter@users.noreply.github.com>
Co-authored-by: Claude Fable 5 <noreply@anthropic.com>
2026-08-21 17:26:23 -05:00
c79585edb4 fix(mermaid): parse compact multidirectional labels (#131)
* fix(mermaid): parse compact multidirectional labels

* fix(mermaid): preserve source ids ending in markers

* chore: bump plugin version to 2.6.2

* chore: bump plugin version to 2.6.4

* fix: preserve single-character Mermaid source IDs

* fix: preserve chained Mermaid marker IDs

---------

Co-authored-by: Cathryn Lavery <cathryn@bestself.co>
2026-08-21 14:31:30 -05:00
ddaeae936e feat(line): add ridgeline as a Line variant (#143)
* feat(line): add ridgeline as a Line variant

One distribution per series, stacked at a fixed pitch on a single shared
amplitude. Ships three static examples (light, dark, full editorial),
the type-line.md spec, and a geometric gate.

verify-ridgeline.py derives the figure's one amplitude and its baseline
pitch from the figure itself, then holds every vertex to both. It also
checks the drawn baseline rules, the shared bin scale, absolute M/L/Z
only, the overlap ceiling, the focus pairing and every label binding.
test-verify-ridgeline.py proves each check in both polarities and pins
the scope treaty with the sibling Line gates.

The contract binds data-bins on a <path>, which no other chart in the
repo declares, so verify-slopegraph and this gate never claim the same
file.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>

* fix(verify-ridgeline): read exponent coordinates as numbers, not commands

parse_d scanned for [A-Za-z] independently of the numbers, so the `e` in a
valid scientific-notation coordinate such as 4.4e2 was counted as a path
command. The explicit-command rule then rejected a correct ridgeline with a
message about command counts.

Tokenise the d attribute left to right with the number branch tried first,
so an exponent is consumed as part of its number. A letter that survives
that branch is a real command and still faces the M/L/Z vocabulary check;
anything else leaves the path unreadable, which stays a finding.

Adds both polarities: a shipped coordinate rewritten as 4.4e2 must verify,
and a falsified one written the same way must not.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>

---------

Co-authored-by: 0xDarkMatter <0xDarkMatter@users.noreply.github.com>
Co-authored-by: Claude Fable 5 <noreply@anthropic.com>
2026-08-21 12:23:44 -05:00
Cathryn LaveryandGitHub 5538b35116 fix(gallery): preserve mobile preview height (#135)
* fix(gallery): preserve mobile preview height

* test(gallery): report routing failures directly
2026-08-20 12:42:26 -07:00
b827385a17 feat: consolidate reviewed Diagram Design 2.6.0 release (#134)
* fix(commands): stop hardcoding the visual-type count

Integrates the final reviewed diff from PR #112.

* docs(high-level): correct effective width checklist

Integrates the final reviewed diff from PR #105.

* fix(commands): quote profile argument hint

Integrates the final reviewed diff from PR #126.

* test(sankey): gate conservation and ribbon geometry

Integrates the final reviewed diff from PR #103.

* feat(tooling): add doctor diagnostics gate

Integrates the final reviewed diff from PR #132.

* feat(scripts): lint diagrams as rendered

Integrates the final reviewed diff from PR #18.

* feat(types): add quantitative polar chart

Integrates the final reviewed diff from PR #101.

* chore(release): consolidate reviewed changes in 2.6.0

Documents every combined gate and synchronizes Claude, Codex, and Factory metadata for the 39-type release.

* fix(doctor): support installed-skill projects

---------

Co-authored-by: mysoniw <soniw1@gmail.com>
Co-authored-by: thang <76550342+thangldw@users.noreply.github.com>
Co-authored-by: YinShaokun <yinshaokun@didiglobal.com>
Co-authored-by: 0xDarkMatter <0xDarkMatter@users.noreply.github.com>
Co-authored-by: Rupam Pal <rupam.pal@euromonitor.com>
Co-authored-by: Yuvraj3905 <yuvraj202001@gmail.com>
2026-08-20 12:21:43 -07:00
Cathryn LaveryandGitHub 4b573616cb ci: upgrade actions to Node 24 runtimes (#128) 2026-08-19 20:45:54 -07:00
Cathryn LaveryandGitHub b132fa5d7a fix(packaging): make skill references bundle-safe (#125)
* fix(packaging): make skill references bundle-safe

* test(packaging): normalize scanner paths portably

* fix(packaging): bundle required runtime helpers
2026-08-19 20:31:56 -07:00
Cathryn LaveryandGitHub 0487290d5a fix(treemap): close post-merge fail-open gaps (#127)
* fix(treemap): close fail-open metadata gaps

* chore: bump plugin version to 2.5.18

* fix(treemap): validate declared cell geometry

* fix(package): validate YAML escape sequences

* fix(package): bound Unicode YAML escapes
2026-08-19 20:25:28 -07:00
e011b04af8 fix(treemap): verify every cell share (#124)
* fix(treemap): verify every cell's area, including cells too small to label

Closes #89.

The area check derived its basis from in-cell labels, so a cell with no
label was excluded from it. That is precisely the sliver -- the cell a
4px grid distorts most, and the one that shipped 24% undersized during
review of #87. On current main, widening Oceania from 16px to 24px, a
50% area distortion, still reports OK.

Every cell now declares `data-share`, its percentage of the whole, and
the verifier checks all of them against it. Cells without it are
reported rather than skipped: a treemap whose cells cannot be parsed is
not a passing treemap, it is an unchecked one, and answering OK to it is
the defect. The label and the metadata are also cross-checked, because
two statements of one fact is a new way for the picture to lie while the
gate stays green.

Adversarial tests gain the oversized and undersized unlabelled sliver
(both pass on current main and fail here), a fail-closed case for
missing metadata, and a label/metadata divergence case.

SKILL.md `metadata.version` said 2.4 against 2.5.0 manifests. The
manifests are bumped by a script and that field is hand-maintained, so
nothing read both numbers and nothing could notice. verify-plugin-package
now asserts it tracks the manifest MAJOR.MINOR. The package test's
fixture gains the field with it -- a SKILL.md without one is not a valid
package, and a fixture missing it would only prove the gate can be
tripped by its own test data.

The examples regained the `PARTS ROUNDED, MAY NOT SUM` disclosure the
type reference requires: displayed parts round up to 8.10B against a
stated 8.09B. It was dropped when the examples were rebuilt around the
legend block. The anti-pattern list, which still forbade outright what
the honest-data rule permits once disclosed, now agrees with it.

Also nudges the info mark onto the label row of its neighbours rather
than the vertical centre of its own cell, so the bottom row reads as one
row.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>

* fix(treemap): reject ambiguous share metadata

---------

Co-authored-by: 0xDarkMatter <0xDarkMatter@users.noreply.github.com>
Co-authored-by: Claude Fable 5 <noreply@anthropic.com>
2026-08-19 22:02:02 -05:00
91fb4f243b fix(lint): enforce accessible SVG viewBox and title rules (#123)
* fix(lint): enforce viewBox presence and title length cap

- Add a11y check: non-decorative <svg> must carry a viewBox attribute
  with exactly four numeric tokens and positive width/height dimensions.
- Add a11y check: <title> text must be 60 characters or fewer, closing
  the gap between the CONTRIBUTING.md spec and linter enforcement.
- Update VALID_SVG in test-lint-a11y.py to include viewBox so all
  existing passing cases remain valid after the new checks land.
- Add three adversarial cases: missing-viewbox, invalid-viewbox,
  title-too-long — all verified against the gate suite (47/47 OK).

* fix(lint): accept SVG comma separators and reject non-finite viewBox values

- Re-split viewBox on [\s,]+ so comma-separated values (e.g. 0,0,800,600)
  are accepted as valid SVG
- Guard each component with math.isfinite() so values like inf and nan are
  rejected rather than passing the > 0 size check
- Add adversarial test cases: viewbox-comma-separated (pass),
  viewbox-nonfinite-width, viewbox-nonfinite-height (both fail)
- Bump plugin manifests to 2.4.1

* fix(lint): reject viewBox numbers with Python-only underscore separators

* test(lint): cover remaining viewBox cases

---------

Co-authored-by: Rupam Pal <rupam.pal@euromonitor.com>
2026-08-19 19:53:43 -07:00
Cathryn LaveryandGitHub cc2f51f3fd fix(import): emit extractor output as UTF-8 on Windows (#122)
* fix(import): emit extractor digests as UTF-8

* fix(import): limit UTF-8 setup to CLI entrypoints

* test(import): normalize cross-platform newline parity
2026-08-19 17:49:34 -07:00
Cathryn LaveryandGitHub 8154ec97bf feat(factory): add native Droid plugin packaging (#120)
* feat(factory): add native Droid plugin packaging

* test(factory): guard documented install contract

* fix(factory): enforce install command order
2026-08-19 17:46:46 -07:00