# REPORT-F: which app/game uses which asset

## What changed (plain words)
You can now ask both ways: "which games use this asset" and "which assets does this game use".
Today's data was backfilled from the Factory database and from the hand-built game folders on this box.

- `usage/by_asset.json`, `usage/by_app.json`: the answer files. `usage/backfill/*.jsonl`: the events behind them.
- `tools/usage_index.py`: folds events into the two files (dupes collapse; versions, first/last seen, sources kept).
- `tools/usage_backfill.py` + `tools/usage_db_query.sh`: the backfill (DB briefs, GLB sha256 match, id/sha text refs).
- `tools/usage_pull.sh`: pulls gex44's ledger + re-queries briefs (read-only), then rebuilds. Run it any time.
- `tools/asset_usage.py`, and `asset-search --uses <asset-id>` / `--used-by <slug>` (lib/search.py, 2 lines).
- `tools/build_index.py`: each index row gets `used_by {count, slugs[:10]}`; search hits carry it, text output shows "used by N".
- `omg/factory/library_usage.py`: `record(picks, user, platform, source)`; never raises, never blocks a build.
- `usage/bulk_users.json`: engine/kit trees that vendor the whole library (fge-*, forge-game-engine, forge-repaint). Listed, not counted in `used_by`.

## Where assets enter builds (sources)
| source | what | read? |
|---|---|---|
| OMG Factory `games_library.library_attachments` -> `build_pack` | picks become a tar pack; `meta.game_library` on the brief keeps `releases[]` (release hashes) | yes: DB `app_briefs.meta`, join `pipeline_runs.project_slug` |
| hand games (MOEBELKRIG ikea-fps, inkfall, omg-cast, aaa-arms, kite, casa13...) | GLBs copied in; matched by sha256 of the file, plus text mentions of id or glb sha | yes, scanned ~/forge-build |
| deployed game containers on box1 (126 containers) | pack is baked into the image | NOT read (no manifest on disk; DB already has the releases) |
| OMU Engine app builds (ax42) | no library path exists yet (Part C adds it) | nothing to read yet |
| gex44 `assets.lock.json` files | only one found, a /tmp kit copy | n/a |

## Backfill numbers
330 of 454 assets used; 51 users: 27 OMG games (257 events, all 27 briefs with a pack, 0 unknown releases), 24 hand folders (3028 events), 0 OMU apps.
Top reuse: harbour boulders/rocks, 10-11 users each. Hand matches: 1554 by GLB hash, 1474 by text ref.

## Writable path (NOT applied)
`/srv/forge-assets` is mounted `:ro` in the Factory (`deploy.sh:375`; confirmed `touch` fails). No mount change needed:
`/var/lib/forge-corp` is already mounted read-write and has dirs owned by uid 1000 (the container user). Proposal:
`mkdir /var/lib/forge-corp/library-usage && chown 1000:1000 /var/lib/forge-corp/library-usage` on gex44 (one host command). Default ledger path in `library_usage.py` is `/var/lib/forge-corp/library-usage/events.jsonl`.

## Call site (leave to lead; games_library.py is being edited elsewhere)
In `library_attachments`, right after `picks, classes, gaps = pick(...)` succeeds and `build_pack` returns:
```python
from . import library_usage  # top of file
library_usage.record(picks, user=user_id)   # user_id: new optional kwarg, e.g. brief id
```
Catch: at that point the project slug does not exist yet (only the brief). Record `user=f"brief:{id[:8]}"`; the DB backfill already maps brief to slug, so for OMG the DB re-pull alone is enough and the ledger mostly matters for OMU/Engine and for packs rebuilt without a brief row.

## Tests
`python3 -m pytest test/test_usage_index.py`: 5 passed (fold, dedupe, both directions, bulk, junk lines, record never raises).
Checked by hand: build_index with usage gives 315 rows with `used_by`; `asset-search --uses/--used-by` print rows.

## What would break / NOT done
- `index.json` in this branch was NOT regenerated (other workers touch it; rebuild after merge: `python3 tools/build_index.py`).
- Hand-scan "used" = a GLB identical to a library blob or an id/sha mentioned in text; it cannot tell a game that ships a copy from one that loads it, and docs mentioning ids count (source tag `text-ref` tells you).
- Users for OMG are project slugs (`p01c2cd9c`), not titles; titles are in `usage/briefs.json`.
- Not read: box1 containers, ax42 Engine apps, hand games outside ~/forge-build, OMU (none yet). Nothing applied on any server.
- `usage/briefs.json` is a snapshot of brief titles/slugs (27 rows, no user data beyond ids).
