Blog
Why Product Thinks It's a Small Feature and Engineering Thinks It's Three Sprints
9 min read
PM writes a ticket for "add export to CSV." Engineering comes back: "that touches the reporting service, the data access layer, and we'd need to handle the customer permission model — probably three sprints." PM thinks engineering is padding. Engineering thinks PM doesn't understand the system. Both are right about the problem and wrong about the cause. The problem is not trust. It is that the two sides are working from different models of the same system — and neither model is complete.
The PM's model is accurate about what the user sees: a button that wasn't there before. The engineer's model is accurate about what the codebase requires: a new permission type, a bulk export data path, and backward compatibility work on a shared module. The gap between those two models is where scope misalignment lives. It is not resolved by better communication. It is resolved by giving both sides access to the same system model before the estimation conversation starts.
Why scope always looks smaller from the product side
Product managers work from what is visible: the UI, the user story, the business outcome. A feature that appears in the UI as a single button is, from the PM's vantage point, a single thing. The fact that the button invokes a chain of service calls, touches a shared data layer, requires a new permission type in an authorization service, and creates a backward compatibility obligation for two other teams' services — none of that is visible from the product side. It is not invisible because the PM is not paying attention. It is invisible because PMs have no access to the codebase and no tool that translates "UI feature" into "system change."
This visibility asymmetry is structural, not personal. The PM is not underestimating because they are careless. They are underestimating because the information they would need to estimate accurately — what the codebase must change to implement the feature — is locked inside a system they cannot access. The engineer is not overestimating to pad the timeline. They are estimating from a combination of what they know about the system and what they are about to discover during implementation, and the discovery phase is where most surprises live.
The asymmetry gets worse as the product and engineering teams grow. In a three-person startup, the PM probably wrote some of the code and has a working mental model of the system. In a fifty-person team, the PM has not touched the codebase and the codebase has grown beyond any single engineer's complete understanding. Both sides are operating with incomplete information, and the estimation conversation bridges that gap imperfectly through conversation, negotiation, and gut feel.
Why "just ask engineering" doesn't fix it
Engineering estimates keep surprising product not because engineers are bad at estimating, but because the full blast radius of a change is often not known until the implementation begins. An engineer asked "how long for export to CSV?" before they have explored the relevant code is giving a best-guess estimate based on their memory of a system that may not match the current state of the codebase. The actual scope emerges when they open the data access layer and find the bulk export path does not exist, when they look at the permission model and find the export scope is not registered, when they check the consumers of the shared module and find backward compatibility work they did not anticipate.
This is not a solvable problem through better upfront conversation. The information the engineer needs to give an accurate estimate is in the codebase, and reading the codebase takes time. A senior engineer can do a rough blast radius assessment in an hour or two. In organizations that run sprint planning every two weeks, with fifteen features to estimate in a two-hour planning session, thorough pre-estimate exploration of each ticket is not a realistic expectation. Estimates are made from memory and heuristics. The gaps surface during implementation.
The result is a dynamic where PM and engineering are both partially right about what they see, but neither has the complete picture, and the estimation conversation happens before either side has done the exploration that would produce an accurate number. The conversation is structurally set up to produce surprises.
The three scoping surprises that blow timelines
Cross-team observation of scope surprises tends to collapse into three recurring patterns. Understanding the pattern helps identify it earlier — and ideally, before the sprint starts rather than during implementation.
The three scoping surprises that blow timelines
SURPRISE TYPE 1: Hidden service dependencies
Ticket: "Add in-app notification for payment failures"
PM estimate: 1 sprint (UI banner + trigger)
Discovery during implementation:
-> NotificationService doesn't exist yet — it's a stub
-> Payment failure events are emitted by PaymentProcessorService
which is owned by a different team with a 2-sprint backlog
-> Mobile push requires MobilePushAdapter which has no payment
failure event type registered
-> In-app + push + email requires three separate delivery paths,
each with different retry and deduplication logic
Actual scope: 3 sprints across 2 teams
Discovery timing: day 3 of sprint 1
SURPRISE TYPE 2: Shared schema changes
Ticket: "Add 'archived' status to projects"
PM estimate: 0.5 sprints (new status option, filter in UI)
Discovery during implementation:
-> projects table schema is read by 11 services
-> ProjectQueryService caches project status — cache invalidation
logic does not handle a new enum value
-> ReportingService hardcodes status = 'active' | 'inactive'
— new enum value causes silent exclusion from reports
-> DataWarehouseExportJob uses status field for partitioning
— schema migration requires coordinating export job downtime
Actual scope: 2 sprints + coordination with data team
Discovery timing: day 6 of sprint 1 (schema migration PR review)
SURPRISE TYPE 3: Auth model complications
Ticket: "Let team admins manage billing settings"
PM estimate: 1 sprint (role check on billing settings page)
Discovery during implementation:
-> BillingService is gated by OWNER role, not ADMIN
-> Changing ADMIN to include billing access affects 23 other
permission checks that use the same role hierarchy
-> CustomerPermissionModel has no concept of scoped admin
(admin of a team vs. admin of an account)
-> Legal requires audit log for all billing changes — AuditService
does not currently log BillingService mutations
Actual scope: 3 sprints + legal review + audit service work
Discovery timing: day 8 of sprint 1 (security review)Hidden service dependencies occur when a feature that looks self-contained in the UI requires coordination with services owned by other teams — services that have their own backlogs, their own sprint commitments, and their own architectural constraints. The PM writes a ticket for in-app payment failure notifications. Engineering discovers that the notification service is a stub, the payment failure event does not exist in the mobile push adapter, and the team that owns the payment processor has a two-sprint backlog. None of that was visible from the UI.
Shared schema changes occur when a feature that appears to be a simple data model extension touches a field or table that other services depend on. Adding an "archived" status to projects looks like adding an enum value and a filter in the UI. The codebase shows eleven services reading the projects table, a cache that does not handle new enum values, a reporting service with hardcoded status checks, and a data warehouse export job that uses status for partitioning. The data migration requires coordinating downtime across teams. The timeline expands from half a sprint to two sprints plus cross-team coordination.
Auth model complications occur when a feature requires extending who can do what in a permission system that was built for a different model. "Let team admins manage billing settings" is a UI change of one role check. The codebase reveals that billing is gated by OWNER not ADMIN, that changing ADMIN permissions affects 23 other permission checks, that the permission model has no concept of scoped admin, and that legal requires an audit log that the current audit service does not generate. Three sprints, legal review, and an audit service change — none of which was visible from the ticket.
What shared system visibility changes about the estimation conversation
When both PM and engineering can see the same system model before the estimation conversation, the dynamic shifts entirely. The question stops being "how long do you think this will take?" — which is answered by memory and intuition — and becomes "given what the system actually requires, how do we sequence this work?" The disagreement about scope disappears because scope is no longer inferred from the UI or from memory. It is read from the codebase.
This changes the PM's role in the conversation. A PM who has queried the system before the estimation meeting arrives knowing that the export feature requires a new permission type and a bulk data path in the data access layer. They can ask whether the permission migration is the long pole. They can propose sequencing — ship a read-only export in sprint one, add permission scoping in sprint two — based on an actual understanding of what the two phases of work require. They are not challenging the estimate; they are contributing to the planning. The engineer is not defending their estimate; they are confirming a shared model.
PMs writing specs without codebase access are making educated guesses about implementation complexity that engineering then has to correct — in estimation meetings, in sprint reviews when features take longer than planned, and in post-mortems when projects slip. Giving PMs access to the system model before they write the ticket is not about making PMs into engineers. It is about eliminating the information gap that makes every estimation conversation a negotiation rather than a planning session.
How Jira and codebase context let PMs verify blast radius before writing the ticket
The blast radius of a proposed feature — all the services, schemas, permissions, and consumers it would need to change — is discoverable from the codebase before any engineering work begins. The question "what would the codebase need to change to add a bulk CSV export to the reporting screen?" has a deterministic answer: the data access layer, the permission model, the authorization service, the two consumers of the shared data layer endpoint. That answer does not require an engineer to explore it manually. It requires a tool that can trace the system from a product description to the code it would touch.
"Add export to CSV" — what each side sees, and what the system actually requires
WHAT PRODUCT SEES (from the UI)
-> A button on the Reports screen
-> User clicks button, file downloads
-> Probably a few hours of work, maybe a day
WHAT ENGINEERING SEES (from memory, before exploring)
-> "This touches ReportingService — that module hasn't been changed
in 18 months and the data layer is messy."
-> "We'd need to handle large result sets — streaming or async job?"
-> Initial gut estimate: 1–2 sprints
-> Neither side has the full picture yet
WHAT THE SYSTEM ACTUALLY REQUIRES (from codebase trace)
ReportingService
-> Queries DataAccessLayer.getReportRows()
Currently: returns max 500 rows (pagination, no bulk export path)
Required change: add streaming or async bulk export endpoint
DataAccessLayer
-> Joins across reports, report_items, and organizations tables
organizations table: row-level security by customer_id
Required: verify export path enforces same RLS as read path
CustomerPermissionModel
-> ReportingService reads permissions from PermissionCache
PermissionCache: does not currently cache bulk-export permission scope
Required: add export_data permission type and cache invalidation
AuthorizationService
-> export_data permission does not exist in current permission registry
Required: new permission type, migration, admin UI to grant it
Existing consumers of DataAccessLayer.getReportRows():
-> AnalyticsDashboard [uses same endpoint, will break if signature changes]
-> ScheduledReportJob [nightly job, same method — needs backward compat]
Accurate estimate: 3 sprints
Scoping surprise count: 4 (bulk export path, RLS, permission type, backward compat)
PM's original estimate was off by: ~12xThe Jira dimension adds the sprint-level context that changes pre-planning decisions. A PM querying blast radius before writing a ticket wants to know not just what the codebase would need to change, but whether any of those changes are already in progress — because in-progress changes to shared components create sequencing decisions that affect the feature's estimate and sprint placement. If the data access layer is being refactored in the current sprint by another team, the export feature either needs to wait for that refactor to land or needs to be coordinated with it. That fact is visible in Jira; connecting it to the codebase blast radius makes it actionable before the ticket is written.
This is the capability Kognita's cross-repo index and Jira MCP integration enable for the full team — not just engineers. A PM, a scrum master, or an engineering manager can ask a plain-language question about what a proposed feature would require, and receive back a concrete list of system components, team dependencies, and in-progress work that intersects the implementation path. No IDE. No reading code. No asking engineering to do a spike before every estimation conversation. The system model is accessible to everyone who needs it.
The result is not that estimation becomes trivial — complex features are still complex. The result is that the estimation conversation starts from a shared understanding of what the complexity actually is, rather than from two different mental models of the same system. PM and engineering are no longer negotiating from different data. They are planning from the same data.
Before vs. after: the estimation conversation with shared system context
WITHOUT SHARED SYSTEM CONTEXT
PM: "How long for 'export to CSV' on the reports page?"
Engineer: "I haven't looked at it yet, but ReportingService
is messy — probably 2–3 sprints."
PM: "That seems like a lot for a button."
Engineer: "There's a lot going on under the hood."
PM: [thinks engineer is padding] "Can we do it in one sprint?"
Engineer: [knows they can't, says maybe] "We can try."
Sprint 1: 40% complete, blocked on permission model
Sprint 2: Permission model done, data layer rewrite started
Sprint 3: Delivered. PM has lost confidence in estimates.
Engineer resents being pressured. Both are right
that something went wrong. Neither knows how to fix it.
WITH SHARED SYSTEM CONTEXT (queried before estimation meeting)
PM runs pre-estimation query:
"What does the ReportingService depend on, and what would
need to change to add a bulk data export path?"
Result surfaces in plain language:
-> DataAccessLayer: needs new bulk export endpoint (no streaming path exists)
-> CustomerPermissionModel: export_data permission type doesn't exist
-> AuthorizationService: new permission requires registry migration
-> AnalyticsDashboard + ScheduledReportJob: backward compat risk on DAL change
Estimation meeting:
PM: "I ran the system trace — looks like we need a new permission type
and a bulk export path in the data layer. Is that right?"
Engineer: "Yes exactly. That's the 3-sprint scope."
PM: "The permission migration is the long pole. Can we ship read-only
export in sprint 1 and add permission scoping in sprint 2?"
Engineer: "Yes — that's actually a cleaner sequencing."
Result: 3 sprints as expected. No surprises. No blame.
PM understands why. Engineer isn't defending their estimate.
Both are working from the same system model.Final take
The feature that looks small from the product side and large from the engineering side is not a failure of judgment on either side. It is a predictable outcome of a process where one side can see the UI and the other side can see the code — but neither side can see both at the same time, in the same language, before the sprint starts. The estimation conversation is structurally set up to produce surprises.
Scope misalignment is a shared system visibility problem. Give both sides access to the same system model before the estimation conversation, and the surprises stop being surprises. The complexity does not go away — but it becomes visible at the right moment, when decisions can be made rather than absorbed as delays. Every sprint where product and engineering arrive at estimation from the same shared understanding of the system is a sprint that does not end with a post-mortem about why the feature took three times longer than planned.