Skip to main content
Your progress
0 of 5 lessons complete0%
T2 / M2.13 / L1 OF 5 / Engineer TIER / 9 min

The recommendation timeline

Outcome

By the end of this lesson, you will be able to read the per-recommendation History drawer, interpret each event type, and explain which engine bookkeeping is deliberately withheld from the customer surface and why.


TierEngineer
JTBD”Answer ‘what happened to this finding, and who did it’ without reconstructing it from the audit log.”
PersonasPlatform Engineer · FinOps Lead · Security/Compliance
PrerequisitesM2.1.L5 (reading a recommendation card)
Time9 minutes
Bloom verbRead (Apply), Interpret (Understand), Explain (Understand)

1. Concept

Every recommendation carries a timeline. Generated, viewed, bookmarked, unbookmarked, applied, dismissed, reopened and closed are all recorded as audit events and rendered in a per-recommendation History drawer.

Terminal window
THE DRAWER
Day cards down a continuous spine, newest first.
Each card carries its own activity feed.
One filter, by rule.
The identifier copies on click.

Why day cards rather than a flat list

A recommendation that is raised, closed and raised again over three months produces a scattered event list. Grouping into day cards gives the reader the unit they actually think in (“what happened on the 14th”), and the continuous spine keeps the gaps visible.

Each card is seeded with the status the day started in. This matters more than it sounds: a card is handed one day’s slice of events, which often contains no transition at all, so an unseeded card would render “Status unknown” directly beneath a badge naming the status.

The one filter, and why only one

The drawer offers exactly one filter: by rule. It runs client-side over the cards.

The API accepts kind, since and until filters too, and those are deliberately not surfaced here. The reason is worth understanding because it is a genuine design trap:

Terminal window
THOSE FILTERS NARROW *EVENTS*.
THE CARDS COME FROM AN UNFILTERED RECOMMENDATION LIST.
A card is emitted for a recommendation even when no event
matches, dated from its generatedAt and carrying its
current status.
So an event filter would remove NO cards while relabelling
every one of them, under a bar reading "filtered".

Surfacing them would need the narrowing applied to the recommendation query as well, or that fallback suppressed while a filter is active. Neither is free, so the filter stays off the surface rather than shipping something that lies.

It opens narrowed, on purpose

The panel opens filtered to the rule of the recommendation you opened it from, because that is the question you arrived with. Following one finding through its history otherwise means scrolling past unrelated ones: a recommendation active on two days can easily have four unrelated cards between its own two.

Terminal window
IT NARROWS BY RULE, NOT BY RECOMMENDATION ID.
A finding raised, closed and raised again is one story,
and keying on rule keeps it whole across the reopen.

The filter is multi-select with a Select all row that flips to Clear selection once everything is ticked, so it is never a click that changes nothing. Ticking every rule and ticking none show the same cards, because an empty filter cannot mean “hide everything” without stranding the reader in a blank panel; what differs is what the control says.

The narrowing is stated once, on the control itself: the trigger reads the selected rule’s name, or “2 selected”, instead of “All rules”. That is the panel’s only indicator that it opened narrowed, so it has to stay.

Bookmarks

Bookmarking writes its event in the same transaction as the bookmark row. A star can never exist without the line that explains it.

Bookmarks are per-user, unlike almost everything else on the recommendation surface, which is org-scoped.

What the customer surface withholds

Three things exist on the internal console and not on the customer’s, and the gate is on the surface, not on permissions. A Viewer on the customer surface is read-only too, so read-only is the wrong key.

Terminal window
1. closure reason `rule_not_fired`
Rendered internally as "No longer detected". It is the
vaguest true thing we can say about a close, and it is
the wrong thing to show on a recommendation our own
probe actually verified.
2. `ruleVersion` ("Raised under rule v1")
Our catalogue's version of its own check. A customer
cannot act on it because they cannot see what changed
between versions.
3. The billed-cost card (from cost-history)
Held back while the billing column behind it is
confirmed against a real invoice, because it is the one
panel a customer would reconcile against their bill.

The same split governs the rule_retired status tab, which renders as “Withdrawn” internally and is hidden from the customer’s own tab row entirely.

One request, not one per card

The resource-history view fetches every listed recommendation’s activity in a single request, capped at 200 ids, rather than one per card. The route is resource-scope gated exactly like the single-recommendation history route: a timeline carries actor emails and status transitions, so it is at least as sensitive as the recommendation it describes.


2. Demo

Reading one finding’s history to answer a real question:

Terminal window
QUESTION FROM FINANCE
"We were told this $1,100/month saving was captured in
May. It's September and the bill hasn't moved."
OPEN THE RECOMMENDATION -> History
Sep 02 ● generated RC-003 EC2 Rightsizing
│ i-0a3f9c2b1d m5.2xlarge
│ status: open
│
Jun 14 ● reopened
│ (rule fired again on the same resource)
│
May 21 ● closed cause: rule_not_fired
│
May 19 ● applied by priya@platform
│ status: applied
● viewed by priya@platform
│
May 19 ● generated
status: open
WHAT THIS SAYS
The finding was applied on 19 May, closed two days later
because the rule stopped firing, and RAISED AGAIN on
14 June against the same resource.
The May close was `rule_not_fired`, which is the vaguest
true thing available: the rule stopped detecting it. That
is not the same as "it was fixed".
The June reopen is the tell. The resource is back to the
shape the rule objects to, or never left it.
THE ANSWER TO FINANCE
"It was marked applied in May and the rule went quiet for
three weeks. It came back in June and has been open
since. The saving was never durably captured. L2 covers
how we now measure that instead of trusting the status."
WHAT THE CUSTOMER SURFACE DID NOT SHOW
The words "rule_not_fired" and the rule version. Both are
on the internal console. The customer sees the shape of
the story without our bookkeeping vocabulary.

3. Hands-on (6 min)

Terminal window
1. Open any recommendation and click into History.
How many day cards? ______
Is the rule filter pre-selected? Y / N
What does the trigger read? ____________________
2. Clear the filter to "all rules". Do MORE cards appear?
Y / N
If yes, those are other findings on the same resource.
3. Find a card whose feed shows no transition at all.
What status does it display, and where did that come
from? ______________________________________
4. Bookmark a recommendation, then reopen History.
Is there an event for it? Y / N
(It is written in the same transaction as the star.)
5. Find a recommendation that was applied and later
reopened. Note the gap:
applied ________ reopened ________ days ______
That gap is the thing L2 exists to measure.

Do it through MCP. The same task you just did in the console, asked in one sentence.

Terminal window
BEFORE A ZopNight account with one cloud connected. One open recommendation with an owner you can name.
ASK "Move this recommendation to in progress and share it with the platform team."
CHECK the timeline after the change. Status is a claim, the timeline is the evidence, which is L2.

Tools behind it: get_recommendation (read, Optimize), update_recommendation_status (write, tier 1, metadata only), share_recommendation (write, tier 2, reversible). The full catalogue is at zop.dev/learn/mcp-tools.


4. Knowledge check

Q1

The History drawer accepts kind, since and until filters at the API level but surfaces only a rule filter. Why?

A. Those filters narrow events, while the cards come from an unfiltered recommendation list, and a card is emitted even when no event matches
B. The other filters were not implemented yet
C. They would be too slow client-side
D. They are reserved for the internal console only, and the customer-facing drawer silently ignores whatever is passed in to it

Show answer

Correct: A. So an event filter would remove no cards while relabelling every one of them under a bar reading “filtered”. Surfacing them properly needs the narrowing applied to the recommendation query too, or the no-match card fallback suppressed while a filter is active. Shipping the control without that would produce a UI that says it filtered something and did not.

Q2

The History panel opens narrowed to one rule rather than showing everything. It narrows by rule rather than by recommendation id because:

A. Rule filtering is cheaper to compute
B. Recommendation ids are not stable
C. It exactly matches the Recommendations page filter shape itself
D. A finding that was raised, closed and raised again is one story

Show answer

Correct: D. Keying on the rule keeps it whole across the reopen, where keying on recommendation id would split it into two unrelated histories. The narrowing is stated once, on the trigger itself, which reads the rule’s name instead of “All rules”. If that ever stops naming the selection, the panel loses its only signal that it opened narrowed.

Q3

Why is the closure reason rule_not_fired shown on the internal console but hidden from the customer surface?

A. It contains sensitive infrastructure detail that a customer should not be shown, so the reason is replaced with a generic one on the way out to them
B. It is the vaguest true thing that can be said about a close, and showing it on a recommendation our own probe actually verified would be the wrong explanation
C. Customers cannot be shown closure reasons
D. It is only accurate for K8s rules

Show answer

Correct: B. The gate is on the surface rather than on permissions, because a Viewer on the customer surface is read-only too. Two other things follow the same split. ruleVersion is withheld because a customer cannot act on it: they cannot see what changed between versions. The billed-cost card is withheld until the billing column has been checked against a real invoice.


5. Apply

Next time someone disputes whether a saving was captured, open History before opening the audit log. The reopen events are the fastest signal that an “applied” claim did not hold, and they are the reason the two-column model in L2 exists.


Glossary terms touched

History drawer · Day card · Closure reason · rule_retired


Start with the bill.

Foundations takes about five hours. The first lesson is nine minutes.

Open curriculum. No login. No paywall. 290 lessons across 7 courses, three publicly verifiable credentials. Read it on the train, take the exam on a Saturday, list the credential on your résumé Monday.

5h median time to finish Foundations
0 logins, paywalls, or marketing forms
open curriculum, public credential verifier
Multi-cloud automation· Production-ready in 30 min· SOC 2 · ISO 27001· 20–60% off the bill, first month· 4 platforms · 1 console· Multi-cloud automation· Production-ready in 30 min· SOC 2 · ISO 27001· 20–60% off the bill, first month· 4 platforms · 1 console·