Lock asset pipeline to free sources

This commit is contained in:
2026-05-21 22:21:16 +00:00
parent f0713c6c46
commit fc74a7b129
4 changed files with 94 additions and 3 deletions
+12 -1
View File
@@ -22,7 +22,8 @@ not look cartoonish, old-west, or exaggerated apocalypse junkyard.
## Approved Sources ## Approved Sources
- Fab free assets or assets explicitly owned for this project. - Fab free assets. Paid Fab assets are blocked unless Nathan explicitly approves
the purchase in a later task.
- Quixel/Megascans assets available under the current Epic/Unreal terms. - Quixel/Megascans assets available under the current Epic/Unreal terms.
- CC0/public-domain art libraries. - CC0/public-domain art libraries.
- Assets created internally. - Assets created internally.
@@ -31,6 +32,16 @@ not look cartoonish, old-west, or exaggerated apocalypse junkyard.
Do not scrape random internet images or models. If an asset cannot be traced to Do not scrape random internet images or models. If an asset cannot be traced to
a usable license, reject it. a usable license, reject it.
## Free-Only Lockdown
The asset pipeline is currently free-only. Before download or import, verify
that the asset page is marked free or that the asset is project-owned/internal.
Record the cost in `Docs/Art/AssetLicenses.md` as `Free`, `$0`, `0`, or `N/A`.
Do not click purchase, checkout, add payment, subscription, or paid-license
flows. If an asset looks useful but is not free, record it as a candidate in
notes outside the import flow and wait for explicit approval.
## Staging Workflow ## Staging Workflow
1. Place downloaded/manual assets in: 1. Place downloaded/manual assets in:
+12 -2
View File
@@ -5,8 +5,8 @@ before it is used in a playable map, packaged demo, screenshot, or trailer.
Allowed default sources: Allowed default sources:
- Fab assets explicitly marked free or otherwise purchased/owned for this - Fab assets explicitly marked free. Paid Fab assets are blocked unless Nathan
project. explicitly approves a purchase in a later task.
- Quixel/Megascans assets available under the current Epic/Unreal terms for - Quixel/Megascans assets available under the current Epic/Unreal terms for
this project. this project.
- CC0 or public-domain assets. - CC0 or public-domain assets.
@@ -30,6 +30,16 @@ Expected subfolders:
- `Processed`: assets imported, optimized, renamed, and verified. - `Processed`: assets imported, optimized, renamed, and verified.
- `Rejected`: assets that should not be used. - `Rejected`: assets that should not be used.
## Free-Only Acquisition Gate
Until Nathan explicitly approves a paid purchase, every third-party asset must
have `Cost` recorded as `Free`, `$0`, `0`, or `N/A` for project-owned/internal
assets. Do not use "purchased", "paid", a dollar amount above zero, or blank
cost values in the register.
Any asset with uncertain cost, marketplace bundle requirements, subscription
requirements, or unclear entitlement belongs in `Rejected` until reviewed.
## Naming Policy ## Naming Policy
Use project-readable names before import: Use project-readable names before import:
+66
View File
@@ -0,0 +1,66 @@
#!/usr/bin/env python3
"""Fail if tracked Agrarian assets include paid or unclear costs."""
from pathlib import Path
ROOT = Path(__file__).resolve().parents[1]
REGISTER = ROOT / "Docs" / "Art" / "AssetLicenses.md"
ALLOWED_COSTS = {"free", "$0", "0", "n/a", "na"}
BLOCKED_WORDS = {
"paid",
"purchased",
"purchase",
"subscription",
"unknown",
"unclear",
"tbd",
"marketplace bundle",
}
def parse_markdown_table_rows(text: str) -> list[list[str]]:
rows: list[list[str]] = []
for line in text.splitlines():
stripped = line.strip()
if not stripped.startswith("|") or "---" in stripped:
continue
cells = [cell.strip() for cell in stripped.strip("|").split("|")]
if cells and cells[0] != "Asset":
rows.append(cells)
return rows
def main() -> None:
if not REGISTER.exists():
raise SystemExit(f"Missing asset license register: {REGISTER}")
rows = parse_markdown_table_rows(REGISTER.read_text(encoding="utf-8"))
failures: list[str] = []
for row in rows:
if len(row) < 5:
failures.append(f"Malformed asset license row: {' | '.join(row)}")
continue
asset = row[0]
cost = row[4].strip().lower()
full_row = " ".join(row).lower()
if not cost:
failures.append(f"{asset}: cost is blank")
elif cost not in ALLOWED_COSTS:
failures.append(f"{asset}: cost {row[4]!r} is not free-only")
for blocked in BLOCKED_WORDS:
if blocked in full_row:
failures.append(f"{asset}: blocked free-only word found: {blocked!r}")
if failures:
raise SystemExit("\n".join(failures))
print(f"Asset license free-only verification complete: {len(rows)} entries.")
if __name__ == "__main__":
main()
+4
View File
@@ -12,12 +12,16 @@ REQUIRED = {
"CC0 or public-domain", "CC0 or public-domain",
"/home/nathan/AssetStaging/Agrarian", "/home/nathan/AssetStaging/Agrarian",
"Do not import random internet images", "Do not import random internet images",
"Free-Only Acquisition Gate",
"Paid Fab assets are blocked",
"Native Ground Zero proxy vegetation", "Native Ground Zero proxy vegetation",
], ],
"Docs/Art/AgrarianAssetPipeline.md": [ "Docs/Art/AgrarianAssetPipeline.md": [
"realistic modern post-collapse frontier survival", "realistic modern post-collapse frontier survival",
"Old abandoned equipment", "Old abandoned equipment",
"Do not scrape random internet images or models", "Do not scrape random internet images or models",
"Free-Only Lockdown",
"Do not click purchase",
"LicenseEvidence", "LicenseEvidence",
"Run visual and placeholder verifiers", "Run visual and placeholder verifiers",
"Water should be handled as a shader/system problem", "Water should be handled as a shader/system problem",