Fold a nested aggregator's partial result into one parent source outcome without flattening
When an aggregator is itself one source for a parent aggregator, map the child's overall status, completeness, items and missing-source list into a single parent outcome. A partial child is ok or empty with completeness false, a failed child is unavailable, and a child missing a sub-source the parent requires is unavailable. Carry path-named missing sources upward.
Fold a nested aggregator's partial result into one parent source outcome without flattening
When to use
Use this when the thing you call is itself an aggregator: a backend-for-frontend calling a service that fans out to several stores, a portal page calling a section service, a parent agent reading a sub-agent's summary, a pipeline stage consuming the merged output of an earlier stage, or a federated search calling a regional search that federates again.
This skill assumes each layer already models its own sources as ok, empty, unavailable or skipped with a separate completeness flag, and keeps partial results. It covers the narrower question that model leaves open: the child returns a structured result that says partial or failed, and the parent has to turn that whole result into exactly one outcome for the child as a source. Done carelessly, the parent reintroduces the flattening the child avoided.
The failure pattern
- Transport success read as ok and complete. The child answers with a success status and a body whose overall field says partial. The parent's client only checks the transport status, so the child becomes ok and complete. Everything the child could not see is now, at the parent, confirmed absent.
- Failed child read as empty. The child reports overall failed with zero items, again over a success transport status. The parent sees an empty item list and reports empty. An outage two layers down becomes a confirmed absence one layer up.
- Missing-source list dropped. The child names the sub-sources it could not reach. The parent keeps only a boolean or a count, so the consumer at the top cannot tell which data is missing or whether the missing part matters to it.
- Required sub-source hidden inside a partial. The child treats an authorization or conflict check as optional and reports partial. The parent needed that check to be complete. Because the parent only sees the overall value, it proceeds.
- Degrade counted twice. The parent derives its own overall status from the child's overall value and from the child's sub-source list, so the same missing sub-source lowers the parent's result twice, or once at each of three layers. Every response becomes partial and the flag stops meaning anything.
- Stale label lost. The child served one sub-source from stale cache with an age. The parent copies the items and forgets the stale flag and age. The top layer presents fallback data as current.
Rule
The parent classifies the child from the child's body, not from the transport status alone. It produces one outcome for the child using three inputs: the child's overall status, the child's completeness, and the parent's own requirement on the child's sub-sources. The mapping is:
- Child overall complete, one or more items: status ok, complete true.
- Child overall complete, zero items: status empty, complete true.
- Child overall partial, one or more items: status ok, complete false.
- Child overall partial, zero items: status empty, complete false. Do not report unavailable, because some sub-sources did answer. Do not report empty and complete, because some did not.
- Child overall failed: status unavailable, complete false, regardless of transport status.
- Transport failure, timeout, malformed body, or a body without a recognizable overall field: status unavailable, complete false. The child's sub-sources are all unknown.
- Any child sub-source that the parent lists as required is unavailable, incomplete or stale beyond the parent's tolerance: status unavailable for the whole child, complete false, reason naming that sub-source. This overrides a partial overall value.
Completeness at the parent is the child's completeness and never higher. The stale flag is true if any contributing sub-source was stale, and the reported age is the largest age among them. The effective as-of time used for any absence decision is the oldest observed time among the sub-sources that contributed.
The parent's overall status is then derived only from the parent's own per-source outcomes, where the child is one source. The child's internal partial has already been folded into that one outcome and is not counted again.
How to apply
- Make the child's contract explicit. The child's result must expose an overall value of complete, partial or failed, a completeness flag, the item list, and a per-sub-source list with name, status, completeness, stale flag, age and reason. A summary sentence or a bare item list is not enough for a parent to classify safely.
- Classify from the body. In the parent's adapter for the child, read the overall field first. Treat a success transport status with a failed body as unavailable. Treat a success transport status with an unparseable body as unavailable. Never let a default of an empty collection fill a missing items field.
- Declare requirements per layer. The parent keeps a short list of the child's sub-sources it requires, by name. If the child cannot prove those complete, the parent marks the child unavailable. The child cannot know what the parent needs, so this decision belongs to the parent. Optionally pass the required names down with the request so the child does not skip them for budget reasons.
- Carry provenance as paths. The parent's outcome keeps a missing list whose entries are path names such as child name, then a separator, then sub-source name. Concatenate the child's missing list under the child's name rather than replacing it with a count. Bound the depth, for example three levels, and beyond that keep the count plus the top-level names.
- Propagate the labels, not just the items. Copy the stale flag, the largest age, and the oldest observed time into the parent's outcome for the child. A consumer that gates absence decisions on stale false and completeness true must be able to see these at every depth.
- Pass a remaining time budget down. Give the child a deadline that fits inside the parent's per-source timeout. A child that answers after the parent's deadline is unavailable at the parent even if its late answer was complete. Without this, the child's own per-source timeouts add up to more than the parent will wait, and the parent times out a child that was about to return a good partial answer.
- Speak in the top layer's terms. When the top layer tells a user or an agent that a result is partial, name the missing paths in words the consumer understands, for example that the notes part of the activity section is unavailable, rather than listing internal service names or only saying partial.
Minimal shape (language-neutral)
child result = { overall: complete or partial or failed, complete: true or false, items: [...], sources: [ { name, status, complete, stale, ageseconds, observedat, reason } ] }
parent outcome for the child = { name: "activity", status: ok or empty or unavailable or skipped, complete: child.complete and no required sub-source is missing, stale: any contributing sub-source stale, ageseconds: largest sub-source age, observedat: oldest sub-source observed time, missing: [ "activity/notes", "activity/transfers" ], items: child.items, reason }
Reasoned example
A portfolio page is assembled by a parent service from three sources: holdings, activity and alerts. The activity source is a child service that itself fans out to an orders store, a transfers store and a notes store. The notes store is down for ten minutes.
The child returns a success transport status with overall partial, orders and transfers items present, and notes listed as unavailable with a timeout reason.
A parent that classifies by transport status marks activity ok and complete. The page contains an onboarding banner shown whenever a user has no notes, and a nightly job that deletes empty note drafts for users with no notes. Both read the page model, both see no notes and completeness true, and both act. The banner appears for every user for ten minutes and the nightly job, if it runs in that window, deletes drafts.
A parent that follows this skill marks activity ok, complete false, missing activity slash notes, with the timeout reason. Its overall status is partial. The banner logic requires completeness true for the notes path and does not show. The nightly job requires completeness true and stale false and skips those users. The page shows orders and transfers and says that notes are temporarily unavailable.
Second case in the same setup: the child's sub-source list shows its ownership check as unavailable, and the parent lists that check as required for the activity section. The child still says partial. The parent marks activity unavailable and the whole section fails closed, while holdings and alerts still render.
This example is reasoning about the procedure. It is not the result of an executed test.
Checks before shipping
These are suggested verification steps for adopters, not observed results.
- Return a child body with overall partial over a success transport status. The parent outcome should be ok or empty with completeness false, and the missing list should contain the path-named sub-source.
- Return a child body with overall failed and zero items over a success transport status. The parent outcome should be unavailable, not empty.
- Return a child body with overall partial where the missing sub-source is on the parent's required list. The parent outcome should be unavailable with a reason naming that sub-source.
- Return a child body where one sub-source was served stale with an age. The parent outcome should carry stale true and that age.
- Nest three layers with one missing leaf. The top-level result should be partial exactly once and its missing list should contain one three-segment path.
- Delay the child past the parent's deadline while the child would have returned complete. The parent should report the child unavailable and the other parent sources should still appear.
Pitfalls
- A client wrapper that raises on transport errors but returns any success body untouched, so partial and failed bodies pass through as data.
- Summaries between agents that say what was found but not what could not be checked. A sub-agent's summary needs the same missing list a service response would carry.
- Deciding required sub-sources inside the child. The child does not know which consumer needs what.
- Recomputing the parent's overall status from the child's sub-source list as well as from the child's outcome, which degrades the same failure twice.
- Keeping only the newest observed time for the child, which makes an absence decision look fresher than its oldest contributing sub-source.
- Carrying the missing list only in logs. The top layer's consumer needs it in the response.