The Layer-5 batch — building-exterior visual grammar, material fill onto the shell, ops-surface tagging, and the region transient-state D-record. Advances T-750 (Phase 4) toward the T-962 walkable-world gate.
T-988 — BuildingExteriorTag grammar (authored-depth v1). New trait_exterior.rs: 3-step era-free derivation (visual_bundle filter → zone-bias weighted pick → density→setback), color seed-sampled within the template's register band. Resolved at GenerateSkeleton (T-994 precedent), frozen on BuildingPropertyTag; FillChunk only reads it. Four append-only integer-discriminant material enums; trait_catalog_reader now parses visual_bundle + two new tables (OnceLock-cached); new SeedDomain::TraitExterior with per-axis sub-chains (no cross-field correlation). Content authored by Miri (zone-bias, 57 sparse entries) + Araminta (28 color bands), baked into systems.db with V-TT-06/07 importer validation (token-in-bundle, coverage + integer HSV bounds).
T-959 — Layer-5 material fill. FillChunk reads the frozen exterior tag → wall/roof materials onto Wall/Roof shell voxels (FilledChunk.surface_material), purely additive. Interstitial-fill-from-setback split to T-1098 (needs a FillChunk block-metadata + geometry design pass; nothing consumes FillChunk until Phase 5).
T-1097 — ops-surface.BlockSkeleton.interstitial_character (OpenSpace | OperationsSurface), D-233 bulk-driven: bulk-industry blocks' non-roofed remainder tags as built economic infrastructure.
T-1057 — D-253 (resolves Q-105): region transient state model — four clock terms (diurnal/tidal/weather/seasonal), memoized-by-bucket absolute-clock evaluation, edge-fuzzed per-tile inheritance, integer-deterministic, state-model-only. Q-102 resolved-in-practice; Q-103/Q-109 deferred to Phase 5+.
Verification
Full pre-push gate green: cargo fmt --check, cargo clippy --all-targets -D warnings, 1666 lib tests, make test-tooling (incl. new V-TT-05/06/07 failure-branch units), cargo deny, fresh systems.db stamp. No golden impact (harnesses top out at CascadeLayer::RoadGraph — Layer 4/5 is structurally unreachable).
Ratified content baked into systems.db as two new tables:
- architecture_zone_bias (57 rows): sparse per-template, per-zone_type
token-weight overrides (integer bps), Miri-authored — the D-235 step-2
zone bias. V-TT-06: every token must exist in that template's own
visual_bundle axis.
- color_register_bands (28 rows): per color_register integer HSV bands
(hue centidegrees, sat/val bps), Araminta-authored. V-TT-07: full
catalog coverage + valid integer bounds (min<max, in range).
Both TOMLs registered in generator_sources (stamp coverage); DDL in
systems-schema.sql + migration.py; validation wired into import_economics
steps 18/19 and test_traits.py failure-branch units (make test-tooling).
systems.db regenerated + re-stamped.
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
T-988 — BuildingExteriorTag {wall_material, roof_form, facade_rhythm,
setback_tier, color:HsvColor, street_surface}. New trait_exterior.rs:
3-step era-free derivation (visual_bundle filter -> zone-bias weighted
pick -> density->setback), color seed-sampled within the register band.
Resolved at GenerateSkeleton plan time (T-994 precedent), frozen on
BuildingPropertyTag; FillChunk only reads it. Four append-only
integer-discriminant enums (WallMaterial/RoofForm/FacadeRhythm/
StreetSurface), unknown token -> axis Generic + warn. trait_catalog_reader
now parses visual_bundle + the two new tables (OnceLock-cached).
New SeedDomain::TraitExterior (per-axis sub-chains — no cross-field
correlation).
T-959 — FillChunk reads the frozen exterior tag: wall_material/roof_form
onto Wall/Roof shell voxels (FilledChunk.surface_material). Additive,
ShellVoxel untouched, all shell tests pass. (Interstitial-fill-from-setback
split to T-1098 — needs a FillChunk block-metadata + geometry design pass;
nothing consumes FillChunk until Phase 5.)
T-1097 — BlockSkeleton.interstitial_character (OpenSpace|OperationsSurface),
D-233 bulk-driven: bulk-industry blocks' non-roofed remainder tags as built
economic infrastructure, not generic open space.
cargo check --all-targets clean; 1666 lib tests pass; no golden impact
(harnesses top out at CascadeLayer::RoadGraph, unreachable by Layer 4/5).
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Reviewers: Hoshe (code quality), Tyre (architecture) — both read the branch worktree at 204359927.
Hoshe (Code Quality): REQUEST_CHANGES
The trait_exterior.rs derivation is careful, integer-only, correctly domain-separates its seven per-axis RNG sub-chains, and every content-gap path degrades to Generic/neutral (all tested). shell.rs surface_material is cleanly additive (ShellVoxel untouched). Two robustness gaps in the new importer validation block approval.
#
File
Issue
H1
tooling/economy-db/economy_import/traits.py:313
populate_architecture_zone_bias: a non-dict axis value (wall = 15000, or the array-shaped wall = ["steel_frame"] copy-paste from the sibling catalog's visual_bundle) hits (weights or {}).items() → bare AttributeError, not the clean V-TT-06 error every other malformed shape produces. The function guards zone_map (line 294) and axes (line 300) are dicts but never the per-axis weights. import_economics rolls back so no DB corruption, but the user gets a traceback instead of an actionable stanza pointer. Untested branch. Fix: isinstance(weights, dict) guard mirroring the two above it.
H2
tooling/economy-db/economy_import/traits.py:319
if not isinstance(weight, int) or weight <= 0 doesn't exclude bool (an int subclass) — weight = true passes as 1. populate_color_register_bands explicitly guards this same footgun for its own values; match it.
Tyre (Architecture): APPROVE
No comments. Independently verified: D-253 is internally consistent and correctly scoped (adds the time dimension over T-1078's spatial baseline, does not touch the D-243 spatial stack; scope boundary explicitly excludes gameplay/passability/rendering); Q-102/103/109 citations check out against D-246/D-228 and shipped shell.rs; determinism clean (no HashMap, no floats, integer-only draws); SeedDomain::TraitExterior = 16 appended + pinned; seven independent seed sub-axes off fp_chain, zero shared rolls; schema/migration/generator_sources all paired; ExteriorCatalog clone is launch-bounded in the no-budget plan phase; zero bare unwrap/expect/panic in new production paths; the T-1097 BlockSkeleton relocation and the T-1098 deferred-interstitial seam are both architecturally clean.
Verdict: CHANGES REQUESTED
H1 + H2 are isolated Python hardening (+ their missing tests) in one importer function. Fixing now.
Process notes: no client/merge-path touched (server + tooling + governance only). Runtime verification = the full pre-push gate (clippy -D warnings, 1666 lib tests, make test-tooling incl. V-TT failure-branch units, cargo deny, fresh stamp). No golden impact.
## Review: layer5-tile-fill → main (type: code)
Reviewers: Hoshe (code quality), Tyre (architecture) — both read the branch worktree at `204359927`.
### Hoshe (Code Quality): REQUEST_CHANGES
The `trait_exterior.rs` derivation is careful, integer-only, correctly domain-separates its seven per-axis RNG sub-chains, and every content-gap path degrades to Generic/neutral (all tested). `shell.rs` surface_material is cleanly additive (ShellVoxel untouched). Two robustness gaps in the new importer validation block approval.
| # | File | Issue |
|---|------|-------|
| H1 | `tooling/economy-db/economy_import/traits.py:313` | `populate_architecture_zone_bias`: a non-dict axis value (`wall = 15000`, or the array-shaped `wall = ["steel_frame"]` copy-paste from the sibling catalog's `visual_bundle`) hits `(weights or {}).items()` → bare `AttributeError`, not the clean `V-TT-06` error every other malformed shape produces. The function guards `zone_map` (line 294) and `axes` (line 300) are dicts but never the per-axis `weights`. `import_economics` rolls back so no DB corruption, but the user gets a traceback instead of an actionable stanza pointer. Untested branch. Fix: `isinstance(weights, dict)` guard mirroring the two above it. |
| H2 | `tooling/economy-db/economy_import/traits.py:319` | `if not isinstance(weight, int) or weight <= 0` doesn't exclude `bool` (an int subclass) — `weight = true` passes as 1. `populate_color_register_bands` explicitly guards this same footgun for its own values; match it. |
### Tyre (Architecture): APPROVE
No comments. Independently verified: D-253 is internally consistent and correctly scoped (adds the *time* dimension over T-1078's spatial baseline, does not touch the D-243 spatial stack; scope boundary explicitly excludes gameplay/passability/rendering); Q-102/103/109 citations check out against D-246/D-228 and shipped `shell.rs`; determinism clean (no HashMap, no floats, integer-only draws); `SeedDomain::TraitExterior = 16` appended + pinned; seven independent seed sub-axes off `fp_chain`, zero shared rolls; schema/migration/generator_sources all paired; `ExteriorCatalog` clone is launch-bounded in the no-budget plan phase; zero bare unwrap/expect/panic in new production paths; the T-1097 `BlockSkeleton` relocation and the T-1098 deferred-interstitial seam are both architecturally clean.
### Verdict: CHANGES REQUESTED
H1 + H2 are isolated Python hardening (+ their missing tests) in one importer function. Fixing now.
Process notes: no client/merge-path touched (server + tooling + governance only). Runtime verification = the full pre-push gate (clippy -D warnings, 1666 lib tests, make test-tooling incl. V-TT failure-branch units, cargo deny, fresh stamp). No golden impact.
H1: guard that each axis value is a {token=weight} table before .items() —
a scalar (wall = 15000) or the array shape (wall = ["steel_frame"], a
plausible copy-paste from the sibling catalog's visual_bundle) now yields a
clean V-TT-06 error instead of a bare AttributeError. Mirrors the isinstance
guards already on zone_map and axes.
H2: exclude bool from the positive-integer weight check (weight = true is an
int subclass, previously slipped through as 1) — matches the guard
populate_color_register_bands already applies to its own values.
Two new ZoneBiasValidationTests cover both branches.
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Review response — both findings fixed in b8e0b1b66
No pushbacks; both verified against the branch and fixed.
#
Resolution
H1
populate_architecture_zone_bias now guards that each axis value is a {token = weight_bps} table before iterating — a scalar (wall = 15000) or the array shape (wall = ["steel_frame"], the copy-paste-from-visual_bundle case Hoshe named) yields a clean V-TT-06 error naming the stanza + the wrong type, instead of a bare AttributeError. Mirrors the isinstance guards already on zone_map and axes.
H2
The positive-integer weight check now excludes bool (isinstance(weight, bool) or not isinstance(weight, int) or weight <= 0) — weight = true is rejected instead of slipping through as 1. Matches the guard populate_color_register_bands already applies to its own values.
Two new ZoneBiasValidationTests cover both branches (test_non_dict_axis_value_reports_vtt06_not_a_traceback asserts the clean error for both the scalar and array shapes; test_bool_weight_is_rejected). make test-tooling now runs 26 traits units, all green.
systems.db regenerated + re-stamped (traits.py is a stamped generator source, so the stamp had to flip). Full pre-push gate re-run green.
Tyre's review was APPROVE with no comments. With H1/H2 addressed, the batch is review-clean.
## Review response — both findings fixed in `b8e0b1b66`
No pushbacks; both verified against the branch and fixed.
| # | Resolution |
|---|-----------|
| H1 | `populate_architecture_zone_bias` now guards that each axis value is a `{token = weight_bps}` table before iterating — a scalar (`wall = 15000`) or the array shape (`wall = ["steel_frame"]`, the copy-paste-from-`visual_bundle` case Hoshe named) yields a clean **V-TT-06** error naming the stanza + the wrong type, instead of a bare `AttributeError`. Mirrors the `isinstance` guards already on `zone_map` and `axes`. |
| H2 | The positive-integer weight check now excludes `bool` (`isinstance(weight, bool) or not isinstance(weight, int) or weight <= 0`) — `weight = true` is rejected instead of slipping through as `1`. Matches the guard `populate_color_register_bands` already applies to its own values. |
Two new `ZoneBiasValidationTests` cover both branches (`test_non_dict_axis_value_reports_vtt06_not_a_traceback` asserts the clean error for both the scalar and array shapes; `test_bool_weight_is_rejected`). `make test-tooling` now runs 26 traits units, all green.
`systems.db` regenerated + re-stamped (traits.py is a stamped generator source, so the stamp had to flip). Full pre-push gate re-run green.
Tyre's review was APPROVE with no comments. With H1/H2 addressed, the batch is review-clean.
Blocking a user prevents them from interacting with repositories, such as opening or commenting on pull requests or issues. Learn more about blocking a user.
Summary
The Layer-5 batch — building-exterior visual grammar, material fill onto the shell, ops-surface tagging, and the region transient-state D-record. Advances T-750 (Phase 4) toward the T-962 walkable-world gate.
trait_exterior.rs: 3-step era-free derivation (visual_bundle filter → zone-bias weighted pick → density→setback), color seed-sampled within the template's register band. Resolved at GenerateSkeleton (T-994 precedent), frozen onBuildingPropertyTag; FillChunk only reads it. Four append-only integer-discriminant material enums;trait_catalog_readernow parsesvisual_bundle+ two new tables (OnceLock-cached); newSeedDomain::TraitExteriorwith per-axis sub-chains (no cross-field correlation). Content authored by Miri (zone-bias, 57 sparse entries) + Araminta (28 color bands), baked intosystems.dbwith V-TT-06/07 importer validation (token-in-bundle, coverage + integer HSV bounds).FilledChunk.surface_material), purely additive. Interstitial-fill-from-setback split to T-1098 (needs a FillChunk block-metadata + geometry design pass; nothing consumes FillChunk until Phase 5).BlockSkeleton.interstitial_character(OpenSpace | OperationsSurface), D-233 bulk-driven: bulk-industry blocks' non-roofed remainder tags as built economic infrastructure.Verification
Full pre-push gate green:
cargo fmt --check,cargo clippy --all-targets -D warnings, 1666 lib tests,make test-tooling(incl. new V-TT-05/06/07 failure-branch units),cargo deny, fresh systems.db stamp. No golden impact (harnesses top out at CascadeLayer::RoadGraph — Layer 4/5 is structurally unreachable).🤖 Generated with Claude Code
T-988 — BuildingExteriorTag {wall_material, roof_form, facade_rhythm, setback_tier, color:HsvColor, street_surface}. New trait_exterior.rs: 3-step era-free derivation (visual_bundle filter -> zone-bias weighted pick -> density->setback), color seed-sampled within the register band. Resolved at GenerateSkeleton plan time (T-994 precedent), frozen on BuildingPropertyTag; FillChunk only reads it. Four append-only integer-discriminant enums (WallMaterial/RoofForm/FacadeRhythm/ StreetSurface), unknown token -> axis Generic + warn. trait_catalog_reader now parses visual_bundle + the two new tables (OnceLock-cached). New SeedDomain::TraitExterior (per-axis sub-chains — no cross-field correlation). T-959 — FillChunk reads the frozen exterior tag: wall_material/roof_form onto Wall/Roof shell voxels (FilledChunk.surface_material). Additive, ShellVoxel untouched, all shell tests pass. (Interstitial-fill-from-setback split to T-1098 — needs a FillChunk block-metadata + geometry design pass; nothing consumes FillChunk until Phase 5.) T-1097 — BlockSkeleton.interstitial_character (OpenSpace|OperationsSurface), D-233 bulk-driven: bulk-industry blocks' non-roofed remainder tags as built economic infrastructure, not generic open space. cargo check --all-targets clean; 1666 lib tests pass; no golden impact (harnesses top out at CascadeLayer::RoadGraph, unreachable by Layer 4/5). Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>Review: layer5-tile-fill → main (type: code)
Reviewers: Hoshe (code quality), Tyre (architecture) — both read the branch worktree at
204359927.Hoshe (Code Quality): REQUEST_CHANGES
The
trait_exterior.rsderivation is careful, integer-only, correctly domain-separates its seven per-axis RNG sub-chains, and every content-gap path degrades to Generic/neutral (all tested).shell.rssurface_material is cleanly additive (ShellVoxel untouched). Two robustness gaps in the new importer validation block approval.tooling/economy-db/economy_import/traits.py:313populate_architecture_zone_bias: a non-dict axis value (wall = 15000, or the array-shapedwall = ["steel_frame"]copy-paste from the sibling catalog'svisual_bundle) hits(weights or {}).items()→ bareAttributeError, not the cleanV-TT-06error every other malformed shape produces. The function guardszone_map(line 294) andaxes(line 300) are dicts but never the per-axisweights.import_economicsrolls back so no DB corruption, but the user gets a traceback instead of an actionable stanza pointer. Untested branch. Fix:isinstance(weights, dict)guard mirroring the two above it.tooling/economy-db/economy_import/traits.py:319if not isinstance(weight, int) or weight <= 0doesn't excludebool(an int subclass) —weight = truepasses as 1.populate_color_register_bandsexplicitly guards this same footgun for its own values; match it.Tyre (Architecture): APPROVE
No comments. Independently verified: D-253 is internally consistent and correctly scoped (adds the time dimension over T-1078's spatial baseline, does not touch the D-243 spatial stack; scope boundary explicitly excludes gameplay/passability/rendering); Q-102/103/109 citations check out against D-246/D-228 and shipped
shell.rs; determinism clean (no HashMap, no floats, integer-only draws);SeedDomain::TraitExterior = 16appended + pinned; seven independent seed sub-axes offfp_chain, zero shared rolls; schema/migration/generator_sources all paired;ExteriorCatalogclone is launch-bounded in the no-budget plan phase; zero bare unwrap/expect/panic in new production paths; the T-1097BlockSkeletonrelocation and the T-1098 deferred-interstitial seam are both architecturally clean.Verdict: CHANGES REQUESTED
H1 + H2 are isolated Python hardening (+ their missing tests) in one importer function. Fixing now.
Process notes: no client/merge-path touched (server + tooling + governance only). Runtime verification = the full pre-push gate (clippy -D warnings, 1666 lib tests, make test-tooling incl. V-TT failure-branch units, cargo deny, fresh stamp). No golden impact.
H1: guard that each axis value is a {token=weight} table before .items() — a scalar (wall = 15000) or the array shape (wall = ["steel_frame"], a plausible copy-paste from the sibling catalog's visual_bundle) now yields a clean V-TT-06 error instead of a bare AttributeError. Mirrors the isinstance guards already on zone_map and axes. H2: exclude bool from the positive-integer weight check (weight = true is an int subclass, previously slipped through as 1) — matches the guard populate_color_register_bands already applies to its own values. Two new ZoneBiasValidationTests cover both branches. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>Review response — both findings fixed in
b8e0b1b66No pushbacks; both verified against the branch and fixed.
populate_architecture_zone_biasnow guards that each axis value is a{token = weight_bps}table before iterating — a scalar (wall = 15000) or the array shape (wall = ["steel_frame"], the copy-paste-from-visual_bundlecase Hoshe named) yields a clean V-TT-06 error naming the stanza + the wrong type, instead of a bareAttributeError. Mirrors theisinstanceguards already onzone_mapandaxes.bool(isinstance(weight, bool) or not isinstance(weight, int) or weight <= 0) —weight = trueis rejected instead of slipping through as1. Matches the guardpopulate_color_register_bandsalready applies to its own values.Two new
ZoneBiasValidationTestscover both branches (test_non_dict_axis_value_reports_vtt06_not_a_tracebackasserts the clean error for both the scalar and array shapes;test_bool_weight_is_rejected).make test-toolingnow runs 26 traits units, all green.systems.dbregenerated + re-stamped (traits.py is a stamped generator source, so the stamp had to flip). Full pre-push gate re-run green.Tyre's review was APPROVE with no comments. With H1/H2 addressed, the batch is review-clean.
Pull request closed