KognitaKognita.

Blog

Engineering Says It's Shipped. Product Can't Find It. Here's Why That Keeps Happening.

9 min read

Engineering closes the ticket: "shipped to prod." The PM opens staging: cannot find it. They open the production app: still not visible. They ask in Slack. The response comes back: "oh, it is behind the feature flag, you need to enable it for your account, and it is only in the EU region right now, and the mobile version is not done yet." None of this was in the ticket. The ticket said Done. The feature is not done in any sense that matters to a customer.

This conversation happens constantly across product and engineering teams. It is not a communication failure in the ordinary sense. Both sides are telling the truth as they understand it. Engineering shipped the code. Product cannot use the feature. Both are correct. The problem is that "shipped" and "available" are different states, and most organizations have no shared language or shared visibility for the gap between them.

What "shipped" means to engineering versus what it means to product

"Shipped" is an engineering term. It means the code is merged and deployed to the production environment. The implementation work is complete. The engineer's responsibility, as defined by the ticket, is discharged. "Shipped" does not mean customers can see it, interact with it, or benefit from it. It means the code exists in the production system.

"Shipped" is a product term too, but it means something different. In product language, "shipped" means the feature is available to customers as described in the requirements. Customers can find it, use it, and get value from it. The feature is not behind a flag, not limited to a subset of users, not missing on mobile, not requiring manual configuration that has not been done yet.

These two definitions were aligned in a simpler world where deploying code meant the feature was on. Feature flags, progressive rollouts, regional targeting, and permission-gated capabilities have introduced a layer of states between "the code is deployed" and "the customer can use this." That layer is where every "engineering says it shipped, product cannot find it" conversation lives. The code shipped. The feature did not.

The five states between deployed and customer-available

The gap between "merged to main" and "customer can use this" is not a single state. It is a sequence of states, each of which can be a stopping point. A feature can clear several of them and stall on the last one — and from the outside, it looks identical to a feature that stalled at the first one. The Jira ticket says Done in every case.

The five deployment states between merged and customer-available
The five states between "merged to main" and "customer can use this":

  State 1: Deployed, feature flag OFF
    Code is in production. Zero customers see it.
    Jira ticket: Done
    Customer availability: None

  State 2: Deployed, feature flag ON for internal accounts only
    Engineering and QA can test it in production.
    Customers cannot.
    Jira ticket: Done
    Customer availability: None

  State 3: Deployed, percentage rollout (e.g., 5% of users)
    Most customers cannot see it. A small cohort can.
    PM cannot find it unless their account is in the cohort.
    Jira ticket: Done
    Customer availability: Partial — and unpredictable

  State 4: Deployed, regional limitation (e.g., EU only)
    Customers outside the specified region cannot see it.
    Stakeholder demos may be in the wrong region.
    Jira ticket: Done
    Customer availability: Geography-gated

  State 5: Deployed, dependent configuration incomplete
    The feature is live but requires a permission grant, a settings toggle,
    or an admin action before any given customer can use it.
    Jira ticket: Done
    Customer availability: Requires manual enablement per account

Each of these states is legitimate. Feature flags exist because progressive rollouts and controlled launches are good engineering practice. Regional limitations exist because compliance and data residency requirements are real. Dependent configuration exists because some features require setup before they are useful. These are not bugs in the deployment process. They are intentional mechanisms that create the gap between "code is deployed" and "customer can use it."

The problem is not that these states exist. The problem is that none of them are captured in Jira. The ticket closes when the code merges. What state the feature is in afterward — which flags are on, which rollout percentage is set, which regions are enabled, which configurations are still pending — lives in environment configuration, deployment systems, and engineering tooling that product teams have no view into.

Why Jira tickets do not capture deployment state

Jira is a work-tracking system. It tracks the state of work, not the state of the system. A ticket transitions through states — To Do, In Progress, In Review, Done — that correspond to where the work is in the engineering process. Those states end at Done. Done means the work is complete, not that the feature is available. There is no "deployed behind flag" or "rolled out to 10%" or "pending EU configuration" state in the standard Jira workflow, because those are system states, not work states.

The traceability gap between specification and system behavior shows up exactly here. The spec describes the feature. The ticket tracks the work to build it. Neither captures the runtime state that determines whether a customer can actually access what was built. That information exists only in the system — in the feature flag configuration, the deployment tooling, the rollout percentages, the regional gating rules. It does not flow back to Jira automatically, because Jira was not designed to track it.

Teams that try to solve this with manual Jira updates — adding a "deployed" label, a "flag enabled" comment, a transition to a custom "Customer Available" status — run into the same problem as every other manual process: it works when people remember to do it, and it is wrong when they do not. The engineer who merged the PR and closed the ticket is not reliably the person who enables the feature flag two days later or toggles the regional setting a week after that. The knowledge of what state the feature is in disperses across multiple people and systems, and Jira does not collect it.

What the gap costs

The most immediate cost is the Slack conversation itself: the PM asking where the feature is, the engineer explaining the flag situation, the back-and-forth about regional state and mobile parity. This conversation happens multiple times per sprint in most product engineering organizations. It is time spent on communication that should be self-service — the PM should be able to look up what state the feature is in without asking anyone.

The deeper cost is the erosion of trust between product and engineering. From the PM's side, the experience is of features being called done when they are not done. The ticket is closed, but the feature is not available. This creates a credibility gap: if "Done" does not mean "done," what does "Done" mean? How should the PM communicate release timelines to stakeholders when the engineering signals are unreliable? The PM starts hedging every commitment, because they have been burned too many times by features that were shipped but not available.

From the engineering side, the experience is of PMs not understanding how modern deployment works. Of course it is behind a flag — that is best practice. Of course there is a regional rollout — that is responsible release management. The engineering team did exactly what good teams do, and they are being treated as if they failed. This creates its own resentment: the process working as intended is being experienced as a process failure.

Both experiences are legitimate. The problem is the shared vocabulary and shared visibility. Sprint demos hit the same issue when deployment state is invisible to the room: the team demos something that works in their environment and is invisible to everyone else, and nobody understands why. The fix in every case is not better communication between individuals — it is visibility into actual system state that does not require asking anyone.

What a shared deployment visibility layer looks like

The right fix is a layer that connects Jira ticket state to deployment system state — not by asking engineers to update Jira manually, but by surfacing what the system actually shows about a given feature's availability. When a PM asks "is the bulk export feature available to customers yet?", the answer should come from the system, not from whoever last touched the flag configuration.

That answer requires knowing: which feature flag gates this feature, what state that flag is currently in and for which accounts, whether the feature has any regional restrictions active, whether there are known open issues that are blocking full availability, and whether the implementation on all relevant surfaces (web, mobile, API) is complete. None of this is in Jira. All of it exists in the codebase, the deployment configuration, and the open ticket list — if you can read across all three at once.

What Jira says versus what system state shows for a feature with a flag
Jira ticket FEAT-291: "Add bulk export to CSV for order history"
  Status: Done
  Assignee: @mwilson
  Sprint: Sprint 42
  Closed: Tuesday

What that ticket does not tell you:
  -> bulk-export is behind feature flag FEAT_BULK_EXPORT_V1
  -> FEAT_BULK_EXPORT_V1 is currently enabled for: internal@company.com only
  -> The export endpoint exists in /api/orders/export but returns 403 for
     all non-internal accounts
  -> The frontend "Export CSV" button is visible to all users in staging
     but hidden in production (feature flag check is missing in the
     production build — bug filed as ENG-388, not linked to FEAT-291)
  -> Mobile app does not have the export button yet (tracked in separate
     ticket MOB-114, currently unassigned)
  -> EU data residency check is not implemented — export is blocked
     for EU accounts by a middleware guard added in a different PR

The Jira ticket is not wrong. The work described in the ticket is done. What is missing is the full picture of what "done" means for this feature's customer availability — and that picture requires reading across the codebase, the flag configuration, and the open ticket list simultaneously. That is not a Jira problem to solve. It is a system visibility problem.

What Kognita surfaces about feature availability

Kognita is a managed codebase context platform. It indexes your repositories continuously and makes the system's current state queryable in plain language. For feature availability, that means a PM can ask "what is the current customer availability of the bulk export feature?" and get an answer that reflects actual system state — not Jira ticket state.

What Kognita surfaces about a feature's actual availability versus Jira's view
PM asks Kognita: "What is the current customer availability of the
bulk export feature?"

Kognita returns:
  Feature: Bulk CSV export for order history (FEAT-291)
  Jira status: Done (closed Tuesday)
  Actual customer availability: Not available to any external accounts

  Deployment state:
    -> Code merged: Tuesday (PR #1847)
    -> Feature flag: FEAT_BULK_EXPORT_V1
    -> Flag state: enabled for [internal@company.com] only
    -> All other accounts: 403 on /api/orders/export

  Known gaps blocking customer availability:
    -> Frontend button missing in production build (ENG-388, open, unassigned)
    -> Mobile implementation not started (MOB-114, open, unassigned)
    -> EU data residency not implemented — EU accounts blocked by middleware

  To make this available to external accounts:
    -> Fix ENG-388 (frontend button in prod)
    -> Enable FEAT_BULK_EXPORT_V1 for target accounts or globally
    -> Decide on EU rollout path before enabling for EU accounts

The response reflects what the system actually shows: the flag state, the accounts it is enabled for, the known gaps in frontend implementation, the open tickets that are blocking full availability, and what would need to happen before the feature is customer-accessible. None of this required asking an engineer. The information exists in the codebase and the open ticket list — Kognita reads across both and surfaces it in the format a PM can act on.

For engineering managers, this changes the "why can't product find it" conversation. The PM is not asking out of ignorance — they genuinely cannot see the flag state from their tools. When Kognita gives them visibility into what the system state actually is, the questions they bring to engineering are different: not "where is the feature?" but "what specifically needs to happen before we enable this for EU accounts?" That is a better conversation to be having, and it starts from shared factual ground rather than a communication gap.

Final take

Shipped and available are not the same thing, and they have not been the same thing since feature flags became standard practice. The gap between them is not a failure of any individual engineer or PM — it is a structural gap between what work-tracking systems capture and what system-state systems contain. Jira tracks work. It does not track deployment state. And the information that answers "can a customer use this feature today?" lives in the system, not in the ticket.

The fix is not asking engineers to update Jira with flag state, or asking PMs to check the deployment dashboard, or adding a custom Jira transition for "customer available." The fix is visibility into system state that does not require any of those workarounds. When product teams can ask what the actual customer availability of a feature is and get an answer from the system, the "engineering says it shipped" conversation stops being a recurring friction point and becomes a one-second lookup. That is what shared deployment visibility looks like in practice.