Disco ParrotDisco Parrot Home
Docs
Request a Demo

Rollups

The unified treatment of every count, sum, percentage, and capacity number that Disco Parrot derives automatically from your records. Plans progress, open bugs, sprint capacity, and key result auto-progress are one analytical concept with three subsystems and a shared design.

Rollups are how Disco Parrot answers the questions you would otherwise be answering with a spreadsheet. How many plans on this initiative are complete? The number is on the initiative card. How many hours of work has the team committed to in Sprint 24? The number is on the sprint capacity tab. Has Sarah's customer-export goal moved this week? The number is on her key result, derived from the initiative she is shipping.

Every rollup in the system follows the same shape. A target record (an initiative, a sprint, a key result) reads from a set of source records (plans, bugs, members, linked initiatives), applies a rule (count these, sum that, average the other), and renders a number. The rule lives in code, not in your configuration; you turn the rollup on for the surface you want it to render on. The platform keeps the number honest.

This page is the unified reference for every rollup Disco Parrot ships today. The shipped rollups are deliberately small in number and consistent in shape; the unified treatment matters more than the count.

The rollup model

Three principles guide every rollup the platform ships. They are the design thesis; the rest of the page is the application.

Honest math, never magic

Every rollup is documented, every filter is named, every "open" or "complete" status is enumerated. There are no hidden weightings, no synthetic indicators, no opaque health scores, no AI-driven sentiment numbers. Plans progress counts the plans at complete over the plans in {draft, in-progress, complete, blocked}; the cancelled plans are excluded from both numerator and denominator because cancelled work is not in-flight. You can defend the percentage on any initiative card by walking the four statuses; the platform keeps the count current.

Read-time when it can be, write-through when it must be

Most rollups are computed live every time a page asks. Open bugs on an initiative card is recomputed on every page render against the bug store; the cost is one batched round trip, the benefit is that the count is always fresh and there are no invalidation bugs. A small set of rollups (the ones read across many surfaces, like a key result current value that shows on a goals dashboard, a project page, and a cross-team view) are computed once per source event and stored on the target record; recomputing on every dashboard load would multiply the cost.

Explicit configuration, not implicit discovery

A rollup that is going to render on a card has to be added to the card field set; a key result that is going to auto-update has to be opted into auto mode. Plans progress is computed for every initiative the moment a single plan exists underneath one, but it does not render on the initiative card until an admin opens the Initiative workflow's Card Fields sub-tab and adds it to the field set. The platform does not silently add a derived column to every grid the moment it becomes possible.

Three subsystems, one analytical concept

Rollups live in three places in Disco Parrot. They share the model above; each is shaped for the audience that reads it.

Initiative-target rollupsTARGETInitiativeSOURCEPlans, bugsTIMINGRead-timeTRIGGERPage asks; SSE refetch on plan or bugchangeEXAMPLESPlans count, plans progress, bugs open,hours sumSprint capacityTARGETSprintSOURCETeam members, plans, bugsTIMINGRead-timeTRIGGERTab opens; SSE refetch on team changeEXAMPLESPer-member capacity, team total,committed workKey result auto-progressTARGETKey resultSOURCELinked initiativesTIMINGWrite-through on eventTRIGGERinitiative.updated with status orprogress diffEXAMPLESBoolean (all linked done) or numeric(weighted average)
Three rollup subsystems share a common shape: a target record reads from a source set, applies a documented rule, and renders a number. Two are read-time pulls; one writes through on an event because the answer is read across many surfaces and needs to be consistent.
  • Initiative-target rollups. Counts, percentages, and sums that an initiative shows based on the plans and bugs underneath it. Read-time. Rendered through the initiative card and grid field catalog.
  • Sprint capacity rollups. Per-member hours and points capacity computed for a sprint, combined with the work the team has committed, rendered on the sprint capacity tab. Read-time.
  • Key result auto-progress. Boolean or numeric progress on a goal key result, derived from the linked initiative's state. Write-through to the key result record on each initiative event.

What you configure is which rollups render on which surfaces, which key results opt into auto, and which estimate unit is primary for a team. What the platform owns is the rule itself: the denominator, the open-bug status set, the auto-progress formula. Two surfaces, one contract.

Read-time (pull)Initiative rollups, sprint capacityUser opens pageInitiative card or capacity tabSPA requests batchPOST /__/config/rollups/batchServer computes liveReads source records and countsCOSTOne round trip per page openNo invalidation bugs by constructionWrite-through (push)Key result auto-progressInitiative status changesinitiative.updated eventSubscriber wakesFilters status or progress diffKR recomputedBoolean or numeric formulaWrite to KR recordSSE broadcast on changeCOSTSubscriber runs once per eventEvery dashboard reader is fast
Two patterns side by side. Pull rollups (left) compute on every page open and stay fresh by construction. The push rollup (right) writes through once per event because the result is read across many surfaces and recomputing on every dashboard load would be expensive.

It is worth bounding the term. A rollup in this page's sense is a derived number computed by the platform from source records. A stored field (a plan's status, an initiative's owner, a bug's severity) is not a rollup. An event stream (the audit log, the activity feed) is not a rollup. A categorical status (a goal's On Track / At Risk / Off Track, set by the goal's owner) is not a rollup; it is a value someone enters. The numbers on this page are the ones the platform computes; the values elsewhere are the ones your team writes.

Initiative-target rollups

Seven rollups read from plans and bugs and render on the initiative. They are the surface a planner most often associates with the word "rollup." Each is computed at request time against the live store; no rollup value is precomputed or cached on the initiative record. Five render in the card and grid field catalog; two (the hours sums) are computed and exposed through the rollups batch API but do not yet have card-field catalog entries, so today they are reachable through custom integrations rather than through the workflow editor.

RollupCatalog labelWhat it answersSourceFilter
plans_countPlansHow many plans are under this initiativePlansSoft-deleted excluded; cancelled included
plans_complete_countPlans completeHow many plans are at status completePlansstatus = complete; soft-deleted excluded
plans_progressPlans progressPercentage completePlansNumerator: status = complete. Denominator: status in (draft, in-progress, complete, blocked). Cancelled excluded from both.
bugs_countBugsHow many bugs are under this initiativeBugsSoft-deleted excluded; canceled excluded by default
bugs_open_countOpen bugsHow many bugs are not yet resolvedBugsstatus in (triage, backlog, todo, in-progress, in-review)
estimate_hours_plans_totalPlans est. (hrs)Sum of plan estimate hoursPlansSoft-deleted excluded; missing field treated as 0. API only.
estimate_hours_bugs_totalBugs est. (hrs)Sum of bug estimate hoursBugsSoft-deleted excluded; missing field treated as 0. API only.

A few of these are worth a closer read.

Plans progress is the rollup most teams use as their day-to-day signal of "how is this initiative going." The denominator is the four non-cancelled Plan statuses, which means a plan in your customized Plan workflow that sits in a status the rollup does not name (a custom "Code review" or "Awaiting customer" status, for instance) is neither counted as complete nor counted in the denominator. The rollup is asking "what percentage of plans the workflow recognizes as plans-in-flight is at complete," not "what percentage of plans is done." See Customizing workflows for the full mapping of which status ids are load-bearing for the rollups; that page's table is the pre-flight checklist before you rename or remove a shipped status.

Open bugs counts a bug as open when its status is in the five-status set above. Anything outside that set (fixed, verified, closed, canceled) is not open. The rule is about the shipped status ids; a custom Bug status is not in the open list by default.

plans_count includes cancelled plans on purpose. A cancelled plan is still a plan in the project's history; the count exists to answer "how much scope has the team formally addressed under this initiative", including the work they decided not to do. bugs_count excludes canceled bugs by default, because a canceled bug is dismissed work and not scope the team is accountable for. The asymmetry is a real product choice, not an accident.

Hours: plans and Hours: bugs sum the estimateHours field across the relevant source records. The two are kept separate rather than collapsed into one "Hours: total" because the question of "how much engineering is left vs how much bug-fix is left" is what teams actually ask. A combined total is a calculator click away; the split is what gives you the answer to the planning question.

lightbulb
Points rollups land alongside burndown

Disco Parrot's points estimation ships per-plan and per-bug story-point fields and a per-sprint points capacity. The matching Points: plans and Points: bugs initiative rollups land alongside the burndown surface, where they will arrive together as a coherent unit. Story-point work for the moment rolls up to the sprint capacity tab; an initiative card today shows hours, not points.

How to turn an initiative rollup on

Initiative rollups render through the same card-and-grid field catalog every initiative surface uses. To opt one in.

  1. Open Platform → Workflows, pick the Initiative tab, open the Card Fields sub-tab to control kanban and roadmap-card display, or the Grid Fields sub-tab to control the data-grid columns. Power users can reach the same field-set editor from the "Customize view" drawer on any initiative grid or kanban without leaving the board.
  2. Add the rollup you want to the Selected fields list. The catalog labels them as Plans, Plans complete, Plans progress, Bugs, and Open bugs. Drag handles control order.
  3. Save the workflow. The change reaches every initiative surface in your tenant within a few seconds; cards on the kanban and rows in the grid pick up the new column on next render.

Every initiative rollup is defaultEnabled: false on both card and grid surfaces; nothing is on by default. Turn on the ones your team reads. Plans progress and Open bugs are the two most teams keep on; Plans count is useful as a header on a busy roadmap.

add_photo_alternate
Screenshot to capture
An Initiatives kanban card for 'CSV Export on the Reporting Page' rendered on the Approved column: title at the top, owner avatar and target-date row, and the rolled-up fields visible underneath as two rows: a Plans progress row showing '1 of 3 (33%)' with a thin progress bar fill, and an Open bugs row showing '1' with a small bug icon. Card has the standard brand-accent left edge.
save as: public/docs-media/initiative-card-rollups.png
Caption when added: An initiative card with two rollups enabled: plans progress and open bugs.

What stays fresh, and how it gets there

Initiative rollups are read-time. There is no precomputed plans-progress value sitting on the initiative record; the value is computed against the live plan and bug stores every time the SPA asks. The cost is one batched round trip per cache-miss set; the benefit is that there are no invalidation bugs, no precompute that fell out of date, no manual refresh button that does anything different from what the page already does on load.

The batch endpoint is POST /__/config/rollups/batch; it accepts up to twenty rollup ids per request and is gated on initiatives.read overall plus the per-source-entity scope (plans.read or bugs.read) for each rollup spec. The SPA listens to plan and bug events on the SSE stream and refetches the rollup batch when something changes underneath an initiative on the current page. The SPA also pre-filters denied rollup ids before the request, so a user without bugs.read does not ask for the bug rollups, and the cards omit those rows rather than rendering an error. A custom API caller without one of the required scopes sees an HTTP 403 with body {error: "INSUFFICIENT_SCOPE", denied: [{rollupId, requires}]}; the SPA never returns that response because it pre-filters, but partner integrations should handle it.

When a rollup looks wrong

A rollup that surprises you is usually one of four things; the diagnostic path is the same in each case.

The denominator excludes a status you forgot was custom. The most common case: your tenant added a "Code review" status between In progress and Complete on the Plan workflow, and the plans-progress percentage on your initiative reads lower than the team expected. The rollup denominator is hardcoded to the four shipped non-cancelled Plan statuses; the custom status is not counted. Look at the plan list on the initiative; if the missing percentage matches the number of plans in the custom status, this is the cause. The fix is either to keep the custom status (and accept that the rollup measures shipped progress against the platform's idea of in-flight, not the team's) or to consolidate the custom status back into one of the shipped four.

A renamed shipped status id silently changed the rollup. Rename complete on the Plan workflow to merged and the plans-progress numerator drops to zero on every initiative; the rollup is looking for complete. Same for done on Initiative and the goal auto-progress boolean. The workflows page lists every status id the rollups read; the audit log on the workflow record names the actor who changed the id.

A soft-deleted plan or bug stopped counting. Every rollup excludes soft-deleted records. A plan in the trash does not show up in the plans count or the plans-progress denominator. Restore the plan from the trash and the rollup counts it again on the next refresh.

The SSE refresh has not arrived yet. Initiative rollups refetch when a plan or bug event lands on the SSE stream for an initiative on the current page. If your tenant's SSE was disconnected for a moment (a transient network blip), the rollup on the open card reflects the state of the last refetch; reload the page and the next render is fresh.

warning
Custom statuses are silently excluded from rollups

Adding a status to the Plan or Bug workflow does not automatically add it to the open-set or the progress denominator. The status is fully usable in the SPA (dropdowns, alt-flow menus, kanban grids, action launcher, AI tools), but the rollups continue to measure against the shipped ids. Today expanding the rollup's status set requires a platform release, not a workspace edit. Plan customization with the rollup behavior in mind.

Soft-deleted plans and bugs are excluded

Every rollup filter excludes soft-deleted source records. A plan in the trash does not show up in the plans count or the plans-progress denominator. Restore the plan and it counts again. Cancelled plans are not in the plans-progress denominator by design; a plan you cancelled is not "in flight" and counting it would push your progress percentage down for work you have explicitly decided not to do.

Sprint capacity rollups

The sprint capacity rollup is the most operationally important rollup the platform ships. It is the answer to "do we have the bandwidth to deliver this sprint", computed the way your team would compute it on a whiteboard, except automatically. The math is simple, the cascade is clearer when written out, and the surface is on every sprint detail page under the Capacity tab.

Per-member capacity, in one formula

For every member of the sprint's team:

capacityHours = effectiveHoursPerDay × max(0, workingDaysInWindow − daysOff)

workingDaysInWindow is the number of working days inside the sprint's start and end dates, where "working day" is one of the days the team declares as working (default: Monday through Friday). daysOff is the count of the team's or the member's days-off ranges that fall on a working day inside the window. Personal days off and team days off are combined into a union before the count, so a personal day taken on the same day as a team holiday is counted once, not twice.

Worked end-to-end: Priya is an 8-hour-per-day engineer on Sarah's Analytics team. Sprint 24 runs June 3 through June 16; that is ten working days (weekends excluded). The team has one company holiday in the window on June 10 that reduces every member's working days by one. Priya has two personal days off on June 12 and June 13, also working days. Priya's daysOff is the union of the team holiday and her personal days, three working days total. Her capacity for the sprint is 8 × max(0, 10 − 3) = 56 hours. Tom, who shares Priya's hours-per-day but has no personal days off, lands at 8 × (10 − 1) = 72 hours.

info
Team days off are stored on the sprint, not the team

The "team holiday" carve-out is captured on the sprint record (sprint.teamDaysOff), not on the team's calendar. A company holiday on June 10 set during Sprint 24 does not carry into Sprint 25; the team enters it again for the next sprint. Admins planning recurring company holidays should expect to set them per sprint until a team-level holiday calendar lands.

info
Missing sprint dates collapse capacity to zero

The formula relies on workingDaysInWindow. If the sprint has no start or end date, the working-day count is zero and every member's capacity reads zero. Set the dates to make the rollup honest.

The four-layer cascade for effective hours per day

The number of hours a member is expected to work on a typical day is read from the most specific available source.

1Per-sprint overrideSet on the row in the Capacity tabPriya: 8h/day2Team's role defaultTeamRecord.roleCapacityDefaultsSenior eng: 6h/day3Team's defaultTeamRecord.defaultCapacityHoursPerDay7h/day4Platform fallbackBuilt-in baseline6h/dayFirst tier that is set wins. Above: Priya's override (8h) beats the senior-eng default.
The platform resolves a member's hours-per-day top to bottom. The first tier that is set wins; an unset tier falls through to the next. The points cascade is shallower in v1 (per-sprint override or zero).
  1. Per-sprint row override. A member's row on the sprint's capacity tab can set an explicit hours-per-day value for that sprint, capped at 24. Use this for a senior who is on call during this sprint and only available for half-days, or for a contractor who is part-time on this engagement.
  2. Role default for this team. Each team can declare a per-role default; an engineer working senior might default to six hours, a tech lead to four. Set these on the team's general tab.
  3. Team default. Each team can declare a default hours-per-day for all members who do not have a role-specific override or a per-sprint override.
  4. Global default of six hours. The last-resort fallback when no team or role default is set.

This cascade keeps the routine cases short. A team that wants to set capacity once on the team page and have every member inherit it can; a team with a more nuanced structure can override per role; an exceptional sprint can override per row.

Committed work

Alongside the capacity calculation, the same tab sums every plan and bug that has been scheduled into the sprint and shows the team's committed work.

FieldWhat it is
Hours committedSum of estimateHours across every plan and bug in the sprint backlog
Items without estimateCount of plans and bugs in the sprint missing an estimateHours value
Points committedSum of estimatePoints across every plan and bug in the sprint backlog
Items without estimate (points)Count of plans and bugs missing an estimatePoints value (capped at 1000 per item)
Items without any estimateCount of plans and bugs missing both hours and points
Team capacitySum of capacityHours across the included team members
Team points capacitySum of pointsCapacity across the included team members

A plan or bug is "in the sprint backlog" when its sprintId points at this sprint and the record is not soft-deleted. The team's chosen primary unit (hours or points, set on the team's general tab; flipping it changes the headline on every sprint of that team retroactively) drives which pair is the headline pair. The other pair stays visible on the same tab; the platform always computes both so a team that switches modes mid-quarter does not lose a number.

When the SPA renders the "items without estimate" caption it includes a cross-mode count: a sprint with three items missing hours estimates where one of those three has a points estimate reads as "3 items without hours estimate (1 points only)." The third counter (items without any estimate) is what powers the cross-mode caption; both headlines and the caption stay accurate even when the team mixes modes mid-sprint.

The over-capacity warning

When the committed total exceeds the team capacity, a warning icon and an "over" label appear next to the headline number. The warning is not a block; it is a signal. The platform shows the math; the team makes the call.

Committed hoursvs team capacity?overwithinOver-capacity warning shownThree honest responses belowDrop scopeMove items outAcceptNote for retroaudit row staysRe-estimateSuspicious itemmay be overstatedWithin capacityTwo responses based on headroomHeadroom > 30%Pull more inif quality allowsHeadroom < 30%Hold the lineprotect qualityEVERY BRANCH ENDS IN A TEAM GESTUREThe platform shows the math; the team makes the call.
The capacity tab shows the math; the team plans the sprint. The over-capacity warning is a signal, not a block; the headroom percentage tells the team whether to pull more in or hold the line. Every branch ends in a real team gesture, not a platform action.

When the team's points capacity is zero (no per-member points capacity has been set), the over-capacity warning is suppressed and the headline reads "Set per-member points capacity to enable rollup" instead. The empty state is the right answer for a team that has not opted into points; it does not pretend the team is one hundred percent over capacity when the denominator is zero. The hours side does not need an equivalent empty-state because the global six-hour default ensures capacityHours is never structurally zero (it can be zero only when the sprint window itself is missing).

The Capacity tab refreshes on five SSE event types: team-updated, team-member-added, team-member-updated, team-member-removed, and team-owner-transferred. It does not refresh in place on changes to the sprint window or to plan and bug estimates; those edits land on the underlying records immediately, and the tab picks them up on next reload.

add_photo_alternate
Screenshot to capture
The Sprint capacity tab in an over-capacity state: meta strip across the top showing 'Sprint 25 · 2026-06-17 to 2026-06-30 · 10 working days', headline reading '230 hours committed of 212 hours team capacity' with a red warning icon and a small '(over by 18 hours)' label next to it; the per-member table below shows four rows with two of them visually highlighted in a warm tint (Tom Asare's committed column reads 90 hours against his 72-hour capacity, Priya Patel's reads 70 against 56); a 'View work items' link visible above the table linking out to the sprint backlog. The Capacity tab is selected in the tab strip; a small caption underneath the headline reads 'Signal, not a block.'
save as: public/docs-media/sprint-capacity-over-capacity-warning.png
Caption when added: The over-capacity warning. Not a block; a signal that the team's commitments exceed the math. The team responds through the decision tree above.
add_photo_alternate
Screenshot to capture
The Sprint capacity tab on Sprint 24 of Sarah's Analytics team: a meta strip across the top showing 'Sprint 24 · 2026-06-03 to 2026-06-16 · 10 working days · 1 team holiday', a committed indicator reading '24 hours committed of 212 hours team capacity', a per-member table with columns Member, Role, Hours per day, Days off, Capacity (hours); rows for Sarah Chen (Lead, 4 hrs/day, 0 personal days, 36 hrs), Priya Patel (Senior, 8 hrs/day, 2 personal days, 56 hrs), Tom Asare (Senior, 8 hrs/day, 0 personal days, 72 hrs), Maya Rodriguez (Mid, 6 hrs/day, 1 personal day, 48 hrs); a side card on the right summarizing 'Items without hours estimate: 1' and 'Items without points estimate: 5 (3 hours only)'.
save as: public/docs-media/sprint-capacity-tab.png
Caption when added: The capacity tab for Sprint 24 with a per-member breakdown, the team total, the team-holiday carve-out, and the committed work summary.

Key result auto-progress

A goal's key result can be set to one of two progress modes. Manual progress is what most key results use: a planner enters the current value when they update the goal. Auto progress is the opt-in mode where the key result derives its number from the state of the initiatives it is linked to.

Auto progress is the only rollup in the platform that writes a derived value back to a stored record. The reason: a key result is read across the workspace's goals dashboard, project pages, and cross-team rollups, and recomputing it on every dashboard load would multiply the cost. Computing it once per initiative event and storing the answer keeps every reader fast and the number consistent.

How auto progress works

Auto progress is triggered by initiative.updated events that carry a status or progress change. When such an event arrives, the auto-progress subscriber wakes up, finds every key result that links to that initiative, and recomputes the key result's current value (rounded to two decimals). The new value writes through to the key result record if it differs from the stored one; the change broadcasts to every connected client. If the recomputed value equals the stored value, the write is skipped and no event fires.

The computation depends on the key result's metric type.

  • Boolean key results read as 1 when every linked initiative is at status done, otherwise as 0. This is the right shape for goals like "All four pillars of Q4 are shipped"; the key result flips when the last initiative completes and stays flipped while the work holds.
  • Numeric key results are designed to read as the contribution-weighted average of the linked initiatives' progress fields, scaled into the key result's value range. This is the right shape for goals that distribute credit across a portfolio of work.
info
Numeric auto-mode awaits an Initiative progress input surface

The numeric path reads from a per-initiative progress field that is not yet populated by any user-visible editor today. Auto-mode boolean key results work as designed and are the supported way to derive a key result from initiative state in v1. A planner who wants a percentage-style key result driven from initiative completion should use a manual key result that they update during the weekly review until the per-initiative progress input lands.

If a key result has no auto-driving links, or only links to portfolios (which support but do not numerically drive the key result), or its initiative-target links have all been soft-deleted, the subscriber writes nothing and the manually entered value stays exactly where it was. There is no decay-to-zero, no reset-to-manual fallback; the previously computed (or last manually set) value remains.

lightbulb
Write-through is what makes the goals dashboard fast

A tool that recomputes a goals dashboard on every page load against thousands of plans and bugs produces either a slow dashboard or stale numbers. Write-through is the platform's answer: the recompute runs once per relevant event, the number lands on the key result record, and every dashboard reader is fast.

A key result can carry two kinds of links: links to initiatives, which can drive boolean or (when the prerequisite ships) numeric progress, and links to portfolios, which act as supporting evidence but do not contribute to the auto-computed number. The split is deliberate. An initiative is a unit of work with a status the platform can read; a portfolio is a roll-up shape that contains other initiatives whose progress is already linked individually. The SPA shows the link type next to each link on the key result panel so a planner reading the goal knows which links contribute to the number and which are descriptive only.

Marcus's Ship five customer-facing launches in Q4 goal at the workspace level holds a portfolio-supporting link to Q4 Launches. The portfolio is the right organizing shape for the goal; the link tells anyone reading the goal where to look for the work. Marcus enters the launches counter manually because the answer to "how many launches have we shipped" is a curated count, not a derivation. The supporting link makes the relationship explicit; the manual progress mode keeps Marcus in charge of the number.

A worked example

Sarah's CSV Export on the Reporting Page initiative has three plans (CSV server endpoint complete, CSV download button in progress, CSV format verification draft) and one bug (Export timeout on large date ranges, in progress).

She has the Plans progress rollup and the Open bugs rollup turned on for her tenant's Initiative cards. Her card on the Initiatives kanban reads:

CSV Export on the Reporting Page
Owner: Sarah Chen · Target: 2026-06-30
Plans progress: 1 of 3 (33%)
Open bugs: 1

The 33% is the live rollup against her three plans: one at complete (CSV server endpoint), one at in-progress (CSV download button), one at draft (CSV format verification). The denominator is three; the numerator is one; the rollup renders as the percentage. When Tom merges the CSV download button PR and moves his plan to Complete, the rollup recomputes on the next read and her card updates on the SSE event within seconds. Honest math, never magic at work: the percentage traces directly to the three plans on the initiative, weighted by nothing, hidden by nothing.

She opens her sprint, Sprint 24, and clicks the Capacity tab. The team has four people. The window is ten working days (June 3 through June 16, weekends excluded). One company holiday lands on June 10. Priya is off two days mid-sprint for personal reasons; Maya is off one. Sarah is the team lead and runs at four hours per day; the three engineers run at eight, eight, and six hours per day respectively.

MemberHours/dayPersonal days offCapacity (hours)
Sarah Chen4036
Priya Patel82 (Jun 12, 13)56
Tom Asare8072
Maya Rodriguez6148

Team total: 212 hours. Committed: 24 hours (22 hours of plan work from the three CSV plans, 2 hours of bug work). The capacity tab reads "24 hours committed of 212 hours team capacity" with no over-capacity warning. The points column reads "Set per-member points capacity to enable rollup" because the team has not adopted points; the empty-state caption holds.

Sarah's goal on the goals page, Improve customer-reported export usability, has a key result called CSV export adoption in manual mode. She enters 33% as the current value, mirroring the plans-progress on her initiative. She keeps it manual for two reasons: the number she actually reports for adoption comes from her analytics tooling rather than the percentage of plans done, and numeric auto-mode awaits the per-initiative progress input surface anyway. The relationship between the initiative and the key result is explicit through the link; the number is hers to write. Explicit configuration, not implicit discovery at work: the platform makes the relationship visible and the responsibility for the number visible at the same time.

Marcus's workspace goal Ship five customer-facing launches in Q4 has a portfolio-supporting link to the Q4 Launches portfolio (which holds Sarah's CSV Export initiative among others) and a manual launches counter. He looks at the supporting link to know which initiatives are in play; he enters the counter himself as launches actually ship.

When the rollup signals over-capacity

Two weeks later the team is mid-sprint and an over-capacity moment arrives. Sprint 25 started with 24 hours committed against 212 hours of capacity, comfortably under. By week two, three things have shifted: Tom picked up an additional bug from the export-timeout family (estimated 12 hours), Sarah accepted a customer-facing demo plan she had not anticipated (estimated 16 hours), and a verification plan that was estimated at 6 hours turned out to be much larger and Priya re-estimated it to 22 hours. The Capacity tab now reads "230 hours committed of 212 hours team capacity (over by 18 hours)" with the warning icon.

The team's response runs through the decision tree in the diagram above. They look at the three items that drove the over-commitment. The customer demo is Sarah's call; she decides the demo is non-negotiable but she will own the plan herself in addition to her lead duties, which does not change the math but accounts for the over-commit. The new bug is in-flight and not droppable. The re-estimated verification plan is the one suspicious item; Priya and Sarah look at it together, agree the re-estimate is honest, and the team accepts the over-commit. The audit log captures the over-capacity state; the team notes the over-commit in their retro and adjusts how they scope verification plans in the next sprint.

The pattern here is the rollup pattern in microcosm: honest math (the 230 vs 212 trace directly to the per-member capacity table and the committed estimates), read-time freshness (the tab updated within seconds of Priya's re-estimate), and explicit configuration (no auto-decision rule fires; the warning is a signal, the team is the actor).

Boundaries

A few things the rollup model does not currently cover. We list them so you can plan around them and so the boundaries are explicit.

  • Points rollups on initiative cards. The per-plan and per-bug story-point fields ship today; the matching Points: plans and Points: bugs initiative rollups arrive with the burndown surface.
  • Hours rollups on initiative cards. The two hours rollups are exposed through the rollups batch API but do not yet have card-field catalog entries; today they are reachable through custom integrations rather than through the workflow editor.
  • Numeric KR auto-progress from the initiative side. The shape is implemented; the per-initiative progress input that drives it is not yet exposed in any editor surface. Boolean auto-mode is the supported path today.
  • Custom statuses in the shipped rollup sets. The plans-progress denominator, the open-bugs filter, and the goal auto-progress boolean all read shipped status ids by name. Custom statuses are not counted; expanding the rollup's status set today requires a platform release, not a workspace edit.
  • Per-tenant rollup definitions. The rollup registry is platform-wide. A tenant cannot define a custom plans_at_risk rollup with its own filter through configuration today; the registry is extended through platform releases.

Who sees the change

A rollup is a derived number; saving the source records is what moves it. A planner who edits a plan's status writes the plan, fires a plan.updated event, and the rollup on every initiative card that depends on it refetches on the next page render or SSE arrival. The connected client sees the new number without a refresh. A planner who edits per-member capacity rows on the Capacity tab fires the corresponding team event, and the tab refreshes for every connected client viewing the same sprint. The recompute is silent on the wire when it produces the same number it already had; the broadcast only fires when the value actually changed.

Permissions

Initiative rollups read with the source-entity scopes: plans.read to see plan-derived rollups, bugs.read to see bug-derived rollups. The batch endpoint is gated on initiatives.read overall and per-rollup on the source scope. The SPA drops rollups the caller cannot see before issuing the request, so a user without bugs.read does not see a permission error; the bug rollups do not render. A custom API caller without one of the required scopes sees HTTP 403 with INSUFFICIENT_SCOPE and the denied rollup ids in the response body.

Sprint capacity reads with sprints.read. Editing per-member rows on the Capacity tab (hours-per-day overrides, personal days off, member inclusion) requires sprints.manage; read-only viewers see the calculated numbers without the edit affordances.

Key result auto-progress runs as a server-side subscriber and is not gated on user scope; the computed value writes through to the key result record and is then read with the standard goal-read scope by any user who can see the goal.

Why the shape pays off

For a senior PM evaluating Disco Parrot against Linear, Jira, or Azure DevOps, the rollup model is the answer to the question "does this product roll up plan and sprint state into the parent record without making me maintain two truths." It does, with a small enough rollup set to keep the rules legible, a read-time pattern that eliminates invalidation bugs by construction, an opt-in configuration model that respects what your team actually wants to see, and a write-through path reserved for the one place (key result current value) where read-time would not scale. The numbers your team relies on are the numbers your team chose to show.

For a planner reading the page day to day, every number on every surface should be defensible without picking up a calculator. The rule is documented; the filter is named; the cancelled plan is excluded; the open bug set is enumerated; the capacity formula is one line of math; the over-capacity warning is a signal rather than a block. When something looks wrong, the diagnostic path above is short and the answer is usually a renamed status or a custom status that did not make it into the rollup's status set; the cross-link to the workflows page closes the loop with the page that controls those ids in the first place.