Most security programs do not run out of budget because of a single oversized engagement. They run out because nobody held one authoritative number for how much contracted capacity was left. A penetration testing retainer is signed for a fixed pool of man-days. Then three projects start in parallel, each one consuming days from the same pool, and the only place that ledger lives is a spreadsheet that one person updates by hand after each kickoff call. By the time someone notices the pool is exhausted, two projects are already mid-flight and the contract window is closing.
Man-day agreement tracking exists to remove that blind spot. The goal is simple to state and hard to do manually. You want a single contracted capacity figure for each consulting firm, you want consumption to update itself the moment a project changes, and you want the remaining capacity to be a number you can trust without reconciling anything by hand. PMAP treats this as a first-class part of security assessment management, sitting one level above projects so that every engagement draws from a capacity pool the platform keeps honest.
This article explains why spreadsheets fail at capacity tracking, how PMAP models the vendor catalog and the two contract types that sit on top of it, exactly when man-day usage is recalculated, and how the utilization gauge and linked-projects view turn raw numbers into something a program lead can act on. Every behavior described here is grounded in how the framework agreement and consulting firm domains actually work.
Why Spreadsheets Fail at Capacity Tracking
Spreadsheets are not bad at storing numbers. They are bad at staying correct when the numbers depend on events happening elsewhere. Capacity tracking is exactly that kind of problem. The contracted total is static, but consumption is dynamic. It changes every time a project is created, rescoped, completed, or cancelled. A spreadsheet has no way to know any of those things happened. Somebody has to remember to open it and edit a cell.
That reliance on memory is where the failures start. The person who maintains the tracker is on holiday during a project kickoff, so two new engagements consume days that are never logged. A project gets cancelled and the days it reserved are never returned to the pool, so the remaining figure looks worse than reality and a fundable engagement gets deferred for no reason. Two stakeholders keep separate copies and quietly disagree about how many days are left. None of these are exotic edge cases. They are the normal failure mode of any manual ledger that has to track real-time events.
The cost is not only the wasted reconciliation time. It is the decisions made on stale numbers. Procurement renews a framework at the wrong size. A program lead approves a new wave against capacity that no longer exists. A vendor over-delivers against an exhausted pool and the over-run only surfaces at invoice time. Real-time capacity visibility without manual reconciliation is the whole point of putting agreements in the platform that already owns the projects consuming them. The platform sees the project events firsthand, so it can keep the ledger current without anyone remembering to.
The Vendor Catalog Behind Every Engagement
Before you can track capacity against a firm, the firm has to exist as a clean, consistent record. PMAP keeps a global consulting firm directory for this. It is a platform-wide master-data catalog of external penetration testing houses, security consultancies, and audit bodies. The directory is intentionally cross-tenant. There is no company_id on a firm record, so every company in the deployment shares one catalog. A firm that appears on framework agreements for several tenants is a single maintained record rather than a set of per-tenant duplicates that drift apart over time.
Each firm record carries the practical details an engagement needs. Core identity covers name and legal name. A contact book stores primary and secondary contacts with name, email, and phone, plus the firm website and free-text notes. The directory is searchable by name, email, and contact name, and it is cursor-paginated so large vendor lists stay responsive. An is_active flag lets a platform administrator soft-disable a vendor without deleting it, which keeps historical references intact while removing the firm from active engagement pickers.
Because this catalog is shared master data, write access is deliberately narrow. Reading the directory requires only project:view, so any security manager setting up an engagement can browse vendors and their qualifications. Creating, editing, or deleting a firm is restricted to the platform_admin role. The reasoning is direct. One administrator editing a firm record changes it for every tenant at once, so destructive edits need a single accountable owner rather than open access. The item route also returns 404 rather than 403 when a caller lacks permission, which prevents probing firm UUIDs to confirm a record exists.
Qualification Records Before You Assign
Vendor selection is not only about who is available. It is about who is allowed. Enterprise procurement and compliance teams need auditable vendor vetting before any engagement begins, and the firm directory carries that vetting as structured qualification records rather than as notes in a contract folder.
Each firm can hold any number of qualification records. A qualification captures the certification scheme, such as CREST, CHECK, or ISO 27001, along with the level or class, the scope it covers, the issuer, and a validity window with valid_from and valid_until dates. This is the evidence a security manager checks before assigning a firm to a project. You confirm the credential is the right one and that it has not lapsed, and you do it inside the platform instead of chasing PDFs.
Every qualification carries a three-state status that drives expiry management. The valid values are active, expired, and pending_renewal. The handler enforces this enum on both create and update, so any other value is rejected with HTTP 400, and the status defaults to active when it is omitted at creation. Those three states are what let a program track qualification health across the whole vendor base. You can see which firms hold current credentials, which have lapsed, and which are mid-renewal, which is exactly the view a compliance audit asks for. Qualification mutations follow the same platform-admin restriction as firm edits, because credential records are part of the shared catalog that every tenant relies on.
Two Contract Models: Framework vs Project-Based
With a clean vendor catalog in place, the framework agreement sits one level above projects and captures the commercial relationship. An agreement is a contractual capacity arrangement between a company and a consulting firm. It defines the pool of man-days the firm may draw on when delivering security services for that company, or it scopes a one-off engagement. PMAP supports exactly two contract models, and the distinction between them governs how man-day accounting behaves.
A framework agreement is the shared man-day pool. It carries a total_man_days figure, and multiple projects can draw on that same pool over the life of the contract. This is the retainer pattern. You contract for a hundred days with a pentest firm, then run as many projects as you need under that single agreement until the pool is spent or the contract window closes. For this type, the platform actively tracks consumption and keeps the remaining figure current.
A project_based agreement is the one-off engagement. It represents a single piece of contracted work rather than a reusable pool, and its used_man_days is deliberately left out of automatic recalculation. It stays at zero for type-tracking purposes unless set manually. This matters because not every engagement is a retainer. A standalone assessment with a fixed statement of work does not behave like a drawable pool, and modeling it as one would produce misleading capacity math. By separating the two types, PMAP keeps the capacity gauge meaningful only where a capacity pool actually exists.
The API enforces this strictly. Only the two literal strings "framework" and "project_based" are accepted as an agreement type. Any other value is rejected with HTTP 400, and the type defaults to "framework" when omitted on create. The total_man_days field follows the same logic in the interface. It is shown and required in the create and edit modal only when the agreement type is framework, and it is hidden for project_based agreements where a contracted pool figure has no meaning. In the agreements list, the utilization bar renders only for framework rows, since a project-based row has no pool to measure against.
Automatic Man-Day Accounting
The core of man-day budget control is that PMAP computes consumption rather than asking you to log it. Three figures describe an agreement’s capacity. The contracted total is total_man_days. The amount consumed is used_man_days. The amount left is remaining_man_days. The relationship between them is what the platform keeps honest automatically.
For a framework agreement, used_man_days is recalculated directly from the projects linked to that agreement. The calculation sums each linked project’s actual days, falling back to estimated days where actual is not yet recorded. In source terms, this is SUM(COALESCE(actual_days, estimated_days, 0)) across every project whose agreement link points at this agreement. The fallback behavior is what makes the figure useful throughout the engagement lifecycle. Early on, before a project has logged actuals, its estimate counts against the pool, so capacity planning reflects committed work and not only completed work. As projects finish and record actual days, the same figure tightens toward what was really delivered. The project_based type is excluded from this recalculation entirely, which is why its used figure stays at zero.
The remaining figure is handled differently, and the difference matters for trust. remaining_man_days is a computed column evaluated at query time as total_man_days minus used_man_days. It is never stored. Because it is derived on read from the two values it depends on, it cannot drift away from them. There is no second copy of the remaining figure to fall out of sync, which is precisely the failure that breaks spreadsheets. The number you read is always the live difference between the total and the used figure, computed at the moment you ask for it.
When Recalculation Fires
The accuracy of used_man_days depends entirely on when it is recalculated, so it is worth being precise. Recalculation is not on a timer and it is not a nightly batch. It is driven by the project lifecycle. The project service calls RecalcUsedManDays on the framework agreement domain after any project create, update, or delete that touches a framework_agreement_id. The moment a project that references an agreement changes in a way that affects its day figures, the agreement’s consumption is recomputed from the current set of linked projects.
This event-driven model is what removes the manual step. You do not update the agreement when a project changes. Updating the project is the trigger. Rescope a project and its new estimate flows into the pool. Record actuals at closeout and the figure tightens. Cancel a project and the days it reserved return to the pool, because the recalculation re-sums whatever projects remain linked. The ledger maintains itself off the same events that a person would otherwise have to watch for and transcribe.
There is one operational nuance worth understanding for accurate expectations. The recalculation is invoked fire-and-forget from the project service, meaning a failed recalc does not roll back the project mutation that triggered it. In practice a transient database error could leave used_man_days momentarily stale until the next project mutation triggers another recalculation. The design favors never blocking a legitimate project change over guaranteeing the capacity figure is correct to the second. Because remaining_man_days is always recomputed from the stored total and used values, it stays internally consistent with whatever the current used_man_days is. The figures never contradict each other, even in the window before the next recalc catches up.
Reading the Utilization Gauge
Raw man-day figures answer a question, but a program lead does not want to do arithmetic on every agreement to find the ones in trouble. PMAP renders capacity as a colour-coded utilization gauge so the agreements that need attention announce themselves. The gauge shows the used-to-total ratio as a progress bar with a percentage, and it appears on both the agreements list and the agreement detail page.
The colour bands are fixed thresholds tuned to how capacity actually gets managed. Below seventy percent the bar shows the accent colour, signaling healthy headroom. From seventy to eighty-nine percent it turns orange, the early warning that a pool is filling and a renewal conversation should probably start. At ninety percent or above it turns red, the signal that the agreement is nearly or fully consumed and any new work needs a deliberate decision. These bands are deliberately not symmetric around a midpoint. They are weighted toward the high end because that is where the risk lives. The difference between forty and fifty percent used does not change a decision, but the difference between eighty-five and ninety-five percent absolutely does.
Alongside the gauge, the agreement detail header carries a days-remaining countdown against the contract window. Capacity is two-dimensional. You can run out of days, and you can run out of time, and a healthy man-day balance means nothing if the contract expires next week. The countdown surfaces the time dimension next to the capacity dimension. It turns orange when thirty days or fewer remain and marks the agreement overdue once the end date has passed. Together the gauge and the countdown let a program lead scan a list of agreements and immediately see both the ones approaching their capacity limit and the ones approaching their calendar limit, without opening a single record.
Linked Projects and Vendor Performance
Knowing an agreement is at ninety percent is the alert. Knowing which projects consumed the pool is the explanation, and the agreement detail page provides it. Each agreement shows a paginated table of every linked project, and each row compares planned days against actual days alongside the project’s active finding count. This is where a high utilization figure becomes a conversation you can have. You can see exactly which engagements drew down the pool, whether any of them over-ran their plan, and which are still open against the remaining capacity.
The planned-versus-actual comparison is the heart of vendor performance review. An engagement that consistently delivers within its planned days behaves differently from one that routinely runs over, and the agreement view makes that pattern visible per project rather than burying it across separate project pages. Over-run is highlighted directly so it does not have to be hunted for.
This per-project picture rolls up into a firm-level performance view as well. The consulting firm detail page carries a performance tab with KPI cards covering total, active, and completed project counts, plus aggregate planned and actual man-days across all of that firm’s engagements. The actual figure is shown in red when it exceeds planned, which turns a vendor’s track record into a number you can read at a glance. When it is time to renew a framework or select a firm for the next engagement, that history is the evidence. You are choosing vendors on delivered performance recorded by the platform, not on impressions.
The firm record also surfaces a deliverables view, a read-only panel of project-file deliverables attributable to that firm with per-row download. It gives a consolidated picture of what a vendor actually produced across engagements without navigating project by project. To keep the firm page responsive, the deliverables tab fetches its data only when it is activated rather than on every page load.
Multi-Tenant Scope and Authorization
Capacity and contract data is commercially sensitive, so the framework agreement domain enforces tenant isolation on every path that returns agreement data. Unlike the firm catalog, which is shared master data, agreements belong to a specific company. Every list and export path applies a scope filter from the auth context, so a scoped user only ever sees agreements for companies in their scope. Cross-tenant agreement data is never returned in a listing.
Item-level access uses a deliberate split between not-found and forbidden responses. A GetByID request for an agreement outside the caller’s scope returns 404, not 403, so a cross-tenant probe cannot confirm that an agreement exists by reading the error code. Update and delete apply the same logic in two steps. An out-of-scope target returns 404, while a target that is in scope but accessed by a caller lacking the required permission returns 403. The two cases are kept distinct on purpose. Hiding existence from outsiders is a different concern from telling an in-scope user they need a higher permission, and PMAP answers each correctly.
The mutating actions are individually gated. Creating an agreement requires the framework_agreement:create permission and also requires the target company to be within the caller’s scope, so you cannot create an agreement against a company you do not control. Updating requires framework_agreement:update and deleting requires framework_agreement:delete. This separation lets a deployment grant capacity-tracking visibility broadly while keeping the ability to alter contract records tightly held, which mirrors how procurement authority works in most organizations.
When it is time to report outward, both the agreement list and the firm catalog export to CSV or XLSX respecting the active search and filter state. The agreement export includes the computed man-day columns, so a procurement or compliance handoff carries the live usage figures and not a snapshot someone retyped. Exports are synchronous and bounded at fifty thousand rows at the repository level, which keeps a large export from exhausting memory.
How PMAP Keeps Capacity Honest
The thread running through all of this is that the capacity figure is never something a human is asked to maintain by hand. The vendor catalog gives every engagement a clean, vetted firm record with auditable qualifications. The two agreement types keep the capacity math meaningful only where a real pool exists, so a one-off engagement never pollutes a retainer’s gauge. Man-day accounting computes consumption from the projects themselves and derives the remaining figure on read, so the two numbers cannot disagree. Recalculation rides the project lifecycle, so the ledger updates off the same events a person would otherwise have to watch. The utilization gauge and days-remaining countdown turn those figures into a scan-and-act view, and the linked-projects table explains every number behind a vendor’s record.
The result is that real-time capacity visibility stops being a reconciliation chore and becomes a property of the system. A program lead opens an agreement and reads a number that is current by construction, not by someone’s diligence. That is what man-day agreement tracking is supposed to deliver, and it is why it belongs inside the platform that already owns the projects doing the consuming.
For the step-by-step procedure of creating an agreement, linking projects, and reading the gauge, see the guide on managing a framework agreement and man-day budget. To understand how agreements fit into a wider engagement, read about planning a pentest project with multiple firms, where the agreement link drives the man-day budget at the project level. For the broader picture, the security assessment management pillar covers how scoping, assessment, and remediation come together. Teams structuring their vendor relationships may also find the pentest firm persona view useful.
On the standards side, vendor vetting and capacity governance map onto recognized practice. CREST certification underpins the qualification schemes most pentest firms carry. ISO/IEC 27001:2022 addresses supplier and third-party controls, and NIST SP 800-161 covers supply chain and third-party risk management for organizations that need to evidence vendor governance.
Frequently Asked Questions
What is the difference between a framework and a project-based agreement?
A framework agreement is a shared man-day pool that multiple projects draw on over the life of the contract, like a retainer. Its used_man_days is recalculated automatically from linked projects, and it shows a utilization gauge. A project_based agreement represents a one-off engagement rather than a reusable pool. Its used_man_days is excluded from automatic recalculation and stays at zero for type-tracking purposes unless set manually, and it does not display a capacity gauge. The API accepts only these two type values and defaults to framework when the type is omitted.
How are used man-days calculated?
For a framework agreement, used_man_days is the sum of each linked project’s days, computed as the actual days where recorded and the estimated days where actual is not yet available. The exact rule is SUM(COALESCE(actual_days, estimated_days, 0)) across every project linked to that agreement. The fallback means early-stage projects count against the pool by their estimate and tighten to actuals as they close. The remaining figure is then derived as total_man_days minus used_man_days at query time and is never stored, so it cannot drift from the values it depends on.
When does PMAP recalculate man-day usage?
Recalculation is event-driven, not scheduled. The project service calls RecalcUsedManDays on the agreement after any project create, update, or delete that touches a framework_agreement_id. Changing a project that references an agreement is what triggers the recalculation. The call is fire-and-forget, so a failed recalc does not roll back the project change, and the figure refreshes on the next project mutation. Because the remaining figure is always recomputed from the stored total and used values, the displayed numbers stay internally consistent.
Can I track a consulting firm’s certifications before assigning them?
Yes. Each firm in the global directory can hold qualification records that capture the certification scheme such as CREST, CHECK, or ISO 27001, along with the level or class, scope, issuer, and a validity window. Each record carries a status of active, expired, or pending_renewal, which lets you confirm a credential is current before assigning the firm to a project. Reading qualifications requires only project:view, while creating and editing them is restricted to the platform administrator role because the firm catalog is shared across all tenants.
What do the colours on the utilization gauge mean?
The gauge shows the used-to-total man-day ratio as a percentage bar with three bands. Below seventy percent the bar is the accent colour, indicating healthy headroom. From seventy to eighty-nine percent it turns orange as an early warning that the pool is filling. At ninety percent or above it turns red, signaling the agreement is nearly or fully consumed. The bands are weighted toward the high end because that is where decisions change. A separate days-remaining countdown tracks the contract window and turns orange at thirty days or fewer, marking the agreement overdue once the end date passes.
Is agreement data isolated between tenants?
Yes, but the two domains differ on purpose. The consulting firm directory is intentionally cross-tenant, so every company shares one vendor catalog and a firm is a single maintained record. Framework agreements are tenant-scoped. Every list and export applies a scope filter, item reads return 404 on a cross-tenant target to avoid leaking existence, and update and delete apply a 404 for out-of-scope targets versus 403 for in-scope but unauthorized callers. Creating an agreement also requires the target company to be in the caller’s scope.
Can I see which projects consumed an agreement’s capacity?
Yes. The agreement detail page shows a paginated table of all linked projects, each comparing planned days against actual days alongside the active finding count, with over-runs highlighted. This explains the utilization figure by showing exactly which engagements drew down the pool. At the firm level, a performance tab aggregates total, active, and completed project counts plus aggregate planned and actual man-days, with actuals shown in red when they exceed planned, giving you a vendor track record to inform renewals and future engagement selection.