docs(tooling): T-1253 — sweep the live references to retired tool paths

A script scanned every tracked doc, rule, skill, agent, hook and source file
for tooling/ paths that no longer exist, skipping historical records (sprints,
discussions, workshops, governance, generated wiki pages). It found 62. The
ones that tell a reader what to RUN now name the reach verb:

- The atlas skill still sent agents to tooling/atlas, atlas-verify,
  atlas-update-field and atlas-commit-and-sync — about forty lines, all
  retired in T-1285. They now name the `reach atlas` verbs, and the skill
  records that commit-and-sync STAGES by default (--commit to commit) and
  takes --corridor as an option.
- The clerk agent named tooling/clerk-review (now `reach dev clerk`). The Si
  and clerk briefings sent those agents to the retired tooling/db/decision
  and sqlite-query CLIs and to decisions/*.md paths that moved to
  governance/ in the pql migration. They now name pql.
- The ticket-cli rule documented `pql decisions read`, which does not exist;
  `show` already includes the body.
- The culture authoring guide and the RON sources name
  `reach validate ron`, with the same arguments as before.
- The 41 Blender payloads' usage lines ran the retired tooling/blender
  wrapper, and the docstrings still cited pre-carve-out paths. They now read
  `reach blender run <payload>`.
- Doc comments in server/, client/, wiki TOMLs and the domain modules.

What is left is deliberate: "Formerly …" provenance, dated plans and findings
docs, the retired-pipeline doc, and a build-artefact path.

project.yaml 0.4.14 (mirrored to the client). Comment-only, but four touched
files are in the canvas-version registry (trait_catalog_reader.rs, since
T-1289, canvas_sources.py itself, and two client files). The gate is
path-based and has no override. The previous push was rejected on exactly
this.

Three of the edits are stamped ledger sources, so systems.db is regenerated
and the stamp is fresh.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
This commit is contained in:
2026-09-23 20:13:58 +02:00
co-authored by Claude Opus 5.5
parent e3daf561d1
commit c597ec9131
69 changed files with 156 additions and 170 deletions
+1 -1
View File
@@ -24,7 +24,7 @@ You check whether a diff is consistent with the project's institutional knowledg
**This file is the manual-audit prompt.** Report findings directly, with a citation (D/Q/R-record or ticket) for each. No file writes, no binary gate needed.
**Pre-push hook (separate prompt, dormant by default):** the hook's clerk step only runs with `SR_RUN_CLERK=1` set (disabled otherwise, #965). When enabled, `tooling/clerk-review` spawns `claude -p` with its own inline prompt — not this file — writes findings to `.cache/pre-push-review.md`, and outputs one of `APPROVED` / `REJECTED` / `INCOMPLETE` to stdout. If you're auditing that path, read `tooling/clerk-review` itself; this persona doesn't drive it.
**Pre-push hook (separate prompt, dormant by default):** the hook's clerk step only runs with `SR_RUN_CLERK=1` set (disabled otherwise, #965). When enabled, `reach dev clerk` (`tooling/domains/dev/clerk.py`) spawns `claude -p` with its own inline prompt — not this file — writes findings to `.cache/pre-push-review.md`, and outputs one of `APPROVED` / `REJECTED` / `INCOMPLETE` to stdout. If you are auditing that path, read `tooling/domains/dev/clerk.py` itself; this persona doesn't drive it.
## What you do NOT do
+1 -1
View File
@@ -74,7 +74,7 @@ pql plan rebuild # drop + replay changelog from scratch (post-checkout/rew
pql decisions claim D <domain> "title" # next free id, no side effects (D | Q | R)
pql decisions list [--type confirmed|question|rejected] [--domain X]
pql decisions show D-010 [--with-tickets]
pql decisions read D-238 # full markdown body
pql decisions show D-238 # includes the full markdown body (there is no `read` verb)
pql decisions refs D-010 # cross-references
pql decisions sync # parse governance/*.md -> pql.db
pql decisions validate # malformed-record gate (pre-commit)
+36 -32
View File
@@ -14,7 +14,8 @@ allowed-tools: Bash, Read, Grep, Glob, Write, Edit, Agent
Query and manage celestial bodies (planets, moons, gas giants, asteroid belts,
oort clouds) and stations in `server/data/systems.db`.
**CLI binary:** `tooling/atlas` (wraps `cargo run --bin atlas`)
**CLI:** `reach atlas db <verb>` fronts the Rust `atlas` binary (built on demand);
the other `reach atlas …` verbs wrap the proposal workflow (T-1285)
**Database:** `server/data/systems.db` (auto-detected from working directory)
**All output is JSON on stdout.**
@@ -22,28 +23,28 @@ oort clouds) and stations in `server/data/systems.db`.
### Show full system hierarchy
```bash
tooling/atlas show-system "GJ 15A"
reach atlas db show-system "GJ 15A"
```
Returns: system info + all bodies + all stations in the system.
### Show a single body
```bash
tooling/atlas show-body "GJ15Ab"
reach atlas db show-body "GJ15Ab"
```
Returns: body details + stations orbiting that body.
### Show a single station
```bash
tooling/atlas show-station "GJ15Ab-S1"
reach atlas db show-station "GJ15Ab-S1"
```
### List systems with filters
```bash
tooling/atlas list-systems
tooling/atlas list-systems --sector west_reach
tooling/atlas list-systems --sector west_reach --hop 7
tooling/atlas list-systems --sector west_reach --unfinished
tooling/atlas list-systems --sector east_reach --finished
reach atlas db list-systems
reach atlas db list-systems --sector west_reach
reach atlas db list-systems --sector west_reach --hop 7
reach atlas db list-systems --sector west_reach --unfinished
reach atlas db list-systems --sector east_reach --finished
```
Sectors: `north_reach`, `south_reach`, `east_reach`, `west_reach`, `deep_frontier`, `core`
Returns: system_id, proper_name, star_type, spectral_class, gate_topology,
@@ -51,39 +52,39 @@ geographic_sector, hop_distance, population. Sorted by hop then system_id.
### Unfinished systems (with optional sector filter)
```bash
tooling/atlas unfinished
tooling/atlas unfinished --sector west_reach
reach atlas db unfinished
reach atlas db unfinished --sector west_reach
```
### Next hop (with optional sector filter)
```bash
tooling/atlas next
tooling/atlas next 7
tooling/atlas next --sector west_reach
tooling/atlas next 8 --sector west_reach
reach atlas db next
reach atlas db next 7
reach atlas db next --sector west_reach
reach atlas db next 8 --sector west_reach
```
### List bodies with filters
```bash
tooling/atlas list-bodies
tooling/atlas list-bodies --system "GJ 15A"
tooling/atlas list-bodies --type planet
tooling/atlas list-bodies --type planet --inhabited
tooling/atlas list-bodies --unnamed
reach atlas db list-bodies
reach atlas db list-bodies --system "GJ 15A"
reach atlas db list-bodies --type planet
reach atlas db list-bodies --type planet --inhabited
reach atlas db list-bodies --unnamed
```
Types: `planet`, `moon`, `gas_giant`, `asteroid_belt`, `oort_cloud`
### List stations with filters
```bash
tooling/atlas list-stations
tooling/atlas list-stations --system "GJ 15A"
tooling/atlas list-stations --type horizon
reach atlas db list-stations
reach atlas db list-stations --system "GJ 15A"
reach atlas db list-stations --type horizon
```
Types: `horizon`, `commercial`, `military`, `research`, `industrial`, `agricultural`, `transit`
### Add a body
```bash
tooling/atlas add-body \
reach atlas db add-body \
--id "GJ15Ab" \
--system "GJ 15A" \
--type planet \
@@ -99,7 +100,7 @@ tooling/atlas add-body \
### Add a station
```bash
tooling/atlas add-station \
reach atlas db add-station \
--id "GJ15Ab-S1" \
--system "GJ 15A" \
--orbits "GJ15Ab" \
@@ -111,13 +112,13 @@ tooling/atlas add-station \
### Database statistics
```bash
tooling/atlas stats
reach atlas db stats
```
Returns: system count, body count by type, inhabited count, station count by type.
### Corridor status (remaining unfinished systems)
```bash
tooling/atlas corridor-status
reach atlas db corridor-status
```
Shows remaining unfinished systems grouped by geographic sector and hop
distance. Supersedes the old bulk-populate classifier pass (removed) — use
@@ -125,8 +126,8 @@ the per-system `author` → review → `commit-system` workflow below instead.
### Update a system-level field
```bash
tooling/atlas-update-field "GJ 687" settlement_wave wave_3
tooling/atlas-update-field "GJ 53A" star_type G
reach atlas update-field "GJ 687" settlement_wave wave_3
reach atlas update-field "GJ 53A" star_type G
```
Updates a whitelisted field in systems.db. Auto-detects the correct table
(`star_systems`, `system_gates`, or `system_history`). Inserts a row in
@@ -139,11 +140,14 @@ Whitelisted fields: `star_type`, `spectral_class`, `proper_name`,
### Commit and sync a single system
```bash
tooling/atlas-commit-and-sync "GJ 105A" east_reach
reach atlas commit-and-sync "GJ 105A" --corridor east_reach # stages
reach atlas commit-and-sync "GJ 105A" --corridor east_reach --commit # and commits
```
Full pipeline: verify proposal → wipe existing data (if any) → commit to DB
→ sync wiki → git add + git commit. Second argument is the corridor tag for
the commit message (defaults to `east_reach`).
→ sync wiki → git add. **It stages by default**; `--commit` also makes the git
commit (the old script always committed). It refuses to continue when the
proposal fails verification. `--corridor` tags the commit message (default
`east_reach`).
## Body ID Naming Convention
@@ -25,7 +25,7 @@ This context feeds all subsequent steps but is NOT written to the JSON.
## Step 2: Astrophysical Skeleton
Run `tooling/atlas author "{system_id}"` to generate the base proposal JSON.
Run `reach atlas db author "{system_id}"` to generate the base proposal JSON.
Enrich with realistic body counts per star type:
- G/F stars: 8+ planets
@@ -83,7 +83,7 @@ Either can flag issues that loop back to Step 3.
## Step 6: Integrity Check
```bash
tooling/atlas-verify docs/atlas/proposals/{id}.json
reach atlas verify docs/atlas/proposals/{id}.json
```
All checks from `references/integrity-check.md` must pass. Fix any
@@ -91,21 +91,22 @@ failures before proceeding.
## Step 7: Commit
Use the combined commit-and-sync script:
Use the combined commit-and-sync verb:
```bash
tooling/atlas-commit-and-sync "{system_id}" {corridor_tag}
reach atlas commit-and-sync "{system_id}" --corridor {corridor_tag} --commit
```
This runs: verify → wipe-if-exists → commit-system → sync-wiki → git
add + git commit in one command. The corridor_tag (e.g. `east_reach`)
add, and with `--commit` the git commit too (without it the result is only
staged). It stops if verification fails. The corridor tag (e.g. `east_reach`)
is used in the commit message.
If system-level DB fields need correction before committing (e.g.
`star_type`, `settlement_wave`), use:
```bash
tooling/atlas-update-field "{system_id}" {field} {value}
reach atlas update-field "{system_id}" {field} {value}
```
Post-commit: verify topology section survived sync-wiki. If missing,
@@ -2,7 +2,7 @@
Run these checks on the proposal JSON before commit. All must pass.
`tooling/atlas-verify` only ever opens the proposal JSON file — it never opens
`reach atlas verify` only ever opens the proposal JSON file — it never opens
`systems.db`. Checks that require comparing against the live database (2, 4)
are **not enforced by the script** and must be performed manually or by the
authoring agent before commit.
@@ -63,7 +63,7 @@ authoring agent before commit.
## Running the Check
```bash
tooling/atlas-verify docs/atlas/proposals/{id}.json
reach atlas verify docs/atlas/proposals/{id}.json
```
Or verify all proposals at once:
+1 -1
View File
@@ -57,7 +57,7 @@ single direction is "the" direction.)
*Body page* (`bodies/{id}/index.md`) — different, and more dangerous:
1. Origin is the bodies catalog in `server/data/systems.db`, authored through the
atlas CLI (`tooling/atlas add-body` / `author-system`), which is
atlas CLI (`reach atlas db add-body` / `author-system`), which is
atlas-CLI-owned and survives `make regen-db` (`Skill(atlas)`).
2. `scaffold_bodies.py` reads the system page's Celestial Bodies table, runs
`body_definition_parser.py`, and writes the body frontmatter once. Resolution
+2 -2
View File
@@ -15,9 +15,9 @@ config/name="The Settled Reach"
; truth (CLAUDE.md), this is the copy that survives an export. Godot bakes
; ProjectSettings into the PCK, so `application/config/version` reads the same
; in the editor and in a shipped build, where res://../project.yaml does not
; exist at all (T-1241). Kept honest by `make check-client-version`, which the
; exist at all (T-1241). Kept honest by `reach check client-version`, which the
; pre-push hook runs — do not edit this by hand without moving project.yaml too.
config/version="0.4.13"
config/version="0.4.14"
run/main_scene="res://scenes/main_menu.tscn"
config/features=PackedStringArray("4.6", "GL Compatibility")
config/icon="res://icon.svg"
+1 -1
View File
@@ -21,7 +21,7 @@ extends RefCounted
## project.yaml scan lacked.
##
## `project.yaml` remains the source of truth for the version (CLAUDE.md); the
## ProjectSettings entry is a mirror, and `tooling/check-client-version` fails
## ProjectSettings entry is a mirror, and `reach check client-version` fails
## the push if the two drift.
const SETTING_KEY: String = "application/config/version"
+2 -2
View File
@@ -256,7 +256,7 @@ func test_gauntlet_ui_stays_hidden_after_multiple_snapshots() -> void:
# -- GauntletHUD Feature Tests (#496) ----------------------------------------
# Timer lifecycle, personal bests, room change, visibility.
# Spec: sprint-9/client.md #496. Ticket: tooling/db/ticket show 496.
# Spec: sprint-9/client.md #496. Ticket: pql ticket show T-496.
func test_format_time_zero() -> void:
# Static utility: 0 seconds → "00:00"
@@ -482,7 +482,7 @@ func test_gauntlet_snapshot_roundtrip_via_apply() -> void:
# -- BugReportDialog Feature Tests (#495) ------------------------------------
# Pause/unpause lifecycle, wire guard, text render, state machine.
# Spec: sprint-9/client.md #495. Ticket: tooling/db/ticket show 495.
# Spec: sprint-9/client.md #495. Ticket: pql ticket show T-495.
func test_bug_report_sends_pause_on_open() -> void:
# start_capture() must send Pause to the server.
+1 -1
View File
@@ -406,7 +406,7 @@ func test_baked_version_mirrors_project_yaml() -> void:
# Drift guard, dev-only by nature (an export has no project.yaml to compare
# against — which is the whole reason the value is baked). project.yaml stays
# the source of truth; this catches the bump-one-forget-the-other case from
# inside the suite, as well as from tooling/check-client-version in the hook.
# inside the suite, as well as from `reach check client-version` in the hook.
var yaml_path := ProjectSettings.globalize_path("res://") + "/../project.yaml"
if not FileAccess.file_exists(yaml_path):
return # exported/packaged run — nothing to compare, and nothing to guard
@@ -162,7 +162,7 @@ const RELIEF_TEXTURE_FULL_SCALE_Q: int = 60
## was consumed, but only as a stipple PROBABILITY — so a ridge and a plain
## differed in dot density, which at one pixel per cell reads as noise rather
## than as landform. Measured on the 2026-08-16 cold ladder
## (tooling/atlas-flatness): Region carried 2,923 distinct colours against
## (`reach atlas flatness`): Region carried 2,923 distinct colours against
## Global's 1,581 while holding a quarter of its structure. Colour count went UP
## and legibility went DOWN, which is the signature of texture standing in for
## form.
+8 -6
View File
@@ -23,13 +23,15 @@ Review branch changes before push to catch institutional drift: decision contrad
## Where to Find Decisions
- **Decision index:** `decisions/README.md`master index of all domain files
- **Domain files:** `decisions/architecture.md`, `decisions/perception.md`, `decisions/content.md`, `decisions/scope.md`, `decisions/economics.md`, `decisions/process.md`
- **Open questions:** `decisions/questions.md`, `decisions/questions-process.md`
- **Rejected proposals:** `decisions/rejected.md`
- **Decision DB table:**
- **Decision index:** `governance/README.md`the domain guide and the pql-maintained record index
- **Confirmed decisions:** `governance/decisions/<domain>.md` — architecture, perception, content, scope, economics, process
- **Open questions:** `governance/questions/<domain>.md`
- **Rejected proposals:** `governance/rejected/<domain>.md`
- **Queries** (pql; never the `sqlite3` CLI, which crashes in Claude Code):
```bash
tooling/db/sqlite-query "SELECT id, title, status, domain FROM decisions WHERE domain = '<domain>'"
pql decisions list --domain <domain>
pql decisions list --type question
pql decisions refs D-NNN # what cites a record
```
## Output
+8 -7
View File
@@ -26,14 +26,15 @@ If any of these conditions fail, the ticket is not ready. Flag what is missing a
## Where to Find Decisions
- **Decision index:** `decisions/README.md`lists all domain files and how to query them
- **Domain files:** `decisions/architecture.md`, `decisions/perception.md`, `decisions/content.md`, `decisions/scope.md`, `decisions/economics.md`, `decisions/process.md`
- **Open questions:** `decisions/questions.md` (Q-NNN), `decisions/questions-process.md` (Q-NNN process)
- **Rejected proposals:** `decisions/rejected.md` (R-NNN)
- **Decision DB queries:**
- **Decision index:** `governance/README.md`the domain guide and the pql-maintained record index
- **Confirmed decisions (D-NNN):** `governance/decisions/<domain>.md` — architecture, perception, content, scope, economics, process
- **Open questions (Q-NNN):** `governance/questions/<domain>.md`
- **Rejected proposals (R-NNN):** `governance/rejected/<domain>.md`
- **Queries** (pql — the old `tooling/db/decision` CLI was retired in the pql migration):
```bash
tooling/db/decision show D-NNN # Show a specific decision
tooling/db/decision check-dupes "title" # Check for duplicates before creating
pql decisions show D-NNN # one record, with its markdown body
pql decisions list --type question # open questions
pql decisions claim D <domain> "title" # next free id, before writing a new one
```
## Where to Find Workshop Outcomes
@@ -13,7 +13,7 @@
# red = the trap (output that is read back as input)
#
# Every path here was read in the tool's own source, not inferred.
# tooling/check-dataflow-graph asserts the paths still exist; it CANNOT verify
# `reach check dataflow-graph` asserts the paths still exist; it CANNOT verify
# that an edge's MEANING is still true — see D-262.
#
# View it: clide draw --file docs/diagrams/data-flow/wiki-generator-flow.d2
+5 -1
View File
@@ -67,7 +67,11 @@ name: The Settled Reach
# here, not merely stale.
# 0.4.13 — stipple contrast (T-1194). Paint only; bumped because the client
# step_canvas cluster is in the T-1242 registry.
version: 0.4.13
# 0.4.14 carries NO canvas-generation change: comment-only edits (retired tool
# paths renamed to their reach verbs, T-1289/T-1253) touched
# server/src/atlas/trait_catalog_reader.rs, canvas_sources.py itself, and two
# client files in the registry. Path-based gate, spent rather than dodged.
version: 0.4.14
repository: settled-reach
Binary file not shown.
+2 -2
View File
@@ -3,7 +3,7 @@
//!
//! - **Star map** ([`StarMapRequest`]/[`StarMapResponse`]): a session-scoped,
//! non-per-body proxy over the static `client/data/star_map_data.json`
//! dataset (produced by `tooling/generate-star-map-data.py`). Reads the file
//! dataset (produced by `reach atlas map data`). Reads the file
//! fresh on every request — no caching, no staleness handling — because the
//! client only asks once per session when the Atlas star-map view opens.
//! The parsed JSON is passed through as an opaque `serde_json::Value` rather
@@ -79,7 +79,7 @@ pub enum StarMapStatus {
pub struct StarMapResponse {
pub status: StarMapStatus,
/// Verbatim parsed JSON (`_meta`, `nodes`, `edges` — see
/// `tooling/generate-star-map-data.py`), re-serialized as MessagePack.
/// `reach atlas map data`), re-serialized as MessagePack.
/// `None` unless `status == Ready`.
pub data: Option<serde_json::Value>,
}
+4 -4
View File
@@ -3,10 +3,10 @@
//! # Usage
//!
//! ```sh
//! # Via wrapper script (recommended):
//! tooling/atlas list-bodies --system "GJ 15A"
//! tooling/atlas list-bodies --type planet --inhabited
//! tooling/atlas show-system "GJ 15A"
//! # Via reach (recommended — builds the binary on demand):
//! reach atlas db list-bodies --system "GJ 15A"
//! reach atlas db list-bodies --type planet --inhabited
//! reach atlas db show-system "GJ 15A"
//! tooling/atlas show-body "GJ 15Ab"
//! tooling/atlas add-body --system "GJ 15A" --type planet --orbit 1 --id "GJ 15Ab"
//! tooling/atlas stats
+1 -1
View File
@@ -511,7 +511,7 @@ fn write_output(path: &PathBuf, products: &[BrandProduct], inputs: &[BrandInput]
let mut out = String::new();
out.push_str("# Generated Minor Brand Products — The Settled Reach\n");
out.push_str("# Auto-generated by generate_brands binary. Do not hand-edit.\n");
out.push_str("# Re-run: tooling/generate-brands\n");
out.push_str("# Re-run: reach generate brands\n");
out.push_str(&format!(
"# Total: {} brand_products, {} brand_inputs\n\n",
products.len(),
+1 -1
View File
@@ -9,7 +9,7 @@
//! `main.rs` — this directory is not a cargo bin target (no `main.rs`).
//!
//! NOTE: both binaries feed the systems.db meta stamp — this file is part of
//! the `import_economics` source set in `tooling/check-systems-db-stamp`
//! the `import_economics` source set checked by `reach check systems-db-stamp`
//! (GENERATOR_SOURCES). Changing any pool requires `make regen-db`.
//! Pool contents are surname data drawn from founding cultures in wiki canon;
//! ordering is load-bearing (index-based RNG draws), so never reorder.
+2 -2
View File
@@ -8,8 +8,8 @@
//!
//! ```sh
//! # Via wrapper script (recommended):
//! tooling/validate-ron server/content/global/zone-identity-spec.example.ron zone
//! tooling/validate-ron server/content/global/culture-van-maanens-star.example.ron culture
//! reach validate ron server/content/global/zone-identity-spec.example.ron zone
//! reach validate ron server/content/global/culture-van-maanens-star.example.ron culture
//!
//! # Direct:
//! cargo run --bin validate_ron -- <file.ron> <zone|culture>
+1 -1
View File
@@ -230,7 +230,7 @@ fn main() {
}
// Star-map dataset proxy (T-949a): resolve the repo-root-relative path to
// the client's pre-generated star_map_data.json (tooling/generate-star-map-data.py).
// the client's pre-generated star_map_data.json (`reach atlas map data`).
// Read fresh on every request — no caching, see atlas_data_proxy module doc.
let star_map_data_path = world_root.join("client/data/star_map_data.json");
if star_map_data_path.exists() {
+2 -2
View File
@@ -20,7 +20,7 @@
//! ## Format
//!
//! RON (Rusty Object Notation) — struct-aware, supports enums and comments.
//! Validate with: `tooling/validate-ron <file.ron> <zone_type|culture>`
//! Validate with: `reach validate ron <file.ron> <zone_type|culture>`
use rand::Rng;
use serde::{Deserialize, Serialize};
@@ -112,7 +112,7 @@ pub struct SocialSiteSpec {
/// NPCs per site) — that lives on `LocationSpec.social_sites`.
///
/// The Rust struct IS the schema. RON files must match this struct exactly.
/// Validate with: `tooling/validate-ron server/content/global/zone-types/<id>.ron zone_type`
/// Validate with: `reach validate ron server/content/global/zone-types/<id>.ron zone_type`
#[derive(Debug, Clone, Serialize, Deserialize)]
pub struct ZoneTypeTemplate {
/// Canonical zone-type identifier (e.g. `"rural_agricultural"`).
+1 -1
View File
@@ -1,7 +1,7 @@
//! Performance benchmarks: tick timing and memory usage
//!
//! Run with: cargo test --release --test perf_bench -- --ignored --nocapture
//! Output: PERF_RESULT:{json} lines for tooling/perf-baseline to parse.
//! Output: PERF_RESULT:{json} lines for `reach dev perf` to parse.
//!
//! Tick budget target: 100ms (D-026)
+1 -1
View File
@@ -15,7 +15,7 @@ the last only after T-1239 spent eight days diagnosing a map drawn from a canvas
whose generating code had been replaced. The failure is invisible to its author:
it reproduces only where a warm cache exists, so a cold checkout looks fine.
This module is the registry `tooling/check-canvas-version` intersects against,
This module is the registry `reach check canvas-version` intersects against,
kept here rather than inline in the hook for the same reason
`tooling/generator_sources.py` exists (T-1067): one list, one place, imported by
everything that needs it.
+2 -2
View File
@@ -24,8 +24,8 @@ variation a map is actually read for; distinct-count is reported alongside
precisely so the two can be seen disagreeing.
Usage:
tooling/atlas-flatness .cache/screenshots/atlas_GJ820Bc_land_Region.png [...]
tooling/atlas-flatness --ladder # the standard descent ladder
reach atlas flatness .cache/screenshots/atlas_GJ820Bc_land_Region.png [...]
reach atlas flatness --ladder # the standard descent ladder
"""
import sys
+1 -1
View File
@@ -2,7 +2,7 @@
"""Quick diagnostic for an atlas proposal — shows planet count, body summary, and flags.
Usage:
tooling/atlas-check docs/atlas/proposals/GJ1075.json
reach atlas check docs/atlas/proposals/GJ1075.json
"""
import json
from pathlib import Path
+2 -2
View File
@@ -2,8 +2,8 @@
"""Verify an atlas proposal JSON against integrity checks.
Usage:
tooling/atlas-verify docs/atlas/proposals/GJ273.json
tooling/atlas-verify docs/atlas/proposals/*.json
reach atlas verify docs/atlas/proposals/GJ273.json
reach atlas verify docs/atlas/proposals/*.json
"""
import json
from pathlib import Path
+1 -1
View File
@@ -33,7 +33,7 @@ on the screen", never "is the world any good". Keep it that way; a check that
creeps toward aesthetics will start failing legitimate frames and get muted.
Usage:
tooling/visual-blank-check <PNG> [--max-modal 0.85] [--quiet]
reach visual blank-check <PNG> [--max-modal 0.85] [--quiet]
Exit: 0 = has content, 1 = blank, 2 = error (unreadable/missing).
"""
+1 -1
View File
@@ -5,7 +5,7 @@ Compares two PNG images per-channel with configurable tolerance.
Reads default tolerance from tests/visual.json if available.
Usage:
tooling/visual-diff EXPECTED ACTUAL [--tolerance N] [--diff-output PATH] [--config PATH]
reach visual diff EXPECTED ACTUAL [--tolerance N] [--diff-output PATH] [--config PATH]
Exit codes:
0 = images match (all pixels within tolerance)
+2 -2
View File
@@ -4,13 +4,13 @@
Two modes:
Grid mode (default):
tooling/visual-thumbnail DIR [--config PATH]
reach visual thumbnail DIR [--config PATH]
Reads {flow}_{NNN}.png frames + {flow}_manifest.txt sidecar from DIR,
generates a contact sheet grid with timecodes and labels.
Output: DIR/{flow}_sheet.png
Crop mode:
tooling/visual-thumbnail --crop REGION IMAGE [--config PATH]
reach visual thumbnail --crop REGION IMAGE [--config PATH]
Extracts a named region from IMAGE at 1:1 scale.
Output: IMAGE_crop_{REGION}.png
@@ -70,8 +70,7 @@ stays faithful; the brown/black work-street default lives in the manifest
default_tints (sole near-black, upper work brown, laces dark).
Usage (boots_modern reference invocation):
tooling/blender --background --python \
tooling/scripts/blender/blender_author_boots.py -- \
reach blender run blender_author_boots \
client/assets/characters/bodies \
client/assets/characters/clothing/boots_modern \
[--bodies average_m,child,...] [--offset 0.013] [--shaft-frac 0.30] \
@@ -28,8 +28,7 @@ channel is still authored (costs nothing; enables future brand variants).
Run (per-body only — this garment ships the per-body route):
tooling/blender --background --python \
tooling/scripts/blender/blender_author_buttondown.py -- \
reach blender run blender_author_buttondown \
client/assets/characters/bodies \
client/assets/characters/clothing/buttondown_modern \
[--bodies average_m,child,...] [--offset 0.009]
@@ -38,8 +38,7 @@ boundaries give the waist opening and ankle hems. Regions are painted, not
modelled — no 3D pocket geometry (texture carries identity).
Usage (cargo_pants reference invocation):
tooling/blender --background --python \
tooling/scripts/blender/blender_author_cargo_pants.py -- \
reach blender run blender_author_cargo_pants \
client/assets/characters/bodies \
client/assets/characters/clothing/cargo_pants \
[--bodies average_m,child,...] [--offset 0.013] [--hem-frac 1.0] \
@@ -51,8 +51,7 @@ base.derive_thresholds, so the denim details stay consistent across all 11
bodies. Per-body mode only (offset shells author per body, Q-060).
Usage (jeans_modern reference invocation):
tooling/blender --background --python \
tooling/scripts/blender/blender_author_denim_pants.py -- \
reach blender run blender_author_denim_pants \
client/assets/characters/bodies \
client/assets/characters/clothing/jeans_modern \
[--bodies average_m,child,...] [--offset 0.012] [--hem-frac 1.0] \
@@ -27,8 +27,7 @@ Hoodie deltas over the base t-shirt shell:
PER-BODY ONLY (Q-060: offset-shells are authored per body, never SD-fit):
tooling/blender --background --python \
tooling/scripts/blender/blender_author_hoodie.py -- \
reach blender run blender_author_hoodie \
client/assets/characters/bodies client/assets/characters/clothing/hoodie_modern \
[--bodies a,b,c] [--offset M]
@@ -35,8 +35,7 @@ cut/paint constants — calibrated to the intended metric sizes on average_m.
PER-BODY ONLY: offset-shell garments are authored per body (Q-060 route
guidance) — there is no single-reference mode here.
tooling/blender --background --python \
tooling/scripts/blender/blender_author_jacket_shell.py -- \
reach blender run blender_author_jacket_shell \
<bodies_root> <out_dir> \
[--bodies average_m,child,...] [--offset 0.018] [--wrist-frac 0.85]
@@ -47,8 +47,7 @@ boundaries give the waist opening and ankle hems for free. Per-body mode only
(offset shells author per body, Q-060).
Usage (joggers_modern reference invocation):
tooling/blender --background --python \
tooling/scripts/blender/blender_author_joggers.py -- \
reach blender run blender_author_joggers \
client/assets/characters/bodies \
client/assets/characters/clothing/joggers_modern \
[--bodies average_m,child,...] [--offset 0.014] [--mid-offset 0.010] \
@@ -29,8 +29,7 @@ Per-body mode only (route guidance from Q-060 / 216-capture QA evidence:
offset-shell garments author per body; weights inherited by construction).
Usage:
tooling/blender --background --python \
tooling/scripts/blender/blender_author_lower_shell.py -- \
reach blender run blender_author_lower_shell \
<bodies_root> <out_dir> \
[--bodies a,b,c] [--offset 0.010] [--leg-frac 1.0] \
[--waistband-frac 1.0] [--cuff-frac 0.0] \
@@ -37,8 +37,7 @@ Painted albedo details (flat, toon-friendly; identity lives in the texture):
Per-body only (this garment ships per-body per the Q-060 route guidance):
tooling/blender --background --python \
tooling/scripts/blender/blender_author_offset_coverall.py -- \
reach blender run blender_author_offset_coverall \
<bodies_root> <out_dir> [--bodies a,b,c] [--offset 0.012]
Writes per body:
@@ -33,8 +33,7 @@ SINGLE-REFERENCE (default) — author on one body (average_m); G1
(blender_batch_fit_skinned.py) SD-fits it to the other body types. Right for
derived/hand-authored garments that share one UV layout + one mask.
tooling/blender --background --python \
tooling/scripts/blender/blender_author_offset_shell.py -- \
reach blender run blender_author_offset_shell \
<bodies_dir>/average_m <out_dir> [--offset 0.020] [--sleeve-frac 0.40]
Writes:
@@ -51,8 +50,7 @@ from each body's OWN bone landmarks using the same proportional ratios
(anchored to reproduce the hand-calibrated average_m constants exactly), so
regions stay consistent across bodies.
tooling/blender --background --python \
tooling/scripts/blender/blender_author_offset_shell.py -- \
reach blender run blender_author_offset_shell \
<bodies_dir> <out_dir> --per-body \
[--bodies average_m,child,...] [--offset 0.012] [--sleeve-frac 0.40]
@@ -36,8 +36,7 @@ consistency with torso garments (all UVs outside [0,1] → shader draws nothing)
Modes mirror the base script:
PER-BODY (preferred for offset shells, Q-060):
tooling/blender --background --python \
tooling/scripts/blender/blender_author_offset_shell_legs.py -- \
reach blender run blender_author_offset_shell_legs \
<bodies_dir> <out_dir> --per-body \
[--bodies a,b,c] [--offset 0.012] [--hem-frac 0.78] [--waistband-frac 0.35]
@@ -46,8 +45,7 @@ PER-BODY (preferred for offset shells, Q-060):
fallback for the compositor).
SINGLE-REFERENCE:
tooling/blender --background --python \
tooling/scripts/blender/blender_author_offset_shell_legs.py -- \
reach blender run blender_author_offset_shell_legs \
<bodies_dir>/average_m <out_dir> [--offset 0.020] [...]
Decisions: D-162 (clothing pre-fitted per body type), D-251 (in-house wardrobe).
@@ -25,8 +25,7 @@ What it adds over the base t-shirt shell:
Per-body only (this family is the poster child for the Q-060 per-body route):
tooling/blender --background --python \
tooling/scripts/blender/blender_author_outerwear.py -- \
reach blender run blender_author_outerwear \
<bodies_root> <out_dir> \
[--bodies a,b,c] [--offset 0.022] [--cuff-keep 0.88]
@@ -36,8 +36,7 @@ top, combining the proven practices of the wave-1 family:
Per-body only (Q-060: offset shells author per body, never SD-fit):
tooling/blender --background --python \
tooling/scripts/blender/blender_author_parka.py -- \
reach blender run blender_author_parka \
client/assets/characters/bodies client/assets/characters/clothing/parka_thrds \
[--bodies a,b,c] [--offset 0.026] [--hem-frac 0.15]
@@ -63,8 +63,7 @@ same proportional-ratio philosophy as base.derive_thresholds. Per-body mode
only (offset shells author per body, Q-060).
Usage (shoes_formal reference invocation):
tooling/blender --background --python \
tooling/scripts/blender/blender_author_shoes_formal.py -- \
reach blender run blender_author_shoes_formal \
client/assets/characters/bodies \
client/assets/characters/clothing/shoes_formal \
[--bodies average_m,child,...] [--offset 0.006] [--sole-mm 0.008] \
@@ -52,8 +52,7 @@ torso/leg companion provides, as reusable parameters:
never lands on an untinted texel.
Usage (per-body only offset shells author per body, Q-060):
tooling/blender --background --python \
tooling/scripts/blender/blender_author_slides.py -- \
reach blender run blender_author_slides \
client/assets/characters/bodies \
client/assets/characters/clothing/slides \
[--bodies average_m,child,...] [--offset 0.005] \
@@ -56,8 +56,7 @@ UV space whose islands may overlap; every painted feature is |x|-mirror
symmetric, so overlapping texels agree by construction.
Usage (sneakers_modern reference invocation):
tooling/blender --background --python \
tooling/scripts/blender/blender_author_sneakers.py -- \
reach blender run blender_author_sneakers \
client/assets/characters/bodies \
client/assets/characters/clothing/sneakers_modern \
[--bodies average_m,child,...] [--offset 0.009] [--sole-drop 0.015] \
@@ -50,8 +50,7 @@ as reusable parameters:
PER-BODY ONLY (Q-060: offset shells are authored per body, never SD-fit):
tooling/blender --background --python \
tooling/scripts/blender/blender_author_sweater.py -- \
reach blender run blender_author_sweater \
client/assets/characters/bodies \
client/assets/characters/clothing/sweater_modern \
[--bodies average_m,child,...] [--offset 0.014] [--hem-drop 0.30] \
@@ -40,8 +40,7 @@ proportional-ratio philosophy as base.derive_thresholds. Per-body mode only
(offset shells author per body, Q-060).
Usage (swim_trunks reference invocation):
tooling/blender --background --python \
tooling/scripts/blender/blender_author_swim_trunks.py -- \
reach blender run blender_author_swim_trunks \
client/assets/characters/bodies \
client/assets/characters/clothing/swim_trunks \
[--bodies average_m,child,...] [--offset 0.012] [--hem-frac 0.60] \
@@ -45,8 +45,7 @@ logo_uv TEXCOORD_1 layer ships for channel consistency (not logo-capable).
Per-body mode only (offset shells author per body, Q-060):
tooling/blender --background --python \
tooling/scripts/blender/blender_author_swimsuit.py -- \
reach blender run blender_author_swimsuit \
client/assets/characters/bodies \
client/assets/characters/clothing/swimsuit_onepiece \
[--bodies average_m,child,...] [--offset 0.012]
@@ -41,8 +41,7 @@ texture carries identity, flat toon-friendly).
Run (per-body only offset shells author per body, Q-060):
tooling/blender --background --python \
tooling/scripts/blender/blender_author_tank_top.py -- \
reach blender run blender_author_tank_top \
client/assets/characters/bodies \
client/assets/characters/clothing/tank_top \
[--bodies average_m,child,...] [--offset 0.012] \
@@ -39,8 +39,7 @@ kit needs beyond that script is delivered as reusable parameters, not hacks:
PER-BODY ONLY (Q-060: offset shells are authored per body, never SD-fit):
tooling/blender --background --python \
tooling/scripts/blender/blender_author_track_jacket.py -- \
reach blender run blender_author_track_jacket \
client/assets/characters/bodies \
client/assets/characters/clothing/track_jacket \
[--bodies average_m,child,...] [--offset 0.018] [--wrist-keep 0.90]
@@ -3,7 +3,7 @@ blender_batch_fit_skinned.py (T-1089 gap G1 — the biggest wardrobe gap)
Fit a reference clothing GLB (authored on average_m) to every body type and
export ANIMATABLE skinned variants. This supersedes
tooling/blender_surface_deform_batch.py, whose output used export_skins=False
tooling/scripts/blender/blender_surface_deform_batch.py, whose output used export_skins=False
(:142) those variants cannot animate on the shared skeleton, which is how the
runtime loads clothing (character_visual.gd:582-594).
@@ -15,7 +15,7 @@ It merges three proven codepaths that had never been combined:
Surface Deform bind -> apply -> Data Transfer VGROUP_WEIGHTS
(POLYINTERP_NEAREST) from the fitted body -> normalize -> retarget the
armature modifier to the body's armature -> export_skins=True
* optional Solidify from tooling/convert_outfit.py (skipped by
* optional Solidify from blender_convert_outfit.py (skipped by
default; offset-shell references are already solidified)
Per body type:
@@ -25,8 +25,7 @@ Per body type:
armature, export a skinned GLB.
Run:
tooling/blender --background --python \
tooling/scripts/blender/blender_batch_fit_skinned.py -- \
reach blender run blender_batch_fit_skinned \
<reference_glb> <bodies_dir> <output_dir> \
[--only average_m,average_f,...] [--solidify 0.0] [--self-check]
@@ -1,6 +1,6 @@
"""
blender_compare_bones.py
Usage: tooling/blender --background --python tooling/blender_compare_bones.py -- <file_a.glb> <file_b.glb>
Usage: reach blender run blender_compare_bones <file_a.glb> <file_b.glb>
Compares bone names between two GLB/GLTF files. Reports missing or extra bones.
"""
@@ -21,7 +21,7 @@ def get_bones(path: str) -> set:
if __name__ == "__main__":
argv = sys.argv
if "--" not in argv:
print("Usage: tooling/blender --background --python tooling/blender_compare_bones.py -- <a.glb> <b.glb>")
print("Usage: reach blender run blender_compare_bones <a.glb> <b.glb>")
sys.exit(1)
args = argv[argv.index("--") + 1:]
@@ -2,7 +2,7 @@
blender_create_clothing_refs.py
Usage:
tooling/blender --background --python tooling/blender_create_clothing_refs.py -- \\
reach blender run blender_create_clothing_refs \\
<bodies_dir> <clothing_output_dir>
Creates v0.2 placeholder reference clothing meshes for all 5 initial clothing items.
@@ -247,8 +247,7 @@ def create_reference_mesh(item_id, config, bodies_dir, output_dir):
if __name__ == "__main__":
argv = sys.argv
if "--" not in argv:
print("Usage: tooling/blender --background --python "
"tooling/blender_create_clothing_refs.py -- "
print("Usage: reach blender run blender_create_clothing_refs "
"<bodies_dir> <clothing_output_dir>")
sys.exit(1)
@@ -1,6 +1,6 @@
"""
blender_extract_armature.py
Usage: tooling/blender --background --python tooling/blender_extract_armature.py -- <input.gltf> <output.glb>
Usage: reach blender run blender_extract_armature <input.gltf> <output.glb>
Loads a Quaternius GLTF file, strips all mesh objects and animation data,
and exports only the armature as a GLB skeleton file.
@@ -82,7 +82,7 @@ def extract_armature(input_path: str, output_path: str) -> None:
if __name__ == "__main__":
argv = sys.argv
if "--" not in argv:
print("Usage: tooling/blender --background --python tooling/blender_extract_armature.py -- <input.gltf> <output.glb>")
print("Usage: reach blender run blender_extract_armature <input.gltf> <output.glb>")
sys.exit(1)
args = argv[argv.index("--") + 1:]
@@ -1,6 +1,6 @@
"""
blender_inspect_body.py
Usage: tooling/blender --background --python tooling/blender_inspect_body.py -- <input.gltf>
Usage: reach blender run blender_inspect_body <input.gltf>
Lists all mesh objects in a FullBody GLTF: names, vertex counts, vertex group counts.
"""
@@ -1,6 +1,6 @@
"""
blender_inspect_vgroups.py
Usage: tooling/blender --background --python tooling/blender_inspect_vgroups.py -- <input.gltf>
Usage: reach blender run blender_inspect_vgroups <input.gltf>
Lists vertex groups in a GLTF full-body mesh. Used to verify bone name coverage
for the segmentation script.
@@ -1,6 +1,6 @@
"""
blender_list_animations.py
Usage: tooling/blender --background --python tooling/blender_list_animations.py -- <input.glb>
Usage: reach blender run blender_list_animations <input.glb>
Lists all animation actions in a GLB file.
"""
@@ -12,7 +12,7 @@ import bpy
if __name__ == "__main__":
argv = sys.argv
if "--" not in argv:
print("Usage: tooling/blender --background --python tooling/blender_list_animations.py -- <input.glb>")
print("Usage: reach blender run blender_list_animations <input.glb>")
sys.exit(1)
args = argv[argv.index("--") + 1:]
@@ -1,6 +1,6 @@
"""
blender_list_bones.py
Usage: tooling/blender --background --python tooling/blender_list_bones.py -- <input.glb>
Usage: reach blender run blender_list_bones <input.glb>
Lists all bone names in a GLB/GLTF armature, sorted alphabetically.
Used to verify bone naming after the January 2026 Quaternius naming update.
@@ -13,7 +13,7 @@ import bpy
if __name__ == "__main__":
argv = sys.argv
if "--" not in argv:
print("Usage: tooling/blender --background --python tooling/blender_list_bones.py -- <input.glb>")
print("Usage: reach blender run blender_list_bones <input.glb>")
sys.exit(1)
args = argv[argv.index("--") + 1:]
@@ -1,6 +1,6 @@
"""
blender_process_bodies.py
Usage: tooling/blender --background --python tooling/blender_process_bodies.py -- <source_dir> <output_base_dir>
Usage: reach blender run blender_process_bodies <source_dir> <output_base_dir>
Drives the full body segmentation pipeline for all 11 body types.
Calls blender_segment_body.py logic inline (same Blender session, one pass per body type).
@@ -85,7 +85,7 @@ def write_fork_readme(output_dir, body_type, source, scale):
if __name__ == "__main__":
argv = sys.argv
if "--" not in argv:
print("Usage: tooling/blender --background --python tooling/blender_process_bodies.py -- <source_dir> <output_base_dir>")
print("Usage: reach blender run blender_process_bodies <source_dir> <output_base_dir>")
sys.exit(1)
args = argv[argv.index("--") + 1:]
@@ -1,6 +1,6 @@
"""
blender_process_hair.py
Usage: tooling/blender --background --python tooling/blender_process_hair.py -- <source_base_dir> <hair_out_dir> <facial_hair_out_dir> <eyebrows_out_dir>
Usage: reach blender run blender_process_hair <source_base_dir> <hair_out_dir> <facial_hair_out_dir> <eyebrows_out_dir>
Converts Quaternius Source tier hairstyle GLTF files (rigged to Head bone) into
production GLBs with mask PNG sidecars.
@@ -191,7 +191,7 @@ def make_bald_placeholder(glb_path: str) -> None:
if __name__ == "__main__":
argv = sys.argv
if "--" not in argv:
print("Usage: tooling/blender --background --python tooling/blender_process_hair.py -- <source_base_dir> <hair_out_dir> <facial_hair_out_dir> <eyebrows_out_dir>")
print("Usage: reach blender run blender_process_hair <source_base_dir> <hair_out_dir> <facial_hair_out_dir> <eyebrows_out_dir>")
sys.exit(1)
args = argv[argv.index("--") + 1:]
@@ -1,6 +1,6 @@
"""
blender_process_heads.py
Usage: tooling/blender --background --python tooling/blender_process_heads.py -- <source_dir> <output_dir>
Usage: reach blender run blender_process_heads <source_dir> <output_dir>
Processes the 4 Quaternius OnlyHead .blend files into the head template library.
@@ -118,7 +118,7 @@ def process_head(blend_path: str, output_dir: str, head_id: str) -> None:
if __name__ == "__main__":
argv = sys.argv
if "--" not in argv:
print("Usage: tooling/blender --background --python tooling/blender_process_heads.py -- <source_dir> <output_dir>")
print("Usage: reach blender run blender_process_heads <source_dir> <output_dir>")
sys.exit(1)
args = argv[argv.index("--") + 1:]
@@ -1,6 +1,6 @@
"""
blender_rebuild_forks.py
Usage: tooling/blender --background --python tooling/blender_rebuild_forks.py -- <source_dir> <output_base_dir> [body_type ...]
Usage: reach blender run blender_rebuild_forks <source_dir> <output_base_dir> [body_type ...]
Rebuilds ONLY the fork body types (thin_m/f, heavy_m/f, child) through the same
segmentation pipeline that produced the healthy six (blender_segment_body.py),
@@ -1,7 +1,7 @@
"""
blender_segment_body.py
Usage:
tooling/blender --background --python tooling/blender_segment_body.py -- \
reach blender run blender_segment_body \
<input.gltf> <output_dir> [--scale sx sy sz]
Segments a Quaternius FullBody GLTF into 18 production GLBs:
@@ -461,7 +461,7 @@ def segment_body(gltf_path, output_dir, scale=(1.0, 1.0, 1.0)):
if __name__ == "__main__":
argv = sys.argv
if "--" not in argv:
print("Usage: tooling/blender --background --python tooling/blender_segment_body.py -- <input.gltf> <output_dir> [--scale sx sy sz]")
print("Usage: reach blender run blender_segment_body <input.gltf> <output_dir> [--scale sx sy sz]")
sys.exit(1)
args = argv[argv.index("--") + 1:]
@@ -2,7 +2,7 @@
blender_surface_deform_batch.py
Usage:
tooling/blender --background --python tooling/blender_surface_deform_batch.py -- \\
reach blender run blender_surface_deform_batch \\
<reference_glb> <bodies_dir> <output_dir>
Fits a reference clothing GLB (authored on average_m) to all 11 body types via
@@ -352,8 +352,7 @@ def process_body_type(body_type, reference_glb, bodies_dir, output_dir):
if __name__ == "__main__":
argv = sys.argv
if "--" not in argv:
print("Usage: tooling/blender --background --python "
"tooling/blender_surface_deform_batch.py -- "
print("Usage: reach blender run blender_surface_deform_batch "
"<reference_glb> <bodies_dir> <output_dir>")
sys.exit(1)
+4 -4
View File
@@ -228,7 +228,7 @@ Include this table in a comment block in the RON file header, or maintain it sep
## Step 8: Validate and commit
```bash
tooling/validate-ron content/global/culture-{id}.ron culture
reach validate ron content/global/culture-{id}.ron culture
```
A passing validation confirms:
@@ -287,7 +287,7 @@ After validation, the culture profile is ready for Spike 1 prompt testing. Human
- [ ] 3-5 voice examples authored, range covered
- [ ] At least 1 occasional injection with suppression logic
- [ ] Tell-tone table authored (5 TellCategories)
- [ ] `tooling/validate-ron content/global/culture-{id}.ron culture` passes
- [ ] `reach validate ron content/global/culture-{id}.ron culture` passes
---
@@ -357,7 +357,7 @@ These seven categories define the interface between primitives (Mellanie, role-a
- Not "how does any person do this" but "what is the cultural tell for this culture specifically?"
2. Write the clause as a short trailing phrase (4-8 words). Test: does it read naturally after "moves freight containers ___"?
3. Avoid clauses that are too action-specific — they need to trail any verb, not just one type
4. Run `tooling/validate-ron content/global/culture-{id}.ron culture` to confirm syntax
4. Run `reach validate ron content/global/culture-{id}.ron culture` to confirm syntax
**Three-culture contrast for modifiers** (same as voice persona contrast test):
@@ -380,6 +380,6 @@ Add these items to the culture profile checklist:
- [ ] `behavior_modifiers` array populated with at least 2 clauses per category (14 minimum)
- [ ] Each clause tested: grammatically trails "moves freight containers ___" and "checks a manifest ___"
- [ ] Three-culture contrast check: modifiers are clearly distinct from Vuurkloof, Vael, and Osse
- [ ] `tooling/validate-ron` still passes after adding modifiers
- [ ] `reach validate ron` still passes after adding modifiers
*Addendum: Sprint 26, #634 (composable behavior content). Category vocabulary established jointly by Gestalt (culture modifiers) and Mellanie (behavior primitives). Add new categories only by agreement between both sides — unmatched categories silently fall back to any modifier.*
+1 -1
View File
@@ -20,7 +20,7 @@
# Assignment basis: political affiliation, NOT hop distance (D-172).
# Hop distance correlates with Compact membership but is not the rule.
#
# Pipeline: tooling/economy-db/import_economics.py → set_currency_zones()
# Pipeline: reach ledger import (economy_import/economy.py) → set_currency_zones()
# Server ticket: #805 (wires this file into the import function)
#
# Decisions: D-171 (three-currency system), D-172 (zone initialization),
+1 -1
View File
@@ -21,7 +21,7 @@
# Additions/deprecations: propose a new [tags.<axis>.<tag>] entry here AND
# wire it into at least one catalog template's allow_tags/visual_bundle in
# the same change -- the two sides move together. Importer validation
# (tooling/economy-db/economy_import/traits.py, V-TT-03/V-TT-04) is the
# (tooling/domains/ledger/economy_import/traits.py, V-TT-03/V-TT-04) is the
# mechanical enforcement of that co-maintenance contract: it hard-fails the
# import if the catalog references a tag absent from this registry, or if
# this registry's fallback graph doesn't resolve to a generic placeholder --