Revert "chore(assets): regen character manifest — was stale since the wardrobe landed"
This reverts commit 04241989b. The premise was wrong: the manifest is not
stale, it is AHEAD of its generator.
Both versions list the same 24 garments. What the regen dropped is the
`style` and `logo_capable` fields that T-1089 added to the manifest schema
but never taught `generate-character-manifest` to emit. So the generator
faithfully reproduces a manifest that is missing half its schema, and
`test_garment_engine_t1089.gd` catches it — which is how this was found, on
the push gate rather than in review.
`make manifest` is therefore a trap for anyone who runs it: it silently
reverts the T-1089 extension. Filed as T-1287.
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
This commit is contained in:
@@ -120,3 +120,38 @@ worktree refusals — none of them performed. Every assertion was mutation-check
|
||||
|
||||
Gate: `ruff check tooling/` clean, `make test-tooling` PASS (12 checks).', NULL, '2026-09-02 14:54:35', '2026-09-02 14:54:35.578', '2026-09-02 14:54:35.578', NULL, 'e0bd8f1d16b2dc7c7d1b8b1511633cc3', 2) ON CONFLICT(hash) DO NOTHING;
|
||||
INSERT INTO ticket_history (ticket_record_id, field, old_value, new_value, changed_by, changed_at, created_at, updated_at, deleted_at, hash, canonical_version) VALUES ('06G64ASTXBBHMWMBQSVPM9MK1W', 'status', 'backlog', 'done', NULL, '2026-09-02 14:54:37', '2026-09-02 14:54:37.762', '2026-09-02 14:54:37.762', NULL, '5f9240c61aa2bf03924e4edaf4dd6f7c', 2) ON CONFLICT(hash) DO NOTHING;
|
||||
INSERT INTO ticket_history (ticket_record_id, field, old_value, new_value, changed_by, changed_at, created_at, updated_at, deleted_at, hash, canonical_version) VALUES ('06G65N2W393K7A4B8JA8FGP22R', 'description', NULL, '`generate-character-manifest` (now `reach generate character-manifest`) emits
|
||||
only `{"slot": ...}` per clothing entry. The committed
|
||||
`client/assets/characters/manifest.json` also carries `style` and
|
||||
`logo_capable`, added to the schema by T-1089 — the generator was never taught
|
||||
to produce them.
|
||||
|
||||
So the artifact is AHEAD of its generator, and `make manifest` silently reverts
|
||||
the T-1089 extension. Confirmed on 2026-09-02: a regen produced the same 24
|
||||
garments with those two fields dropped, and `test_garment_engine_t1089.gd >
|
||||
test_manifest_has_tshirt_with_style_and_logo_flag` failed on the push gate.
|
||||
Reverted in 6024045fc.
|
||||
|
||||
This is the exact failure mode `.claude/rules/asset-pipeline.md` exists to
|
||||
prevent, one directory over: an artifact that cannot be reproduced from its
|
||||
source. The manifest is not covered by that rule (no meta stamp, not
|
||||
systems.db), which is why it drifted unnoticed.
|
||||
|
||||
WHAT TO DECIDE FIRST — where do `style` and `logo_capable` come from? They are
|
||||
not derivable from a filename. Either:
|
||||
(a) a sidecar the generator reads (e.g. the clothing `coverage.json` already
|
||||
beside the assets, or per-garment metadata), or
|
||||
(b) the manifest is genuinely hand-maintained, in which case the generator
|
||||
should MERGE rather than overwrite, and say so.
|
||||
|
||||
(a) is the asset-pipeline-consistent answer. (b) needs the generator to stop
|
||||
claiming to be the source of truth.
|
||||
|
||||
ALSO: `test_garment_engine_t1089.gd:108` reports `Expecting ''modern'' but was
|
||||
''modern''` — the strings print identically, so the assertion is comparing
|
||||
something other than what it displays (String vs StringName, or a trailing
|
||||
character). Worth a look while in there; a failure message that shows two
|
||||
identical values costs whoever hits it real time.
|
||||
|
||||
Acceptance: `reach generate character-manifest` on a clean tree leaves
|
||||
manifest.json byte-identical, and the T-1089 test still passes after it runs.', NULL, '2026-09-02 15:54:41', '2026-09-02 15:54:41.911', '2026-09-02 15:54:41.911', NULL, '1a36359b2986139da3157d2429351f74', 2) ON CONFLICT(hash) DO NOTHING;
|
||||
|
||||
@@ -1,3 +1,4 @@
|
||||
INSERT INTO ticket_idmap (record_id, ticket_id, created_at, updated_at, deleted_at, hash, canonical_version) VALUES ('06G63FEA51J4JKE3A7473D3QZ0', 'T-1284', '2026-09-02 10:50:23.145', '2026-09-02 10:50:23.145', NULL, '74113524e3a280bd06875305a547349a', 2) ON CONFLICT(record_id) DO UPDATE SET ticket_id=excluded.ticket_id, updated_at=excluded.updated_at, deleted_at=excluded.deleted_at, hash=excluded.hash, canonical_version=excluded.canonical_version WHERE excluded.updated_at >= ticket_idmap.updated_at;
|
||||
INSERT INTO ticket_idmap (record_id, ticket_id, created_at, updated_at, deleted_at, hash, canonical_version) VALUES ('06G642RKW8PNW7AP9BY9203SPG', 'T-1285', '2026-09-02 12:14:48.290', '2026-09-02 12:14:48.290', NULL, '020f491d1ae8fbde83d2aae0f8325011', 2) ON CONFLICT(record_id) DO UPDATE SET ticket_id=excluded.ticket_id, updated_at=excluded.updated_at, deleted_at=excluded.deleted_at, hash=excluded.hash, canonical_version=excluded.canonical_version WHERE excluded.updated_at >= ticket_idmap.updated_at;
|
||||
INSERT INTO ticket_idmap (record_id, ticket_id, created_at, updated_at, deleted_at, hash, canonical_version) VALUES ('06G64ASTXBBHMWMBQSVPM9MK1W', 'T-1286', '2026-09-02 12:49:55.434', '2026-09-02 12:49:55.434', NULL, '7c65442cc261176c9c472fdbd635cc91', 2) ON CONFLICT(record_id) DO UPDATE SET ticket_id=excluded.ticket_id, updated_at=excluded.updated_at, deleted_at=excluded.deleted_at, hash=excluded.hash, canonical_version=excluded.canonical_version WHERE excluded.updated_at >= ticket_idmap.updated_at;
|
||||
INSERT INTO ticket_idmap (record_id, ticket_id, created_at, updated_at, deleted_at, hash, canonical_version) VALUES ('06G65N2W393K7A4B8JA8FGP22R', 'T-1287', '2026-09-02 15:54:39.514', '2026-09-02 15:54:39.514', NULL, 'de690eafa611669d722b0ffb850a1d7b', 2) ON CONFLICT(record_id) DO UPDATE SET ticket_id=excluded.ticket_id, updated_at=excluded.updated_at, deleted_at=excluded.deleted_at, hash=excluded.hash, canonical_version=excluded.canonical_version WHERE excluded.updated_at >= ticket_idmap.updated_at;
|
||||
|
||||
@@ -229,3 +229,39 @@ worktree refusals — none of them performed. Every assertion was mutation-check
|
||||
unrecognised verdict and blocked the push.
|
||||
|
||||
Gate: `ruff check tooling/` clean, `make test-tooling` PASS (12 checks).', 'done', 'medium', NULL, NULL, 'D-263', '2026-09-02 12:49:55.434', '2026-09-02 14:54:37.762', NULL, '678c0d0578c2255438d2e51829d87a64', 2) ON CONFLICT(record_id) DO UPDATE SET type=excluded.type, parent_record_id=excluded.parent_record_id, title=excluded.title, description=excluded.description, status=excluded.status, priority=excluded.priority, assigned_to=excluded.assigned_to, team=excluded.team, decision_ref=excluded.decision_ref, updated_at=excluded.updated_at, deleted_at=excluded.deleted_at, hash=excluded.hash, canonical_version=excluded.canonical_version WHERE excluded.updated_at >= tickets.updated_at;
|
||||
INSERT INTO tickets (record_id, type, parent_record_id, title, description, status, priority, assigned_to, team, decision_ref, created_at, updated_at, deleted_at, hash, canonical_version) VALUES ('06G65N2W393K7A4B8JA8FGP22R', 'bug', '06FBPPMZNNEV052DBYYY3A897C', 'make manifest silently drops the T-1089 garment schema fields', NULL, 'backlog', 'medium', NULL, 'client', NULL, '2026-09-02 15:54:39.514', '2026-09-02 15:54:39.514', NULL, 'ddb9c65aa4c4537924de591c4c017051', 2) ON CONFLICT(record_id) DO UPDATE SET type=excluded.type, parent_record_id=excluded.parent_record_id, title=excluded.title, description=excluded.description, status=excluded.status, priority=excluded.priority, assigned_to=excluded.assigned_to, team=excluded.team, decision_ref=excluded.decision_ref, updated_at=excluded.updated_at, deleted_at=excluded.deleted_at, hash=excluded.hash, canonical_version=excluded.canonical_version WHERE excluded.updated_at >= tickets.updated_at;
|
||||
INSERT INTO tickets (record_id, type, parent_record_id, title, description, status, priority, assigned_to, team, decision_ref, created_at, updated_at, deleted_at, hash, canonical_version) VALUES ('06G65N2W393K7A4B8JA8FGP22R', 'bug', '06FBPPMZNNEV052DBYYY3A897C', 'make manifest silently drops the T-1089 garment schema fields', '`generate-character-manifest` (now `reach generate character-manifest`) emits
|
||||
only `{"slot": ...}` per clothing entry. The committed
|
||||
`client/assets/characters/manifest.json` also carries `style` and
|
||||
`logo_capable`, added to the schema by T-1089 — the generator was never taught
|
||||
to produce them.
|
||||
|
||||
So the artifact is AHEAD of its generator, and `make manifest` silently reverts
|
||||
the T-1089 extension. Confirmed on 2026-09-02: a regen produced the same 24
|
||||
garments with those two fields dropped, and `test_garment_engine_t1089.gd >
|
||||
test_manifest_has_tshirt_with_style_and_logo_flag` failed on the push gate.
|
||||
Reverted in 6024045fc.
|
||||
|
||||
This is the exact failure mode `.claude/rules/asset-pipeline.md` exists to
|
||||
prevent, one directory over: an artifact that cannot be reproduced from its
|
||||
source. The manifest is not covered by that rule (no meta stamp, not
|
||||
systems.db), which is why it drifted unnoticed.
|
||||
|
||||
WHAT TO DECIDE FIRST — where do `style` and `logo_capable` come from? They are
|
||||
not derivable from a filename. Either:
|
||||
(a) a sidecar the generator reads (e.g. the clothing `coverage.json` already
|
||||
beside the assets, or per-garment metadata), or
|
||||
(b) the manifest is genuinely hand-maintained, in which case the generator
|
||||
should MERGE rather than overwrite, and say so.
|
||||
|
||||
(a) is the asset-pipeline-consistent answer. (b) needs the generator to stop
|
||||
claiming to be the source of truth.
|
||||
|
||||
ALSO: `test_garment_engine_t1089.gd:108` reports `Expecting ''modern'' but was
|
||||
''modern''` — the strings print identically, so the assertion is comparing
|
||||
something other than what it displays (String vs StringName, or a trailing
|
||||
character). Worth a look while in there; a failure message that shows two
|
||||
identical values costs whoever hits it real time.
|
||||
|
||||
Acceptance: `reach generate character-manifest` on a clean tree leaves
|
||||
manifest.json byte-identical, and the T-1089 test still passes after it runs.', 'backlog', 'medium', NULL, 'client', NULL, '2026-09-02 15:54:39.514', '2026-09-02 15:54:41.911', NULL, '2f6393f44525977bfeba1200e8f79561', 2) ON CONFLICT(record_id) DO UPDATE SET type=excluded.type, parent_record_id=excluded.parent_record_id, title=excluded.title, description=excluded.description, status=excluded.status, priority=excluded.priority, assigned_to=excluded.assigned_to, team=excluded.team, decision_ref=excluded.decision_ref, updated_at=excluded.updated_at, deleted_at=excluded.deleted_at, hash=excluded.hash, canonical_version=excluded.canonical_version WHERE excluded.updated_at >= tickets.updated_at;
|
||||
|
||||
@@ -46,33 +46,6 @@
|
||||
"thick"
|
||||
],
|
||||
"clothing": {
|
||||
"boots_modern": {
|
||||
"slot": "feet"
|
||||
},
|
||||
"buttondown_modern": {
|
||||
"slot": "torso"
|
||||
},
|
||||
"cargo_pants": {
|
||||
"slot": "legs"
|
||||
},
|
||||
"hoodie_modern": {
|
||||
"slot": "torso"
|
||||
},
|
||||
"jacket_modern": {
|
||||
"slot": "torso"
|
||||
},
|
||||
"jeans_modern": {
|
||||
"slot": "torso"
|
||||
},
|
||||
"joggers_modern": {
|
||||
"slot": "torso"
|
||||
},
|
||||
"pants_formal": {
|
||||
"slot": "legs"
|
||||
},
|
||||
"parka_thrds": {
|
||||
"slot": "torso"
|
||||
},
|
||||
"peasant_pants": {
|
||||
"slot": "legs"
|
||||
},
|
||||
@@ -82,41 +55,289 @@
|
||||
"peasant_tunic": {
|
||||
"slot": "torso"
|
||||
},
|
||||
"shoes_formal": {
|
||||
"slot": "feet"
|
||||
"tshirt_modern": {
|
||||
"slot": "torso",
|
||||
"style": "modern",
|
||||
"logo_capable": true
|
||||
},
|
||||
"hoodie_modern": {
|
||||
"slot": "torso",
|
||||
"style": "modern",
|
||||
"logo_capable": true
|
||||
},
|
||||
"buttondown_modern": {
|
||||
"slot": "torso",
|
||||
"style": "modern",
|
||||
"logo_capable": false
|
||||
},
|
||||
"shorts_modern": {
|
||||
"slot": "legs"
|
||||
"slot": "legs",
|
||||
"style": "modern",
|
||||
"logo_capable": false
|
||||
},
|
||||
"slides": {
|
||||
"slot": "torso"
|
||||
"jeans_modern": {
|
||||
"slot": "legs",
|
||||
"style": "modern",
|
||||
"logo_capable": false
|
||||
},
|
||||
"sneakers_modern": {
|
||||
"slot": "torso"
|
||||
"pants_formal": {
|
||||
"slot": "legs",
|
||||
"style": "formal",
|
||||
"logo_capable": false
|
||||
},
|
||||
"jacket_modern": {
|
||||
"slot": "torso",
|
||||
"style": "modern",
|
||||
"logo_capable": true
|
||||
},
|
||||
"suit_jacket_black": {
|
||||
"slot": "torso"
|
||||
},
|
||||
"sweater_modern": {
|
||||
"slot": "torso"
|
||||
},
|
||||
"swim_trunks": {
|
||||
"slot": "torso"
|
||||
},
|
||||
"swimsuit_onepiece": {
|
||||
"slot": "torso"
|
||||
},
|
||||
"tank_top": {
|
||||
"slot": "torso"
|
||||
},
|
||||
"track_jacket": {
|
||||
"slot": "torso"
|
||||
},
|
||||
"tshirt_modern": {
|
||||
"slot": "torso"
|
||||
"slot": "torso",
|
||||
"style": "formal",
|
||||
"logo_capable": false,
|
||||
"regions": {
|
||||
"R": "lapels_collar",
|
||||
"G": "jacket_body",
|
||||
"B": "sleeves",
|
||||
"A": "shirt_triangle"
|
||||
},
|
||||
"default_tints": [
|
||||
[
|
||||
0.13,
|
||||
0.13,
|
||||
0.16,
|
||||
1
|
||||
],
|
||||
[
|
||||
0.09,
|
||||
0.09,
|
||||
0.11,
|
||||
1
|
||||
],
|
||||
[
|
||||
0.09,
|
||||
0.09,
|
||||
0.11,
|
||||
1
|
||||
],
|
||||
[
|
||||
0.93,
|
||||
0.93,
|
||||
0.96,
|
||||
1
|
||||
]
|
||||
]
|
||||
},
|
||||
"uniform_utility": {
|
||||
"slot": "torso"
|
||||
"slot": "full_body",
|
||||
"style": "utility",
|
||||
"logo_capable": true,
|
||||
"default_tints": [
|
||||
"#3b474f",
|
||||
"#6b8280",
|
||||
"#d18c2e",
|
||||
"#d9dee0"
|
||||
]
|
||||
},
|
||||
"tank_top": {
|
||||
"slot": "torso",
|
||||
"style": "modern",
|
||||
"logo_capable": true,
|
||||
"regions": {
|
||||
"R": "collar_band",
|
||||
"G": "body",
|
||||
"B": "armhole_trim"
|
||||
},
|
||||
"default_tints": [
|
||||
"#f5f2eb",
|
||||
"#e8693b",
|
||||
"#f5f2eb",
|
||||
"#ffffff"
|
||||
]
|
||||
},
|
||||
"sweater_modern": {
|
||||
"slot": "torso",
|
||||
"style": "modern",
|
||||
"logo_capable": false,
|
||||
"regions": {
|
||||
"R": "collar",
|
||||
"G": "body",
|
||||
"B": "cuffs_hem"
|
||||
},
|
||||
"default_tints": [
|
||||
"#946b4f",
|
||||
"#b8916e",
|
||||
"#946b4f",
|
||||
"#ffffff"
|
||||
]
|
||||
},
|
||||
"track_jacket": {
|
||||
"slot": "torso",
|
||||
"style": "sport",
|
||||
"logo_capable": true,
|
||||
"multi_region": true,
|
||||
"regions": {
|
||||
"R": "stand_collar",
|
||||
"G": "body",
|
||||
"B": "sleeve_stripes",
|
||||
"A": "cuffs_hem_band"
|
||||
},
|
||||
"default_tints": [
|
||||
"#ebedf2",
|
||||
"#294d9e",
|
||||
"#f0f2f7",
|
||||
"#1a2652"
|
||||
]
|
||||
},
|
||||
"joggers_modern": {
|
||||
"slot": "legs",
|
||||
"style": "modern",
|
||||
"logo_capable": false
|
||||
},
|
||||
"cargo_pants": {
|
||||
"slot": "legs",
|
||||
"style": "modern",
|
||||
"logo_capable": false
|
||||
},
|
||||
"swim_trunks": {
|
||||
"slot": "legs",
|
||||
"style": "modern",
|
||||
"logo_capable": false
|
||||
},
|
||||
"swimsuit_onepiece": {
|
||||
"slot": "full_body",
|
||||
"style": "modern",
|
||||
"logo_capable": false,
|
||||
"regions": {
|
||||
"R": "straps_trim",
|
||||
"G": "body",
|
||||
"B": "side_blocks"
|
||||
},
|
||||
"default_tints": [
|
||||
"#f2f0e8",
|
||||
"#e34a33",
|
||||
"#1f7a8c",
|
||||
"#ffffff"
|
||||
]
|
||||
},
|
||||
"sneakers_modern": {
|
||||
"slot": "feet",
|
||||
"style": "modern",
|
||||
"logo_capable": false,
|
||||
"multi_region": true,
|
||||
"regions": {
|
||||
"R": "sole",
|
||||
"G": "upper",
|
||||
"B": "laces_trim"
|
||||
},
|
||||
"default_tints": [
|
||||
"#bdc0c4",
|
||||
"#ebebee",
|
||||
"#e1e1e6"
|
||||
]
|
||||
},
|
||||
"shoes_formal": {
|
||||
"slot": "feet",
|
||||
"style": "formal",
|
||||
"logo_capable": false,
|
||||
"regions": {
|
||||
"R": "sole",
|
||||
"G": "upper",
|
||||
"B": "toe_cap"
|
||||
},
|
||||
"default_tints": [
|
||||
[
|
||||
0.1,
|
||||
0.1,
|
||||
0.11,
|
||||
1
|
||||
],
|
||||
[
|
||||
0.07,
|
||||
0.07,
|
||||
0.08,
|
||||
1
|
||||
],
|
||||
[
|
||||
0.07,
|
||||
0.07,
|
||||
0.08,
|
||||
1
|
||||
],
|
||||
[
|
||||
1,
|
||||
1,
|
||||
1,
|
||||
1
|
||||
]
|
||||
]
|
||||
},
|
||||
"boots_modern": {
|
||||
"slot": "feet",
|
||||
"style": "modern",
|
||||
"logo_capable": false,
|
||||
"regions": {
|
||||
"R": "sole",
|
||||
"G": "upper_shaft",
|
||||
"B": "laces_eyelets"
|
||||
},
|
||||
"default_tints": [
|
||||
"#292624",
|
||||
"#704a2e",
|
||||
"#382e26",
|
||||
"#ffffff"
|
||||
]
|
||||
},
|
||||
"slides": {
|
||||
"slot": "feet",
|
||||
"style": "modern",
|
||||
"logo_capable": false,
|
||||
"regions": {
|
||||
"R": "sole",
|
||||
"G": "strap"
|
||||
},
|
||||
"default_tints": [
|
||||
[
|
||||
0.82,
|
||||
0.83,
|
||||
0.85,
|
||||
1
|
||||
],
|
||||
[
|
||||
0.93,
|
||||
0.35,
|
||||
0.2,
|
||||
1
|
||||
],
|
||||
[
|
||||
1,
|
||||
1,
|
||||
1,
|
||||
1
|
||||
],
|
||||
[
|
||||
1,
|
||||
1,
|
||||
1,
|
||||
1
|
||||
]
|
||||
]
|
||||
},
|
||||
"parka_thrds": {
|
||||
"slot": "torso",
|
||||
"style": "modern",
|
||||
"logo_capable": true,
|
||||
"regions": {
|
||||
"R": "hood_roll_collar",
|
||||
"G": "body",
|
||||
"B": "sleeves",
|
||||
"A": "pocket_quilt_trim"
|
||||
},
|
||||
"default_tints": [
|
||||
"#384257",
|
||||
"#4d5973",
|
||||
"#455269",
|
||||
"#788599"
|
||||
]
|
||||
}
|
||||
},
|
||||
"accessories": []
|
||||
|
||||
Reference in New Issue
Block a user