feat(attribution): per-file provenance for the forked theme's bundled art #213
No reviewers
Labels
No labels
build-dist
priority
P1
priority
P2
priority
P3
priority
P4
bug
duplicate
enhancement
help wanted
invalid
question
wontfix
No milestone
No project
No assignees
1 participant
Notifications
Due date
No due date set.
Dependencies
No dependencies set
Reference
Toilville/toilville-design!213
Loading…
Reference in a new issue
No description provided.
Delete branch "chore/third-party-asset-attribution"
Deleting a branch is permanent. Although the deleted branch may continue to exist for a short time before it actually gets removed, it CANNOT be undone in most cases. Continue?
Follow-on to #212. That PR deleted the archived copies of this art; this one records whose the live copies are.
udg/products/wp-themes/toilville-fse/is a fork of MotoPress's Prime FSE. Its art is third-party GPL work sitting in the live tree under ordinary names —check.svg,quote.svg,feature-1.svg— and nothing in the repo said whose it was except upstream's ownreadme.txt. That is how it came to be mistaken for unattributed mystery assets recovered from an archived design system (#207). Each audit had to rediscover it. This records it by path, so the next one measures instead of guessing.Scope
In scope: bundled media provenance for the forked WordPress theme. Six files, +576/−0.
udg/config/attribution.yml— the canon. Authored, reviewed in PRs, in git. 57 bundled files across five works:prime-fse-ui-artprime-fse-icon-fontprime-fse-screenshotsora-fontprime-fse-demo-photosThese are upstream's own claims, transcribed from
readme.txt, and the file says so. We record who asserts what and where — not an independent verification of MotoPress's authorship. The generator enforces only that every bundled media file is claimed by exactly one work.udg/products/wp-themes/toilville-fse/ATTRIBUTION.soon— the generated projection. Emitted byudg/generators/attribution.py, wired into thejust buildandjust checkrecipes.To be precise about where the gate bites in CI: no workflow runs
just checkwholesale (udg-dist-check.ymlruns three named generator checks), so the enforcement path in CI is the pytest lane —Test Generator / testrunsPYTHONPATH=. pytestfrom the root, which collectsgenerator/tests/unit/test_attribution.py, and its coverage and staleness tests fail the build. Verified: 19 passed under that exact invocation. I deliberately did not add a step to.forgejo/workflows/— thelint-workflowslane runs--strict, which exits non-zero on pre-existing soft warnings elsewhere in the repo, so any workflow-touching PR goes red through no fault of its own. Worth adding a named gate there once that is scoped to changed files.Per ADR-0002, SOON's only legitimate role in this stack is a regenerated, never-authored projection — so provenance (a human claim) is authored in YAML and only the index is generated, and
checkfails if the.soonwas hand-edited. It holds exactly one SOON table and no comment lines, becausesoon::Table::decodereads every non-empty line as a row; a#header would decode as data. The human-readable notice stays upstream'sreadme.txt, which ships with the theme — this is the machine-readable index on top of it.udg/generators/_soon.pyports the canonical encoder (bridges/crates/soon, Python homebin/forge_soon.py) because the generators are stdlib-only and cannot import across repos — the same way_miniyaml.pyports a YAML subset instead of taking PyYAML.Out of scope:
includes/tgmpa/is a bundled third-party PHP library (TGM Plugin Activation) that also arrived with the fork. It is code rather than artwork, so it is not claimed here — worth its own pass if you want bundled code attribution too. No live asset, token, theme or pattern changes: this adds an index and a gate, and touches no art.Testing
generator/tests/unit/test_attribution.py— 19 new tests: coverage, staleness, two failing controls, no double-claims, upstream recorded, encoder parity vectors, table framing, format-version pin, single-decodable-table.Verified against failing controls, not just the happy path:
ok — 57 bundled files carry provenance, exit 0.soonhand-editedjust buildEncoder parity: verified byte-identical to
bin/forge_soon.pyover the real 57 rows and over the spec's quoting vectors, with matchingSOON_FORMAT_VERSION(0.5.0-soon.1). The test pins those vectors and the version, so a drifted port fails instead of emitting a different dialect under the same version. Worth noting: every URL contains a colon and is therefore always quoted — the detail a hand-written SOON file gets wrong.Full suite:
generator/tests/unit→ 194 passed, 18 skipped, 3 failed. The 3 are pre-existingtest_doctor.pysandbox failures, identical to a cleanorigin/mainbaseline run in a separate checkout. No new failures.test_archive_inert.pystill passes 5/5 — the canon deliberately avoids naming a dated archive folder, since a build input that does fails that test, and it says so inline.Impact Statement
Risk: low. Nothing renders from this, and no existing generator, token, theme, pattern or asset is touched. The new
.soonfile ships inside the theme directory alongside upstream'sreadme.txt; it is inert data that no build step reads back.What changes for contributors:
just buildgains one step, andjust checkgains one gate. From now on, adding a media file to the forked theme without a provenance entry fails the test lane. That is the intended cost — it is what stops this art going unattributed again. The failure message names the file and points atudg/config/attribution.yml.One rule it must enforce: Toilville-authored art added to this theme needs its own work entry. Filing it under an upstream work to quiet the gate would re-create exactly the confusion this fixes, so a test asserts no bundled asset is attributed to Toilville LLC.
Licence posture: unchanged and already compliant. MotoPress's attribution has been intact in the theme's
readme.txtsince the fork landed; this does not fix a compliance gap, it makes the existing position legible per path. Resolves the open provenance question from #207 for the live copies, as #212 did for the archived ones.