Skip to content

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 team
  • add_slogan() - Add a slogan to the team's catalog
  • get_slogan() - Look up a slogan by ID
  • remove_slogan() - Remove a slogan from the catalog
  • with_max_active_slogans() - Set a soft cap on active slogans

Slogan

A lightweight, portable projection unit published by a Team.

  • new() - Create a new slogan
  • with_contexts() - Restrict to specific contexts
  • with_ttl() - Set frame lifetime
  • with_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 registry
  • attach() - Record an agent's opt-in to a Team
  • detach() - Remove an agent's attachment
  • is_attached() - Check if agent is attached to team
  • teams_for_agent() - Get all teams an agent is attached to
  • agents_for_team() - Get all agents attached to a team
  • can_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 valid
  • Rejected(RejectionReason) - Request was rejected

RejectionReason

Why a projection was rejected:

  • NotAttached - Agent is not attached to the Team
  • SloganNotFound - Slogan doesn't exist in Team's catalog
  • ContextNotPermitted - Slogan not permitted in requested context
  • CapExceeded - 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 registry
  • attachment_registry() - Create fresh attachment registry
  • is_supporter() - Check if agent is attached
  • league_request() - Build a generic projection request
  • supporter_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 config
  • enrolled_in_expected_leagues() - Verify league enrollments
  • supporter_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, &registry, &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