Part 8 established that foundational slices cannot be verified by code alone. Database constraints, migration artifacts, and durable enforcement are required. Part 9 takes that lesson into the first reference-data slice: ManageRanks. This slice is where the implementation chain proves itself under realistic constraints. Without a single source of truth for rank codes, registration, access control, and reporting each risk hardcoding or duplicating the rank definitions. The ManageRanks reference-data slice solves this by establishing a canonical repository of rank codes (P, SL, L) and their access-level mappings, enforced through database constraints and validation rules that all downstream slices depend upon.

Copilot_20260629_090713.png

This is the ninth post in the series on AI-assisted greenfield software development. It builds on posts Part 1: Business Requirements, through Part 8: Durable Database Invariants, in the series. If you have not read the earlier posts, start there first, because Part 9 assumes the repository already has shared kernel definitions, foundational agent roles, and a dependency-aware implementation plan.

The First Reference-Data Slice

After Part 8’s focus on durable invariants, the implementation plan moves into the reference-data foundation. Rank management is the first of five reference-data slices that form the backbone of the Zeus Academia system. The sequence is:

Slice Purpose
ManageRanks (EP-1-1) Define the canonical rank set (P, SL, L) and their access-level mappings
ManageDegrees (EP-1-2) Create the degree catalog used by qualification workflows
ManageUniversities (EP-1-3) Create the university catalog used by qualification workflows
ProvisionExtension (EP-1-4) Manage extension inventory and availability rules
ManageAcademicCalendars (EP-1-5) Define term calendars and academic-period boundaries

ManageRanks appears first because registration, lifecycle changes, and access control all depend on it. Without a canonical rank source, downstream slices have no choice but to duplicate or invent rank semantics. That fragmentation compounds through the system.

Why Reference-Data Slices Matter

Reference data is the foundation that other domain slices depend on. When rank codes are scattered across multiple features or hardcoded in business logic, you lose the ability to enforce consistency, track changes, or adapt to new requirements. The ManageRanks slice inverts this by treating rank management as a first-class, independently deployable feature.

A reference-data slice provides:

  • Canonical source of truth: One database table, one API, one validation rule
  • Deterministic behavior: Duplicate codes are blocked by both application logic and persistence constraints
  • Downstream confidence: Registration, access control, and reporting consume stable rank data instead of reinventing it
  • Auditability: Changes to rank definitions are traced and versioned through the application layer

Agent Roles and Slice Coordination

Like Part 8’s foundational work, ManageRanks requires coordination across multiple agent roles. The implementation prompt defines a structured handoff sequence:

Role Responsibilities
slice-coordinator Confirm slice boundaries, persistence strategy, and migration path
backend-domain Implement add and list behavior with validation rules
testing-verification Verify uniqueness, allowed codes, and response contracts

This clear separation prevents scope drift and ensures each agent knows exactly what evidence to produce before handing off to the next.

Clarifying the Slice Boundaries

The ManageRanks implementation is driven by the implementation prompt ep-1-1-manage-ranks-implementation.prompt.md, which defines the slice’s responsibilities, dependencies, and acceptance criteria within the Zeus Academia vertical-slice architecture.

The first step described in the implementation prompt is confirming what the ManageRanks slice owns and what it does not. This boundary-clarification work belongs to the slice-coordinator agent:

Boundary Clarification Checklist:

  1. Confirm whether rank records are seeded at deployment, managed through the API, or both.
  2. Document the canonical rank codes (P, SL, L) and their access-level mappings.
  3. Identify any existing rank data in the Shared Kernel that must not be duplicated.
  4. Specify the folder structure: src/features/ReferenceData/ManageRanks/ or alternative.
  5. If later slices still persist raw rank codes before foreign-key wiring is complete, decide whether this slice adds a temporary CHECK constraint or accepts the gap explicitly.

What this boundary work produces:

  • Confirmed ownership: AddRank command + ListRanks query form the slice boundary
  • Persistence strategy: database-backed seed at deployment, admin API for runtime changes
  • Integration points: access-level mapping exposed so registration and reporting resolve it once
  • Clear acceptance criteria: only P, SL, L accepted; duplicates rejected deterministically; migration artifact when constraints change

Clarifying boundaries before implementation prevents scope drift and ensures downstream slices have a stable contract to depend on. This boundary work becomes the contract that backend-domain and testing-verification will verify against.

Implementing the Add-Rank Command

With boundaries confirmed, the backend-domain agent builds the core add behavior. The AddRank command accepts a rank code, validates that it is one of the canonical codes, and stores it with its access-level mapping. The implementation follows the mediatr and fluentvalidation patterns established in earlier posts:

AddRank Implementation Checklist:

  1. Create an AddRankCommand that accepts rankCode and accessLevel.
  2. Build an AddRankCommandValidator that enforces:
    • rankCode must be one of “P”, “SL”, “L”
    • rankCode must be unique (no duplicate codes in persistence)
  3. Create an AddRankCommandHandler that:
    • Validates the command
    • Stores the rank in the database with the access-level relationship
    • Returns a response with the created rank
  4. Wire the endpoint to accept rank creation requests.

What this implementation produces:

  • AddRankCommand with typed rankCode and accessLevel properties
  • AddRankCommandValidator enforcing code enumeration and uniqueness
  • AddRankCommandHandler with database persistence and error handling
  • HTTP endpoint (POST /api/ranks) bound to the handler
  • Database migration ensuring rankCode uniqueness constraint

This structure separates concerns: validation happens before persistence, the handler orchestrates the add flow, and the endpoint exposes a clean contract.

Enforcing Uniqueness at Two Levels

Without explicit uniqueness checks, a concurrent request might insert duplicate rank codes. The implementation guards uniqueness both at the application and persistence levels:

Application layer: The validator queries the database before persisting, raising an error if the code already exists. This provides immediate feedback and prevents unnecessary database round-trips.

Persistence layer: A unique constraint on the rankCode column in the database ensures that even if validation is bypassed or corrupted data is restored, duplicates cannot be stored. The validator tests confirm that both layers reject duplicates deterministically.

Implementing the List-Ranks Query

With add-rank behavior in place, the slice must expose the canonical rank data to downstream features. The ListRanks query retrieves all stored rank codes and their access-level mappings in a stable form. The implementation follows mediatr patterns:

ListRanks Implementation Checklist:

  1. Create a ListRanksQuery (no parameters).
  2. Create a ListRanksQueryHandler that:
    • Queries the rank repository for all records, ordered by rankCode
    • Maps each rank to a response DTO with rankCode, accessLevel, and createdAt
    • Returns a list of rank records with stable, predictable field names
  3. Create a ListRanksResponse contract that registration, access control, and reporting can depend on.
  4. Wire a GET /api/ranks endpoint to this handler.

What this implementation produces:

  • ListRanksQuery as a read-only operation
  • ListRanksQueryHandler with ordering and DTO mapping
  • Stable response contract so downstream slices can deserialize and use the data reliably
  • HTTP endpoint (GET /api/ranks) returning JSON-serialized rank records

    The list behavior is intentionally simple: it queries the database in a deterministic order and returns the raw rank data. Downstream slices (registration, reporting) consume this and apply their own business logic.

ManageRanks Architecture Overview

The ManageRanks slice is implemented as a vertical slice with clear boundaries, validation, and persistence. The architecture diagram below illustrates the flow from HTTP request to database persistence, highlighting the two-layer enforcement of rank code uniqueness.

ManageRank-Architecture.png

Building Validation and Verification Tests

Reference-data correctness is foundational; errors cascade to dependent features. The verification step covers add and list flows with both success and failure scenarios. The testing-verification agent follows the assertion patterns established in earlier posts:

Verification Test Checklist:

  1. Validator tests:
    • AddRankCommandValidator accepts P, SL, L and rejects other codes
    • Validator detects duplicate rank codes by querying the test database
    • Invalid inputs (null, empty, unknown codes) fail with clear error messages
  2. Handler tests:
    • AddRankCommandHandler successfully stores valid ranks
    • Handler returns the stored rank with access-level mapping
    • Duplicate attempts fail without side effects (no partial writes)
  3. Integration tests:
    • POST /api/ranks with valid code succeeds and is idempotent
    • GET /api/ranks returns all ranks in stable order
    • Constraint violations (direct database inserts) are caught as corruption signals
  4. Persistence tests:
    • Database unique constraint rejects duplicate rankCode values
    • Migration ensures rankCode column exists with correct type and constraints

What this verification produces:

  • Validator unit tests covering valid codes, invalid codes, and duplicates
  • Handler tests confirming storage and response mapping
  • Integration tests validating the full request/response cycle
  • Constraint tests confirming database-level uniqueness
  • Test evidence demonstrating the slice meets all acceptance criteria

Tests are particularly important for reference data because they serve as executable documentation: future developers can see exactly which codes are valid, how duplicates are handled, and what the stable query response looks like. This evidence also ensures that the next slice in the plan (ManageDegrees) can safely depend on ManageRanks without reinventing its verification.

Documenting the Rank-to-Access-Level Mapping

Reference-data slices are most valuable when downstream slices can consume the mapping without redefining it. This is ensured by explicitly documenting the rank-to-access-level relationship in both code comments and API documentation.

The ListRanksResponse includes:

{
  "ranks": [
    {
      "rankCode": "P",
      "accessLevel": "Principal",
      "createdAt": "2026-06-28T10:00:00Z"
    },
    {
      "rankCode": "SL",
      "accessLevel": "StaffLeadership",
      "createdAt": "2026-06-28T10:00:00Z"
    },
    {
      "rankCode": "L",
      "accessLevel": "Lecturer",
      "createdAt": "2026-06-28T10:00:00Z"
    }
  ]
}

This mapping is consumed directly by:

  • Registration slice: Maps user input to a valid rank + access-level pair
  • Access-control slice: Resolves permissions based on stored access-level values
  • Reporting slice: Groups or filters by access level without hardcoding codes

By making the mapping explicit and queryable, the ManageRanks slice becomes a force multiplier for downstream features.

The Enforcement Contract

Like Part 8’s critical lesson, ManageRanks cannot be verified by code alone. The persistence layer must enforce the same invariants as the application logic.

Rule Canonical layer Persistence backing required Verification evidence
Rank code validity Validator + reference-data boundary Not required (canonical set enforced by handler) Validator tests + integration tests
Rank code uniqueness Validator + handler Yes, unique constraint Handler tests + migration proof

This clarity ensures that neither the application layer nor persistence layer can drift. If a developer later considers adding a uniqueness constraint without updating the validator, the verification flow will catch it. If the validator is removed but the constraint remains, tests will fail.

Acceptance and Handoff

The slice is complete when:

  • ✅ Only P, SL, and L are accepted
  • ✅ Duplicates are blocked at application and persistence levels
  • ✅ Rank data is queryable with stable response contract
  • ✅ Tests cover add, duplicate, list, and constraint-violation scenarios
  • ✅ Migration artifact documents uniqueness schema
  • ✅ Downstream slices have documented access to the rank-to-access-level mapping
  • ✅ Enforcement matrix evidence confirms both application and persistence layers protect the same rules

At this point, the slice is ready for integration testing with dependent features. The next phase will wire registration, access-control, and reporting slices to depend on the ManageRanks API, validating that the reference-data contract is stable and sufficient. Each of those slices will be able to assume that ManageRanks has already proven it can survive direct writes, migrations, and load without bypassing its own rules.

The Implementation Wave

ManageRanks is the first test of whether the reference-data strategy actually works. If this slice is implemented incorrectly, the mistake gets inherited by registration, access control, and reporting. That weight is exactly why it appears early in the plan: the cost of getting it right is paid once, up front, instead of being distributed across five downstream slices.

The next reference-data slice, ManageDegrees, will follow the exact same structure: boundary clarification, command/query implementation, two-layer enforcement, and verification with migration evidence. Each succeeding reference-data slice builds confidence that the pattern itself is sound.

Once all five reference-data slices are complete, registration becomes possible without duplicating any rank, degree, university, or extension logic. That is the payoff of treating reference data as a first-class concern instead of a setup detail.

Demonstration

You can showcase the value of ManageRanks by demonstrating that the two-layer enforcement works as intended. The following steps illustrate the expected behavior:

  1. Add a rank: Call the AddRank endpoint with code “P” and access level “Principal”. Verify it is stored once.
  2. Add a duplicate: Attempt to add “P” again. Observe the deterministic rejection.
  3. List ranks: Call the ListRanks endpoint. Confirm the three canonical codes are returned with their access-level mappings.
  4. Bypass validation: Connect directly to the database and attempt to insert “X” as a rank code. Observe the constraint violation. The database does not allow the invalid state even when validation is bypassed.

This shows that ManageRanks enforces its contract at both the code level and the persistence level.

Post implementation guidance updates

Like in the previous post, the implementation of the ManageRanks slice has prompted updates to the AI guidance. I encountered problems persisting Ranks when call the endpoint. The cause was that SQLite in-memory connections created isolated databases per DbContext scope, causing “no such table” errors across HTTP requests despite successful migrations. Switching to LocalDB resolved the issue, and the guidance documentation has been updated to reflect this requirement. Additionally, the migration pattern for reference-data slices has been clarified to ensure that future slices follow the same approach.

The following files have been updated to reflect the new reference-data slice and its enforcement patterns:

Change File Purpose
New Instruction database-setup-migrations.instructions.md Comprehensive guide on LocalDB setup, SQL Server migration patterns, and troubleshooting
Vertical Slice Update vertical-slice-implementation.instructions.md Added migration validation requirements and persistence slice checklist items
Project Overview Update project-overview.instructions.md Added database setup reference and clarified LocalDB for development

See rank-management-guidance-updates.md for details on the guidance updates and rationale.

Feedback and References

This post references:

Feedback is always welcome. Send your thoughts to AIPractitioner@pdata.com.

Disclaimer

AI contributed to the writing of this post, but humans reviewed it, refined it, enhanced it, and gave it soul.

Implementation Prompt

This post is derived entirely from a single executable specification:

Prompts

  • Create a new blog post, 2026-06-28-AIAGSD9, that explains the implementation of slice ep-1-1-manage-ranks-implementation.prompt.md