New generate_brands binary reads 126 brand archetype templates (wiki/economics/archetypes/brand_templates.toml), assigns halo+volume pairs to all 48 hand-authored corps, outputs wiki/economics/corporations/generated_brands.toml. Result: 10,000 brand_product rows, 26,750 brand_inputs, all 48 corps covered. Brand structural validation V-B01..V-B06 passes. Generated file is gitignored (regenerated on each `make economy-db` run). make economy-db now runs generate-brands before import_economics.py. import_economics.py merges generated_brands.toml alongside hand-authored brands.toml. Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
7.4 KiB
title, description, type, status, ticket, author, created, updated
| title | description | type | status | ticket | author | created | updated |
|---|---|---|---|---|---|---|---|
| Bincode v1 → v2 Migration — Risk Audit (Sprint 36) | Audit of bincode usage in the server crate, risk assessment, and migration recommendation for ticket #636. | architecture | final | #636 | Tyre | 2026-04-19 | 2026-04-19 |
Bincode Migration — Risk Audit
Ticket: #636 (Migrate bincode v1.x to v2.x) Advisory: RUSTSEC-2025-0141 (bincode v1.3.3 unmaintained) Author: Tyre TL;DR: bincode is an orphan dependency — nothing in the server crate actually calls it. Remove it outright. The "migration" is a four-line change.
1. What the audit found
Grep-audit of the entire repository, not just server/src/:
grep -rn "use bincode\|bincode::" server/ tests/ tooling/ --include="*.rs"
# → 0 hits
Cargo manifest references:
grep -rn "bincode" server/ --include="*.toml" --include="*.lock"
# → server/Cargo.toml:19 bincode = "1"
# → server/Cargo.lock:329 [[package]] name = "bincode" version = "1.3.3"
# → server/Cargo.lock:1311 " bincode"," — under settled-reach-server deps
# → server/audit.toml:6 ignore = ["RUSTSEC-2025-0141"]
No Rust source file in any crate (server/, tests/, tooling/) contains the string bincode. The lockfile entry under tooling/test-client shows bincode transiting through rmp-serde or a sibling — not from direct use.
Conclusion: bincode = "1" in server/Cargo.toml was added in anticipation of save-load / Rust-Rust sync (see docs/workshops/v01-gap-analysis/round1-tyre.md, docs/workshops/save-load-architecture/workshop-brief.md) but the implementation path chose rmp-serde / MessagePack instead (see server/src/bridge/types.rs — tests use rmp_serde::to_vec_named and rmp_serde::from_slice, line 1052 onward).
Bincode is a dead dependency.
2. Recommended migration: DELETE, don't bump
2.1 The actual changes
server/Cargo.toml — remove line 19:
-bincode = "1"
server/audit.toml — remove the ignore (lines 5–9):
-[advisories]
-# RUSTSEC-2025-0141: bincode v1.3.3 is unmaintained.
-# Migration to bincode v2 or an alternative is tracked in ticket #636.
-# This ignore can be removed once #636 is resolved.
-ignore = ["RUSTSEC-2025-0141"]
(If removing the whole [advisories] section leaves audit.toml empty, either delete the file or leave the file with just a header comment — check .config/cargo-audit/ or the Makefile for how cargo audit is invoked.)
server/Cargo.lock — regenerate by running cargo check in server/. Verify bincode no longer appears.
2.2 Verification
# 1. No source regressions:
grep -rn "bincode" server/ tests/ tooling/ --include="*.rs"
# Expected: 0 hits.
# 2. Clean build:
cargo check --workspace --all-features
# 3. Clean tests:
cargo test --workspace
# 4. Audit is green without the ignore:
cargo audit
# Expected: no RUSTSEC-2025-0141 mention.
# 5. cargo-deny (once #726 lands):
cargo deny check
2.3 Risk assessment
| Risk | Likelihood | Impact | Mitigation |
|---|---|---|---|
Hidden use bincode I missed |
Near-zero | Build break | Covered by §2.2 step 1 grep + cargo check |
| Proc-macro or build.rs pulling bincode | Near-zero | Build break | No build.rs in server crate; no proc-macro deps use it |
| Transitive need (some crate depends on it) | Zero | N/A | Transitive deps come through lockfile without a manifest entry |
| Future save-load work expects it in manifest | Low | Re-add | If save-load lands with bincode later, re-add bincode = "2" then — fresh v2 install, no migration |
All four risks are trivially mitigated. Net risk: ~0.
3. If the team decides to keep bincode — the v1 → v2 cheat sheet
Included for completeness even though §2 is the recommendation. If save-load (#553, D-085) or a future Rust↔Rust server-sync feature decides to use bincode, adopt it fresh at v2 with these signature changes:
3.1 The core API difference
v1 (current, unmaintained):
// Relies on serde Serialize/Deserialize derives.
let bytes: Vec<u8> = bincode::serialize(&value)?;
let value: MyType = bincode::deserialize(&bytes)?;
v2 (stable):
// New "Encode"/"Decode" derives, explicit config.
use bincode::{config, encode_to_vec, decode_from_slice};
let cfg = config::standard();
let bytes: Vec<u8> = encode_to_vec(&value, cfg)?;
let (value, _used): (MyType, usize) = decode_from_slice(&bytes, cfg)?;
Derive change: v2 introduced its own #[derive(bincode::Encode, bincode::Decode)] traits. If the type must stay serde-compatible (required for us — we use rmp-serde and ron side-by-side), use the compat shim:
use bincode::serde::{encode_to_vec, decode_from_slice};
let bytes = encode_to_vec(&value, config::standard())?;
let (value, _) = decode_from_slice::<MyType, _>(&bytes, config::standard())?;
This keeps #[derive(Serialize, Deserialize)] as the only derives on the data types — no dual-derive required. That matters because the same types cross the MessagePack boundary via rmp-serde.
3.2 Config
v2 makes encoding config explicit. config::standard() uses variable-int, little-endian — matches v1 default for our types (no floats in the save shape today, so endian parity is not critical). For perfectly-byte-identical output to v1, use config::legacy(). Any new adoption should use config::standard() — don't inherit v1 quirks.
3.3 Known gotchas (for future reference)
- v2 does not auto-handle untagged serde enums in the compat layer (pre-v2.0.1); if we adopt it and hit an untagged enum, use
bincode::serde::Compat. - v2's
decode_from_slicereturns the byte count consumed — v1 silently ignored trailing bytes. Useful for streaming multi-message frames; irrelevant for one-shot save files. - The
bincode::options()builder from v1 (with_fixint_encoding()etc.) is gone — replaced byconfig::Configuration. - Binary format is not compatible across v1 ↔ v2. Any v1-written blob is unreadable by v2. (This is moot for us — we have none.)
3.4 Touch points if we were actually migrating
None. Literally no source file imports or uses it.
4. For Dudley — execution checklist
- Delete
bincode = "1"fromserver/Cargo.toml. - Delete the
RUSTSEC-2025-0141ignore block fromserver/audit.toml. cargo check --workspace— regeneratesCargo.lock.cargo test --workspace— must pass.cargo audit— must not print RUSTSEC-2025-0141 anymore.- Commit:
fix(deps): remove unused bincode dependency (#636) RUSTSEC-2025-0141 no longer relevant — bincode was declared but never imported. Drop the crate and the audit ignore. Future save-load work that wants bincode should adopt v2 fresh.
Estimated effort: ~15 minutes including verification.
5. What this means for docs
One doc to update: docs/sprints/sprint-27/server.md line 93 mentions the audit ignore. Either leave it (it's historical notes) or strike through. Not blocking.
Audit status: Complete. Recommendation: remove bincode entirely. If the team prefers "migrate now, don't remove" (symbolic commitment to the migration path), say the word and I'll spec that instead — but it costs more with zero benefit given the usage survey.