Team Infrastructure Migration Guide
Overview
The team system has been consolidated into a unified plant_team crate at /home/srussell/src/plantangenet/team/. This guide explains how to migrate code that previously used team infrastructure from the classic game crate.
What Changed
Before (Classic Game)
Team infrastructure was defined in game/src/classic/team/:
use plant_game::classic::team::{Team, Slogan, TeamAttachmentRegistry, validate_projection};
After (plant_team)
Team infrastructure is now defined in plant_team:
use plant_team::{Team, Slogan, TeamAttachmentRegistry, validate_projection};
Migration Steps
1. Update Cargo.toml
Add plant_team to your crate's dependencies:
[dependencies]
plant_team = { workspace = true }
2. Update Imports
Replace imports from plant_game::classic::team with imports from plant_team:
Old:
use plant_game::classic::team::{
Team, Slogan, TeamRegistry,
TeamAttachment, TeamAttachmentRegistry,
ProjectionRequest, ProjectionOutcome, RejectionReason,
validate_projection,
TeamConfig, TeamParticipationRegistry, TeamLeagueRequest,
};
New:
use plant_team::{
Team, Slogan, TeamRegistry,
TeamAttachment, TeamAttachmentRegistry,
ProjectionRequest, ProjectionOutcome, RejectionReason,
validate_projection,
TeamConfig, TeamParticipationRegistry, TeamLeagueRequest,
};
3. No Code Changes Required
The API is identical. Your existing code should work without modification once imports are updated.
Core Team Types
Team
A brand-bound identity projection construct.
new()- Create a new teamadd_slogan()- Add a slogan to the team's catalogget_slogan()- Look up a slogan by IDremove_slogan()- Remove a slogan from the catalogwith_max_active_slogans()- Set a soft cap on active slogans
Slogan
A lightweight, portable projection unit published by a Team.
new()- Create a new sloganwith_contexts()- Restrict to specific contextswith_ttl()- Set frame lifetimewith_coherence()- Set coherence hint (0.0-1.0)permits_context()- Check if slogan is permitted in a context
TeamAttachmentRegistry
Bidirectional index of agent ↔ Team attachments.
new()- Create a new registryattach()- Record an agent's opt-in to a Teamdetach()- Remove an agent's attachmentis_attached()- Check if agent is attached to teamteams_for_agent()- Get all teams an agent is attached toagents_for_team()- Get all agents attached to a teamcan_project()- Check if agent can emit slogans for team
ProjectionRequest
A request to emit a Team slogan into a named context.
new()- Create a projection request with agent, team, slogan, and context
ProjectionOutcome
Result of validate_projection():
Accepted- Request is validRejected(RejectionReason)- Request was rejected
RejectionReason
Why a projection was rejected:
NotAttached- Agent is not attached to the TeamSloganNotFound- Slogan doesn't exist in Team's catalogContextNotPermitted- Slogan not permitted in requested contextCapExceeded- Agent exceeded Team's soft cap
TeamConfig
Static configuration for a brand-affiliated team.
new()- Create a team config (const fn)participations()- Get league enrollment registryattachment_registry()- Create fresh attachment registryis_supporter()- Check if agent is attachedleague_request()- Build a generic projection requestsupporter_request()- Build request only if attached
Classic Game-Specific Extensions
For classic game code that needs league integration, use the helper function:
use plant_game::classic::team::config::team_config_identity;
let config = TeamConfig::new(...);
let team_influencer = team_config_identity(&config);
This creates a TeamInfluencer for use with the league system.
Testing
The impl_standard_team_tests! macro is available from plant_team:
use plant_team::{TeamConfig, impl_standard_team_tests};
const MY_TEAM: TeamConfig = TeamConfig::new(
"my-team",
"My Team",
"my-team",
&["league_a", "league_b"],
);
#[cfg(test)]
mod tests {
use super::*;
impl_standard_team_tests!(MY_TEAM);
}
This generates three structural tests:
identity_is_stable()- Verify identity fields match configenrolled_in_expected_leagues()- Verify league enrollmentssupporter_attachment_is_revocable()- Verify attach/detach cycle
Design Model
Teams provide a lightweight identity projection system:
- No mandate: Multiple teams can coexist without conflict
- Opt-in attachment: Agents choose to attach to teams
- Non-binding slogans: Slogans have no enforcement weight
- Context filtering: Slogans can be restricted to specific contexts
- Soft caps: Per-agent active slogan limits (enforcement delegated to coordinator)
- Pure validation:
validate_projection()performs stateless checks
Examples
Creating a Team
use plant_team::{Team, Slogan};
let mut team = Team::new(
"slug-bears",
"league",
"Slug Bears",
"Process-first, continuity-first.",
);
let slogan = Slogan::new("patience", "slug-bears", "We sweep together.")
.with_contexts(["curling"]);
team.add_slogan(slogan);
Managing Attachments
use plant_team::TeamAttachmentRegistry;
let mut registry = TeamAttachmentRegistry::new();
// Agent attaches to team
registry.attach("agent-1", "slug-bears");
// Check attachment
assert!(registry.is_attached("agent-1", "slug-bears"));
// List teams for agent
let teams: Vec<&str> = registry.teams_for_agent("agent-1").collect();
// Detach
registry.detach("agent-1", "slug-bears");
Validating Projections
use plant_team::{ProjectionRequest, validate_projection, ProjectionOutcome};
let request = ProjectionRequest::new(
"agent-1",
"slug-bears",
"patience",
"curling"
);
let outcome = validate_projection(&team, ®istry, &request, 0);
match outcome {
ProjectionOutcome::Accepted => println!("Slogan approved!"),
ProjectionOutcome::Rejected(reason) => println!("Rejected: {:?}", reason),
}
Backward Compatibility
The classic game crate still re-exports team types from plant_team for backward compatibility:
// These still work in classic game code:
use plant_game::classic::team::{Team, Slogan, TeamAttachmentRegistry};
Further Reading
- Team Infrastructure Design - Detailed design documentation
- plant_team crate — see
society/team/in the plantangenet engine repo