Feature Key Normalization

Reference documentation for feature key formats and normalization in SpecFact CLI.

Overview

SpecFact CLI supports multiple feature key formats to accommodate different use cases and historical plans. The normalization system ensures consistent comparison and merging across different formats.

Supported Key Formats

1. Classname Format (Default)

Format: FEATURE-CLASSNAME

Example: FEATURE-CONTRACTFIRSTTESTMANAGER

Use case: Auto-derived plans from brownfield analysis

Generation:

specfact code import --key-format classname

2. Sequential Format

Format: FEATURE-001, FEATURE-002, FEATURE-003, …

Example: FEATURE-001

Use case: Manual plans and greenfield development

Generation:

specfact code import --key-format sequential

Manual creation: When creating project state interactively, use FEATURE-001 format and manage it via project snapshot or project devops-flow.

3. Underscore Format (Legacy)

Format: 000_FEATURE_NAME or 001_FEATURE_NAME

Example: 000_CONTRACT_FIRST_TEST_MANAGER

Use case: Legacy plans or plans imported from other systems

Note: This format is supported for comparison but not generated by the analyzer.

Normalization

The normalization system automatically handles different formats when comparing plans:

How It Works

  1. Normalize keys: Remove prefixes (FEATURE-, 000_) and underscores
  2. Compare: Match features by normalized key
  3. Display: Show original keys in reports

Example

from specfact_cli.utils.feature_keys import normalize_feature_key

# These all normalize to the same key:
normalize_feature_key("000_CONTRACT_FIRST_TEST_MANAGER")
# → "CONTRACTFIRSTTESTMANAGER"

normalize_feature_key("FEATURE-CONTRACTFIRSTTESTMANAGER")
# → "CONTRACTFIRSTTESTMANAGER"

normalize_feature_key("FEATURE-001")
# → "001"

Automatic Normalization

Plan Comparison

Key normalization is applied automatically when comparing or merging bundle data.

Behavior: Features with different key formats but the same normalized key are matched correctly.

Plan Merging

When merging plans (e.g., via sync bridge --adapter speckit), normalization ensures features are matched correctly:

specfact project sync bridge --adapter speckit --bundle <bundle-name> --bidirectional

Behavior: Features are matched by normalized key, not exact key format.

Converting Key Formats

Using Python Utilities

from specfact_cli.utils.feature_keys import (
    convert_feature_keys,
    to_sequential_key,
    to_classname_key,
)

# Convert to sequential format
features_seq = convert_feature_keys(features, target_format="sequential", start_index=1)

# Convert to classname format
features_class = convert_feature_keys(features, target_format="classname")

Command-Line

Use project regenerate to re-derive project state from the current bundle:

specfact project regenerate --bundle <bundle-name>

Best Practices

1. Choose a Consistent Format

Recommendation: Use sequential format (FEATURE-001) for new plans:

  • ✅ Easy to reference in documentation
  • ✅ Clear ordering
  • ✅ Standard format for greenfield plans

Auto-derived plans: Use classname format (FEATURE-CLASSNAME):

  • ✅ Directly maps to codebase classes
  • ✅ Self-documenting
  • ✅ Easy to trace back to source code

2. Don’t Worry About Format Differences

Key insight: The normalization system handles format differences automatically:

  • ✅ Comparison works across formats
  • ✅ Merging works across formats
  • ✅ Reports show original keys

Action: Choose the format that fits your workflow; the system handles the rest.

3. Use Sequential for Manual Plans

When creating project bundles manually, use FEATURE-001 sequential format for feature keys.

Why: Sequential format is easier to reference and understand in documentation.

4. Let Analyzer Use Classname Format

When analyzing existing codebases:

specfact code import --key-format classname  # ← Default, explicit for clarity

Why: Classname format directly maps to codebase structure, making it easy to trace features back to classes.

Migration Guide

Converting Existing Plans

If you have a plan with 000_FEATURE_NAME format and want to convert:

  1. Load the plan:

    from specfact_cli.utils import load_yaml
    from specfact_cli.utils.feature_keys import convert_feature_keys
       
    plan_data = load_yaml("main.bundle.yaml")
    features = plan_data["features"]
    
  2. Convert to sequential:

    converted = convert_feature_keys(features, target_format="sequential", start_index=1)
    plan_data["features"] = converted
    
  3. Save the plan:

    from specfact_cli.utils import dump_yaml
       
    dump_yaml(plan_data, "main-sequential.yaml")
    

For existing plans: Keep the current format; normalization handles comparison automatically.

For new plans: Use sequential format (FEATURE-001) for consistency.

Troubleshooting

Feature Not Matching Between Plans

Issue: Features appear as “missing” even though they exist in both plans.

Solution: Check if keys normalize to the same value:

from specfact_cli.utils.feature_keys import normalize_feature_key

key1 = "000_CONTRACT_FIRST_TEST_MANAGER"
key2 = "FEATURE-CONTRACTFIRSTTESTMANAGER"

print(normalize_feature_key(key1))  # Should match
print(normalize_feature_key(key2))  # Should match

Key Format Not Recognized

Issue: Key format doesn’t match expected patterns.

Solution: The normalization system is flexible and handles variations:

  • FEATURE-XXX → normalized
  • 000_XXX → normalized
  • XXX → normalized (no prefix)

Note: If normalization fails, check the key manually for special characters or unusual formats.

See Also