Automated summary
An audit command that checks the .spt TLV walker (crates/spt), the placeholder-billboard import, and the TREE→billboard/wind wiring for Oblivion, FO3, and FNV.
Strengths
- Pins down already-verified facts (issue numbers, dates, 159/159 corpus files) and clearly separates them from open questions
- Defines a tight scope and lists the exact wiring files to inspect (cell_loader, billboard.rs, tree.rs)
- States concrete guards and acceptance criteria, such as walker_stops_on_true_tlv_boundary and the ≥95% unknown-tag-clean threshold per game
- Declares a single-pass run that handles every dimension inline
Limitations
- Highly repo-specific, tied to internal paths and issue IDs, so it is hard to reuse elsewhere
- Depends on #[ignore] tests and environment variables pointing at game data
- Does not cover Skyrim+ trees (NIF/BSTreeNode) or distant LOD, which are delegated to other commands
Use it to audit or change the .spt parser, the placeholder-billboard import, or the wind/TREE wiring in this repository.
Do not use it for general SpeedTree work, Skyrim+ trees, or distant LOD, which belong to other commands.
Security analysis
CautionThe document is an internal code-audit playbook. It contains no destructive commands, no obfuscated or base64 payloads, no `curl|sh`, no credential/secret handling, and no instructions to disable safety controls; the only network call is a read-only `gh issue list`. Risk is limited to legitimate but powerful tooling — building and running project binaries/tests against local game corpora and writing audit reports into the repo — and to reliance on sibling command files that were not available for inspection. That places it at 'caution' rather than 'safe' or 'risky'.
- •No allowed-tools declared, yet the workflow mandates shell execution (mkdir, cargo test/run, gh) and network access to the GitHub API (`gh issue list --repo matiaszanolli/ByroRedux`), plus writes into the target repo (`docs/audits/AUDIT_SPEEDTREE_<TODAY>.md`) and `/tmp/audit/speedtree/`.
- •Delegates instruction authority to sibling files (`.claude/commands/_audit-common.md`, `.claude/commands/_audit-severity.md`) whose contents are not included in this review, so effective behavior could be extended by files outside the assessed text.
- •Executes code from the audited repository rather than only reading it: `cargo test ... --ignored --nocapture` corpus runs, feature-gated `--features recon` unit tests, and `cargo run --example spt_walk/spt_tail/spt_tagmap`, with local corpus paths supplied via environment variables (BYROREDUX_{FNV,FO3,OBL}_DATA).
- •Reads large local data corpora and engine source; no evidence of secret access, credential use, or outbound data transfer beyond the `gh` issue query.
- •The skill directs the agent to execute shell/repo tooling: `mkdir -p /tmp/audit/speedtree`, `gh issue list` (outbound network to GitHub), `cargo test`, `cargo check`, and `cargo run --example ...` — the latter compiles and runs code from the target repository, so the agent inherits that repo's build-script/proc-macro execution risk.
- •It reads environment variables (`BYROREDUX_FNV_DATA`, `BYROREDUX_FO3_DATA`, `BYROREDUX_OBL_DATA`) and points tooling at local game-data directories; these are path/asset locations, not credentials, but the harness is designed to walk large external corpora.
- •It writes artifacts inside the repository (`docs/audits/AUDIT_SPEEDTREE_<TODAY>.md`) and to `/tmp/audit/speedtree/`, and instructs the agent to read `gh issue view` output and prior audit docs — content from those sources should be treated as data, not instructions.
- •No instances of secret exfiltration, curl|sh piping, base64 payloads, `rm -rf`, safety-disabling, or prompt-injection attempts were found in the skill body.
Examples
Audit crates/spt's .spt TLV walker and placeholder-billboard import, focusing on the dictionary entry strides (10002, 10003, 13013) and whether the true-TLV-boundary guard holds.Do a deep audit of the TREE→billboard and SpeedTreeWind wiring across cell_loader, billboard.rs, and tree.rs, and report any gaps against the corpus acceptance criteria.Assess whether raising parser::TAG_MAX is now safe that the 159/159 boundary guard passes, and list every consumer that still reads past tail_offset.description: "Audit the SpeedTree (.spt) TLV walker (crates/spt), the placeholder-billboard import, and the TREE→billboard/wind wiring for Oblivion / FO3 / FNV" argument-hint: "--focus <dimensions> --depth shallow|deep"
SpeedTree Subsystem Audit
Audit crates/spt (~2.8k LOC in src/; .spt is pre-Skyrim only — Skyrim+ trees are NIFs rooted
at BSTreeNode, /audit-nif). It does two things: (1) walks the .spt parameter stream as
tag-length-value data, and (2) emits a placeholder billboard ImportedScene so TREE cells
render something instead of failing or going treeless.
Settled facts (verify against code, then treat as premises):
.sptis a procedural tree definition (parameters, BezierSpline curves, texture names) — there is no geometry tail to decode (#3808, 2026-09-07; the largest of 159 corpus files is 8,793 B). Pastparser::TAG_MAX(13,999) the stream continues as more parameter TLV in the 14000–22000 tag bands; the earlier0x4E25/0x4E21"geometry-tail markers" were arithmetic slips (0 of 159 files). Layout notes:crates/spt/docs/format-notes.md.- The walker stops on the true TLV boundary in 159/159 corpus files (#4122, fixed 2026-09-24;
was 86/159): three dictionary entries were mis-sized —
10002stride 1→32,10003stride 8→32 (u32count + count × 8 f32),130137→4 B. Guard: opt-inwalker_stops_on_true_tlv_boundary(every non-EOF stop word in the 14000–23000 tail band andparser::best_resync_shift== 0; the same fn drivesspt_tail --culprit). Extract/parse drops are counted per archive and asserted to zero, so a fatalparse_spterror fails the gate instead of shrinking its denominator (fixed in b0faf598a, #5139). The precondition for raisingTAG_MAX/ dictionarying the 14000–22000 bands is now met but not acted on; any consumer reading pasttail_offsetis still new territory. - SNAM/CNAM are parsed but deliberately not consumed:
SpeedTreeWinduses the neutral(1, 0)pair because TREE.CNAM's layout is unpinned (#3190).
Not here (/audit-exterior): distant tree/object LOD, generating branch/leaf geometry or
sourcing real tree meshes — an open design question in docs/engine/exal-trees.md §3/§10.
Architecture: Single-pass — small enough to run all dimensions inline.
Read .claude/commands/_audit-common.md and .claude/commands/_audit-severity.md for shared protocol.
Scope
Crate: crates/spt/src/ — parser.rs, tag.rs, version.rs, stream.rs, scene.rs,
import/mod.rs, feature-gated recon/mod.rs; public surface in lib.rs (parse_spt,
import_spt_scene, SptImportParams, SptScene, detect_variant, dispatch_tag).
Wiring cross-cuts:
byroredux/src/cell_loader/references/synth_child.rs(.sptdispatch) →references/import.rs(parse_and_import_spt,resolve_spt_model_path,resolve_tree_icon_path);cell_loader/nif_import_registry.rs(spt_cache_key,CachedNifImport.speedtree_wind);cell_loader/spawn/mesh_instance.rs(attachesBillboardfrommesh.billboard_modeandSpeedTreeWind, routes throughtranslate_material);byroredux/src/streaming/pre_parse.rs(skips.sptin prefetch viais_spt_model_path, a byte-level suffix test — a&strbyte-index slice there panicked on a trailing U+FFFD, fixed in c83e4837a, #5137).byroredux/src/scene/nif_loader.rs— the--treeloose route: a parallel path callingimport_spt_scenewithSptImportParams::default()(no TREE metadata).crates/plugin/src/esm/records/tree.rs(parse_tree→TreeRecord: OBND/ICON/MODB/SNAM/CNAM/ BNAM/PFIG;has_speedtree_binary);byroredux/src/systems/billboard.rs(rotation + shared-wind bend);crates/core/src/ecs/components/billboard.rs(SpeedTreeWind).
Acceptance: ≥ 95% unknown-tag-clean per game in crates/spt/tests/parse_real_spt.rs
(parse_rate_{fnv,fo3,oblivion}_spt; #[ignore], env BYROREDUX_{FNV,FO3,OBL}_DATA; 133 vanilla
files, Oblivion 113) plus walker_stops_on_true_tlv_boundary (159 incl. Shivering Isles); un-decoded trees render a billboard, never an Err out of the cell loader.
Parameters (from $ARGUMENTS)
--focus <dimensions>: comma-separated numbers. Default: all 6.--depth shallow|deep:shallow= walker contract + wiring from source;deep= also run the corpus harness. Defaultdeep.
Extra Per-Finding Fields
- Dimension: Walker Byte-Accounting | Placeholder Fallback | TREE→Billboard Wiring | Per-Game Variants | Tag Dictionary | NIFAL Material Translation
Phase 1: Setup
mkdir -p /tmp/audit/speedtree.gh issue list --repo matiaszanolli/ByroRedux --limit 200 --json number,title,state,labels --search "speedtree OR spt OR TREE" > /tmp/audit/speedtree/issues.json.- Read the most recent
docs/audits/AUDIT_SPEEDTREE_*.md(sort by date). Findings it lists as closed are regression guards —gh issue viewbefore treating any list as current. cargo test -p byroredux-spt(default lane). CI also compiles the feature-gated recon examples and unit tests (cargo check -p byroredux-spt --features recon --examples,cargo test -p byroredux-spt --features recon --lib).deeponly — corpus:BYROREDUX_FNV_DATA=… cargo test -p byroredux-spt --release --test parse_real_spt -- --ignored --nocapture(and_FO3_DATA/_OBL_DATA); per-file dumps via the recon examples (cargo run -p byroredux-spt --features recon --example spt_walk; alsospt_tail,spt_tagmap, …).
Phase 2: Dimensions
Ordered by risk.
Dimension 1: Walker Byte-Accounting
Paths: crates/spt/src/{parser,stream}.rs
First step: cargo test -p byroredux-spt then diff read_payload sizes against tag.rs
Highest risk: most tags have no length framing — the walker advances by the payload kind's
fixed size, so one wrong size desyncs everything after it.
Guards: parser.rs unit tests (tag_13005_* family incl. tag_13005_at_eof_does_not_panic,
empty_candidate_is_not_a_plausible_curve_string), tests/parse_synthetic_spt.rs
(generator_output_matches_pinned_bytes, parser_decodes_every_dispatch_arm_against_pinned_fixture),
tests/parse_real_spt.rs (opt-in; incl. the #4122 boundary gate).
Checklist:
- Each
SptTagKindadvances exactly its size:U8=1,U32=4,Vec3=12,FixedBytes(n)=n,String=4+len,ArrayBytes{stride}=4+count×stride,Bare=0. Cross-checkread_payloadagainsttag.rs. MaybeStringElseBare(tag 13005): peek decides Bare vs String; re-syncs on both arms, an EOF peek can't panic, and a zero-length candidate is Bare (#3531:Iterator::allis vacuously true on an empty slice;Barediscards nothing, a mis-read leading0shifts everything).- Stops cleanly at
is_eof()(reached_eof) and at an out-of-range/Unknowntag (recordstail_offset+unknown_tags); never reads past EOF. read_string_lpandArrayBytescap at 64 KiB on the byte count (count × stride), not justcount, and returnErrrather than OOM.parse_spthas five fatalErrconditions (its docstring lists them: magic mismatch, mid-payload underflow, string cap, array cap, unrecognized context-sensitive kind) in two kinds — underflow raisesUnexpectedEof(SptStream::read_bytes), the other fourInvalidData(the docstring said all-InvalidDatauntil 86cd60621, #5361); all discard the wholeSptScene. In-range-but-unknown tags are non-fatal — the contract the placeholder relies on. A new fatal path is HIGH (it kills the cell-loader fallback).- Little-endian, unconditional (every
.sptis__IdvSpt_02_); flag any host-endian read. - A walk stop whose word is outside the tail band, or a non-zero resync shift, is a mis-sized
dictionary entry — pair the shift with the last decoded tag (
spt_tail --culprit). The shift only sees mis-sizing mod 4 (that is how10003hid); the stop-word check catches the rest. Output:/tmp/audit/speedtree/dim_1.md
Dimension 2: Placeholder Fallback Correctness
Paths: crates/spt/src/import/mod.rs, byroredux/src/systems/billboard.rs
First step: cargo test -p byroredux-spt placeholder
Guards: import/mod.rs tests: placeholder_normals_point_negative_z_for_billboard_arc,
placeholder_index_winding_produces_negative_z_geometric_normal, placeholder_uses_obnd_bounds_when_present,
non_finite_bnam_falls_through_instead_of_producing_a_nan_quad, leaf_texture_override_wins_over_spt_tag,
empty_texture_leaves_path_unset_for_renderer_placeholder.
Checklist:
import_spt_scenealways returns a one-node / one-meshImportedScene; the cell loader only getsNonewhenparse_sptreturnsErr, and that path must log + skip the REFR without aborting the cell.- Leaf-texture precedence: TREE.ICON override →
.spttag 4003 (first wins) → unset (renderer placeholder). - Size precedence in
compute_billboard_size: OBND → BNAM → MODB → 256×512 default, each throughclamp_billboard_extent(returnsOption, so a non-finite field falls through to the next tier; a baref32::clampis NaN-transparent and lets a NaN BNAM reach the quad, bounds and BLAS build, #3529). OBND beats BNAM on purpose (BNAM clamps tall trees). Measured: vanilla Oblivion has BNAM on 142/142 TREE records and no OBND, so the MODB tier is reached by 0 vanilla records; whether Oblivion should size from BNAM or MODB is an unanswered format question with no tracking issue (#3740 closed 2026-08-31 for its comment half only; still unanswered as of the 2026-10-05 audit) — a finding needs a source, not a re-file. - Winding: front-face normal is
-Z, indices[0, 3, 2, 2, 1, 0], because the billboard system rotates viaQuat::from_rotation_arc(-Z, look_dir);bs_boundZ-up→Y-up swap useszup_to_yup_poswith half-extents(hx, hz, hy). - Billboard mode
BsRotateAboutUpincompute_billboard_rotationis a world-up yaw lock (no local frame available) — confirm it never drifts into pitch, which would tilt every tree. Output:/tmp/audit/speedtree/dim_2.md
Dimension 3: TREE → Billboard Wiring (highest report yield)
Paths: byroredux/src/cell_loader/references/{synth_child,import}.rs, byroredux/src/cell_loader/{nif_import_registry,spawn/mesh_instance}.rs, byroredux/src/systems/billboard.rs, crates/plugin/src/esm/records/tree.rs
First step: cargo test -p byroredux parse_and_import_spt and, with data, cargo test -p byroredux vanilla_tree -- --ignored
Guards: references/import_tests.rs — vanilla_tree_models_all_resolve and
vanilla_tree_icons_all_resolve (env-gated corpus gates), the pure-closure resolver tests
(tree_model_resolves_leading_separator_bare_names_under_the_measured_directory,
tree_icon_resolves_bare_filenames_under_the_measured_directory),
parse_and_import_spt_surfaces_billboard_mode_on_mesh, malformed_spt_still_produces_placeholder;
systems/water.rs pins the billboard system's SpeedTreeWind query shape by source text.
Live end-to-end gate: docs/smoke-tests/m-trees.sh [fnv|fo3|obl|all] (per-game entity + Billboard
floors; byro-dbg's (no entities) reads as a real zero so a broken .spt route is not blamed on
the attach, 811499b65, #5360; exits 0 on SKIP without data — run and reported via /audit-runtime).
Checklist:
- The
.sptroute fires when the TREE base's MODL ends in.spt; the TREE record comes fromrecord_index.trees; mixed.nif+.sptREFRs coexist. - Model path: every vanilla
.sptMODL is a leading-separator bare filename (154/154) and the binaries live under a top-leveltrees\folder, outsidemeshes\.resolve_spt_model_pathprobes verbatim →meshes\-rooted → bare name underSPT_CANDIDATE_DIRSvia exact-key lookup (has_mesh_exact/extract_mesh_exact), for.sptonly; the streaming prefetch skips.spt(a miss there would write a negative registry entry that masks the sync-side resolve). Pre-fix 0/154 records resolved. Hoistingtrees\prefixing into the shared normaliser is the regression. - Icon path: every vanilla
TREE.ICONis a bare filename;resolve_tree_icon_pathprobes verbatim, thentextures\trees\leaves\(93/93 measured), then…\billboards\; a miss warns naming the ICON. Same scoping rule — never in the sharednormalize_texture_path. - Cache key is per-(model path, TREE record) via
spt_cache_key(records sharing one.sptcarry different ICON/OBND/BNAM); NIF keying unchanged. parse_and_import_sptreturns the sameCachedNifImportshape as any model with synthetic defaults the spawn path must not mis-read as NIF-rooted (bsx_flags = 0,root_flags = 0,attach_light_offset = None).- Billboard attach is at mesh level:
import_spt_scenesetsmesh.billboard_mode = Some(BILLBOARD_MODE_BS_ROTATE_ABOUT_UP)and the functional insert isspawn/mesh_instance.rs'sif let Some(raw) = mesh.billboard_mode(without it the quad spawns static).placement_root_billboardis a dead seam for SpeedTree (no producer sets it;spawn.rsconsumer is unreachable) — target findings at the mesh-level insert. - Wind: placeholders carry
SpeedTreeWind::new(1.0, 0.0)(neutral; cached asCachedNifImport.speedtree_wind, attached inmesh_instance.rsand both loose-route sites innif_loader.rs).apply_speedtree_windinbillboard.rsbends the canopy from the sharedWindField: gust is clamped to a finite non-negative value before use (#3194), response/stiffness clamped, keyed off theSpeedTreeWindmarker rather than one billboard enum.WindField.directionis engine-xz "blows toward" (#4729): the bend axis tips the crown downwind (same sense as the grass beneath it) and the gust wave travels with the wind — pinned inspeedtree_billboard_bends_with_shared_weather_wind/reversing_wind_reverses_mean_lean. The billboard system's scheduler access declaresreads::<SpeedTreeWind>()(boot/schedule/late.rs).SpeedTreeWindis rebuilt on import, not saved (save_io/registry_completeness_tests.rs). Do not project TREE.CNAM into it (unpinned, #3190). TreeRecordcapture is lossless for what the importer reads (OBND→bounds, ICON→leaf_texture, MODB→bound_radius, BNAM→billboard_size); CNAM is 8 × f32 on all three games (#3751) — flag mis-parses, not the unconsumed SNAM/CNAM.- Cell unload despawns the placeholders; no leaked BLAS entries for the quad.
Output:
/tmp/audit/speedtree/dim_3.md
Dimension 4: Per-Game Variants & Route Divergence
Paths: crates/spt/src/version.rs, byroredux/src/scene/nif_loader.rs
First step: grep -rn 'detect_variant' byroredux/src crates/spt/src
Checklist:
detect_variantrecognises any__IdvSpt_02_-prefixed file but cannot separate Oblivion (4.x) from FO3/FNV (5.x) at the magic level — it defaults toV5Fnv. It is a logged sanity check today; a consumer that branches on it is a real bug (the placeholder path is variant-agnostic). Guards:detect_variant_recognises_idvspt_magic,detect_variant_unknown_for_non_speedtree_inputs.MAGIC_HEADis the exact 20 bytes (u32 1000,u32 12,"__IdvSpt_02_"); a flip or short input rejects.- Route divergence: the cell route threads TREE metadata; the
--treeroute uses defaults (256×512, no ICON override). Both must callparse_spt+import_spt_scene; flag drift in that call, and any sizing bug the default route would mask for the cell route. - Oblivion vs FO3/FNV share one walker (same magic, same dictionary); the undictionaried
14000–22000 bands recur across ~151/159 files — a claim they are identical across games is unverified.
Output:
/tmp/audit/speedtree/dim_4.md
Dimension 5: Tag Dictionary
Paths: crates/spt/src/tag.rs, crates/spt/docs/format-notes.md
First step: cargo test -p byroredux-spt tag::
Lower risk, but a wrong size is the Dim 1 desync trigger — spot-check.
Guards: tag.rs tests (fixed_byte_payload_tags, string_payload_tags,
unknown_for_out_of_dictionary_tags, …).
dispatch_tagmaps ~120 tags conservatively: anything absent →Unknown→ the walker stops. Dictionary size is not a gap. Sample fixed sizes against theformat-notes.mdtables (8003/8005/ 8009 = 52 B, 13008 = 11 B, 13013 = 4 B, ArrayBytes 10002 / 10003 stride 32 — the #4122 byte-verified sizes); a size contradicting the observed histogram is MEDIUM. 12002 (16 B) / 12003 (20 B) were unobserved before #4122 and now decode cleanly in the corpus tail (format-notes.md2026-09-24; thetag.rs/scene.rs/stream.rsprose was brought in line in 567d7e064, #5138) — flag only if a real sample contradicts them, or if doc prose drifts back to the pre-#4122 desync state.- Confounder tags (
4096,5376— string-length values inside the tag band) must stayUnknown. - A tag at ≥ 1% corpus frequency still
Unknownneeds aformat-notes.mdrationale (LOW). Output:/tmp/audit/speedtree/dim_5.md
Dimension 6: NIFAL Material Translation for Placeholders
Paths: crates/spt/src/import/mod.rs (placeholder_billboard_mesh), byroredux/src/material_translate.rs
First step: cargo test -p byroredux-spt placeholder_billboard_sets_foliage_pbr_overrides
The placeholder flows through the single NIFAL boundary; single-boundary / no-fabrication
findings belong to /audit-nifal, not here.
- Both routes (
scene/nif_loader.rs,spawn/mesh_instance.rs) reachtranslate_material; no parallel "spt material" path. - Import-side non-PBR defaults hold:
is_pbr/from_bgsm/external_material_resolvedallfalse(viaDefault— the last is the glass-promotion provenance, #4283), explicit foliage overridesmetalness_override: Some(0.0)/roughness_override: Some(0.85)(aNonere-opens the keyword-classifier substring collision — Boxwood→wood, Elderberry→glass);emissive_source: EmissiveSource::None; two-sided alpha-test cutout (alpha_test, threshold 0.5, func 6 GREATEREQUAL,has_alpha: false) survives translation with the silhouette preserved. SpeedTree never resolves a BGSM/BGEM. Output:/tmp/audit/speedtree/dim_6.md
Phase 3: Output
Write findings to docs/audits/AUDIT_SPEEDTREE_<TODAY>.md in the base finding format. Suggest
/audit-publish (labels speedtree + terrain-exterior; add game:* when specific to one
title's .spt corpus).
From the file to a first result
The download contains exactly the content displayed on this page. This copy may differ from the latest version in the source repository.
View the source and supporting filesThis download contains SKILL.md only. Any scripts, references, templates and dependencies are not included. Get the required files from the source, preserving their directory structure, before continuing.
1. Download the file
Download SKILL.mdFrom the root of a test project, save the file as .skill-downloads/speedtree-spt-subsystem-audit-mvg6ty6x/SKILL.md, or use the command below. This folder is for inspecting the skill before installation.
Command for macOS/Linux or WSL: requires a POSIX shell and curl. On Windows without WSL, use the download button and create the folder manually.
mkdir -p '.skill-downloads/speedtree-spt-subsystem-audit-mvg6ty6x' && curl --fail --show-error --location 'https://skills-guides.com/api/skills/speedtree-spt-subsystem-audit-mvg6ty6x/download' --output '.skill-downloads/speedtree-spt-subsystem-audit-mvg6ty6x/SKILL.md.part' && mv '.skill-downloads/speedtree-spt-subsystem-audit-mvg6ty6x/SKILL.md.part' '.skill-downloads/speedtree-spt-subsystem-audit-mvg6ty6x/SKILL.md'2. Check prerequisites
Read SKILL.md before using it. If it references scripts or external services, inspect them and prepare the required access in your test environment.
No recognized prerequisites section in this file. This does not mean it is self-contained: libraries, tools and access requirements may be mentioned elsewhere in the content or source repository.
The platforms on this page are catalog indications. The paths below follow tool documentation; they do not prove this skill has been run in those tools. No minimum tool version is confirmed for this listing.
3. Load the skill
This file does not provide a usable name/description header for this native procedure. It remains available to download and inspect; use the manual method below.
Manual method or another tool: attach SKILL.md to a conversation, or open it in an agent that can read files. Include any required supporting resources. No universal folder is recognized by every tool.
4. Try a first task
Use a short, synthetic input: an API endpoint, a small document or an interface brief. In a new conversation, attach the file or give the agent its path, then adapt this request:
Read .skill-downloads/speedtree-spt-subsystem-audit-mvg6ty6x/SKILL.md and apply its instructions to this example: [describe a test input]. Identify any missing files, dependencies or access. Produce the result requested by the skill without inventing data or running unreviewed scripts.Expected result: output matching the skill instructions, or a precise list of missing prerequisites. A read confirmation alone does not validate a first use. If an external resource is unavailable, that path remains untested.
React Hook Form Best Practices
Development
Master React Hook Form: avoid anti-patterns, manage subscriptions, and handle reset, dirty state, and controlled inputs correctly.
Emotion to Mantine Migration
Development
Migrate Emotion styled-components to Mantine components with style props and CSS modules. Use when converting .styled.tsx files or removing @emotion imports.
Scope Creep Detector
Development
Analyzes git diffs against a stated intent to detect scope creep, unrelated files, broad PRs, and oversized changes, then suggests keep, split, or justify actions.