From 0387d6db229aab1623bf0e2b9e23598e5cb6d900 Mon Sep 17 00:00:00 2001 From: "github-actions[bot]" Date: Tue, 21 Jul 2026 09:06:14 +0000 Subject: [PATCH] feat: sync adventure dead-reckoning from challenges repo (update) --- e2e/smoke.spec.ts | 1 + public/sitemap.xml | 17 +- react-router.config.ts | 1 + scripts/refresh-leaderboard.mjs | 2 +- .../adventures/dead-reckoning.generated.ts | 100 +++++++++- .../adventures/dead-reckoning/adventure.yaml | 186 +++++++++++++++++- .../dead-reckoning/expert-posts.json | 5 + src/data/adventures/summaries.ts | 11 ++ src/test/prerender.test.ts | 4 + src/test/seo.test.ts | 1 + 10 files changed, 311 insertions(+), 17 deletions(-) create mode 100644 src/data/adventures/dead-reckoning/expert-posts.json diff --git a/e2e/smoke.spec.ts b/e2e/smoke.spec.ts index 4734e05a7..0585419b9 100644 --- a/e2e/smoke.spec.ts +++ b/e2e/smoke.spec.ts @@ -21,6 +21,7 @@ const ROUTES: RouteSpec[] = [ { path: "/adventures/dead-reckoning", title: /Dead Reckoning/ }, { path: "/adventures/dead-reckoning/levels/beginner", title: /Laying the Keel/ }, { path: "/adventures/dead-reckoning/levels/intermediate", title: /Sea Trial/ }, + { path: "/adventures/dead-reckoning/levels/expert", title: /The Chronometer/ }, { path: "/adventures/lex-imperfecta", title: /Lex Imperfecta/ }, { path: "/adventures/lex-imperfecta/levels/beginner", title: /The Twelve Tables/ }, { path: "/adventures/lex-imperfecta/levels/intermediate", title: /Governing the Provinces/ }, diff --git a/public/sitemap.xml b/public/sitemap.xml index 48832a225..55bfcf452 100644 --- a/public/sitemap.xml +++ b/public/sitemap.xml @@ -9,9 +9,10 @@ https://offon.dev/accessibility/2026-06-01yearly0.5 https://offon.dev/brand/2026-06-05yearly0.4 - https://offon.dev/adventures/dead-reckoning/2026-07-14monthly0.8 - https://offon.dev/adventures/dead-reckoning/levels/beginner/2026-07-14monthly0.8 - https://offon.dev/adventures/dead-reckoning/levels/intermediate/2026-07-14monthly0.8 + https://offon.dev/adventures/dead-reckoning/2026-07-21monthly0.8 + https://offon.dev/adventures/dead-reckoning/levels/beginner/2026-07-21monthly0.8 + https://offon.dev/adventures/dead-reckoning/levels/intermediate/2026-07-21monthly0.8 + https://offon.dev/adventures/dead-reckoning/levels/expert/2026-07-21monthly0.8 https://offon.dev/adventures/lex-imperfecta/2026-07-15monthly0.8 https://offon.dev/adventures/lex-imperfecta/levels/beginner/2026-07-15monthly0.8 https://offon.dev/adventures/lex-imperfecta/levels/intermediate/2026-07-15monthly0.8 @@ -38,13 +39,13 @@ https://offon.dev/challenges/2026-06-03weekly0.9 - https://offon.dev/challenges/argo-cd/2026-07-14monthly0.7 - https://offon.dev/challenges/argo-events/2026-07-14monthly0.7 + https://offon.dev/challenges/argo-cd/2026-07-21monthly0.7 + https://offon.dev/challenges/argo-events/2026-07-21monthly0.7 https://offon.dev/challenges/argo-rollouts/2026-05-31monthly0.7 - https://offon.dev/challenges/argo-workflows/2026-07-14monthly0.7 - https://offon.dev/challenges/backstage/2026-07-14monthly0.7 + https://offon.dev/challenges/argo-workflows/2026-07-21monthly0.7 + https://offon.dev/challenges/backstage/2026-07-21monthly0.7 https://offon.dev/challenges/flagd/2026-07-15monthly0.7 - https://offon.dev/challenges/gitea/2026-07-14monthly0.7 + https://offon.dev/challenges/gitea/2026-07-21monthly0.7 https://offon.dev/challenges/github-actions/2026-07-15monthly0.7 https://offon.dev/challenges/grafana/2026-07-15monthly0.7 https://offon.dev/challenges/jaeger/2026-07-08monthly0.7 diff --git a/react-router.config.ts b/react-router.config.ts index cd158f6fb..1687d142a 100644 --- a/react-router.config.ts +++ b/react-router.config.ts @@ -21,6 +21,7 @@ export default { "/adventures/dead-reckoning", "/adventures/dead-reckoning/levels/beginner", "/adventures/dead-reckoning/levels/intermediate", + "/adventures/dead-reckoning/levels/expert", "/adventures/lex-imperfecta", "/adventures/lex-imperfecta/levels/beginner", "/adventures/lex-imperfecta/levels/intermediate", diff --git a/scripts/refresh-leaderboard.mjs b/scripts/refresh-leaderboard.mjs index c900704f3..99580eb4c 100644 --- a/scripts/refresh-leaderboard.mjs +++ b/scripts/refresh-leaderboard.mjs @@ -35,7 +35,7 @@ const QUERY_ID = 5; // Category IDs are from: GET https://community.offon.dev/categories.json const ADVENTURE_CATEGORIES = { // GENERATED:adventures - "dead-reckoning": { categoryId: 45, has_beginner: true, has_intermediate: true, has_expert: false, has_single: false }, + "dead-reckoning": { categoryId: 45, has_beginner: true, has_intermediate: true, has_expert: true, has_single: false }, "lex-imperfecta": { categoryId: 43, has_beginner: true, has_intermediate: true, has_expert: true, has_single: false }, "blind-by-design": { categoryId: 41, has_beginner: true, has_intermediate: true, has_expert: true, has_single: false }, "the-ai-observatory": { categoryId: 37, has_beginner: true, has_intermediate: true, has_expert: true, has_single: false }, diff --git a/src/data/adventures/dead-reckoning.generated.ts b/src/data/adventures/dead-reckoning.generated.ts index b621dc8ea..2f2fdc625 100644 --- a/src/data/adventures/dead-reckoning.generated.ts +++ b/src/data/adventures/dead-reckoning.generated.ts @@ -1,5 +1,6 @@ import { CODESPACES_BASE, COMMUNITY_URL } from "@/data/constants"; import deadReckoningIntermediate from "@/assets/diagrams/dead-reckoning-intermediate.svg"; +import deadReckoningExpert from "@/assets/diagrams/dead-reckoning-expert.svg"; import type { Adventure } from "./types"; export const DEAD_RECKONING: Adventure = { @@ -28,9 +29,6 @@ export const DEAD_RECKONING: Adventure = { rankingNote: "Ranking is determined by total points across all three levels. Points per level are awarded by submission order within the active week (100 for the first valid solution, 95 for the second, and so on; late submissions still earn 60).", rankingRulesUrl: `${COMMUNITY_URL}/t/about-the-challenges-category/16`, }, - upcomingLevels: [ - { name: "Expert", difficulty: "Expert" }, - ], levels: [ { id: "beginner", @@ -205,5 +203,101 @@ commissioned vessel stage by stage and reports the first place the pipeline runs }, metaDescription: "Sea Trial: Fix the broken integration points in the delivery pipeline so that commissioning a vessel in Backstage results in a running deployment.", }, + { + id: "expert", + name: "The Chronometer", + difficulty: "Expert", + topics: ["Backstage", "Argo Workflows", "Argo CD", "OpenTelemetry", "Jaeger"], + audience: "Platform and DevOps engineers who already know how the delivery pipeline fits together and want to see how a distributed trace ties it into one story. You should be comfortable with Kubernetes, YAML, and reading a tool's logs and UI. Prior exposure to OpenTelemetry, trace context propagation, and a trace viewer like Jaeger helps, but the focus here is using a trace to reason across service boundaries, not any one tool.", + learnings: [ + "How trace context crosses an asynchronous boundary with no call chain: a commission carries its W3C traceparent to a push-triggered pipeline, so its spans continue the same trace instead of starting a new one", + "Why a distributed trace reveals what per-tool logs cannot: the value that flowed through each step, so a fault surfaces where the data diverges", + "How to read that trace in Jaeger to localise a fault to a single service by following one attribute across the whole voyage", + ], + codespacesUrl: `${CODESPACES_BASE}?devcontainer_path=.devcontainer%2Fdead-reckoning_expert%2Fdevcontainer.json&quickstart=1&machine=standardLinux32gb`, + discussionUrl: "", + deadline: "2026-07-28T23:59:00+01:00", + intro: [ + "Repair the fleet's broken navigation log, then use the complete trace it produces to find why vessels arrive carrying the wrong cargo.", + ], + backstory: [ + "Every commission the office issues is supposed to leave one clean line in the navigation log: the moment a captain fills in the papers, the yards that build and deliver the vessel, and the harbor master bringing it into formation, all recorded as a single voyage you can read end to end. Read the log and you know exactly what happened to any vessel, and when.", + "Lately the log lies. It records the commission office plainly enough, then goes dark the instant a vessel leaves for the yards: the shipyard's and harbor master's work never appears on the same line. And at the far end of the voyage, captains keep signing for the wrong cargo, salt-pork where citrus was ordered, though every yard along the route reported a clean, successful run. No single tool shows anything wrong.", + "Your mission: repair the log so a commission reads as one unbroken voyage again, from the office all the way to open water, then use that complete picture to find where the cargo goes astray, and set it right.", + ], + objective: [ + "Every commission appears in the navigation log (Jaeger) as a single, connected trace, unbroken from the commission office (Backstage) through the shipyard (Argo Workflows) and the harbor master (Argo CD)", + "Every vessel sails carrying the provisions it was commissioned to carry", + ], + architecture: [ + "

This level adds a tracing overlay to the Sea Trial delivery pipeline: every stage now reports spans to an OpenTelemetry Collector, which forwards them to Jaeger. The commission office opens the trace and hands its context to the pipeline, so one commission should read as a single connected voyage: commission <vessel> -> enter parameters and scaffold repos (Backstage) -> ci pipeline (Argo Workflows) -> rollout (Argo CD).

", + "

The cargo rides that trace at three checkpoints, so you see not just that it is wrong but where it changed: provisions.ordered (root span, what was selected), provisions.declared (rollout span, what the deployment sets), and provisions.reported (rollout span, what the running vessel says it carries). In a healthy voyage all three agree.

", + "

Your repairs live in the vessel commissioning template under backstage/templates/vessel-commissioning-template/ (template.yaml and the files under content/). Everything else, the platform/ manifests and the Backstage tracing setup, is working: read it to see how the trace is carried out to sea, but you won't need to change it.

", + "

This level runs a real container build, so your Codespace uses a larger (4-core / 16 GB) machine. Give the pipeline a few minutes after commissioning; the delivery spans land in Jaeger once the rollout completes.

", + `
+

A quick translation from the story to the tools: a vessel is a small service you deploy; its cargo (provisions) is a value it is commissioned to carry, set in its deployment and reported by the running service. The commission office is Backstage, the shipyard is Argo Workflows, the harbor master is Argo CD, and the navigation log is Jaeger. A commission's voyage is the single distributed trace that should span all of them.

+
`, + ], + architectureDiagram: deadReckoningExpert, + diagramAlt: "The delivery pipeline runs left to right across the top: Backstage creates the repositories, Argo Events triggers the CI build, Argo Workflows builds the image and updates the tag, Argo CD syncs the deployment, and the vessel's app is up and running. A W3C traceparent thread runs through the pipeline. Backstage, Argo Workflows, and Argo CD each report spans down to the OpenTelemetry Collector, which feeds Jaeger, where a single commission appears as one connected trace: a Commission Vessel root span over Backstage, Argo Workflows, and Argo CD spans.", + toolbox: [ + { name: "Jaeger", description: "The navigation log (port 30103). Shows each commission's trace; search by service backstage and operation commission <vessel> to open a voyage, then read its spans and their attributes.", url: "https://www.jaegertracing.io/docs/latest/" }, + { name: "Backstage", description: "The commission office and your cockpit (port 3000). Commission a vessel from Create; its page carries a Voyage log card that links to the trace.", url: "https://backstage.io/docs/features/software-templates/" }, + { name: "Argo Workflows", description: "The shipyard (port 30113). Runs the multi-step build-and-deliver workflow and emits the ci pipeline spans.", url: "https://argo-workflows.readthedocs.io/en/latest/" }, + { name: "Argo CD", description: "The harbor master (port 30100). Reconciles each vessel into the cluster and emits the rollout span.", url: "https://argo-cd.readthedocs.io/en/stable/" }, + { name: "OpenTelemetry Collector", description: "The signal station every component reports spans to; it forwards them on to Jaeger. Part of the working tracing setup, here to read, not to change.", url: "https://opentelemetry.io/docs/collector/" }, + ], + howToPlay: [ + { title: "Open the Commission Office", content: `

Start Backstage with make backstage. The first run compiles for ~30-60s; once it's up, the commission +office is available in your browser on port 3000. Leave it running in that terminal; restart any time with +Ctrl-C then make backstage.

+

The rest of the platform (Gitea, Argo Events, Argo Workflows, Argo CD, the OpenTelemetry Collector, and Jaeger) +is already running in the cluster.

` }, + { title: "Explore the UIs", content: `

Open the Ports tab and navigate to each service:

+` }, + { title: "Sail a Commission and Read the Log", content: `

In Backstage, go to Create and run the Commission a Vessel template. Pick a cargo you'll remember (say +Citrus), and let the vessel sail. Delivery still works, but the records don't add up. You have two +instruments to check what really happened:

+ +

The trace is your instrument for both. It carries the cargo along the voyage (provisions.ordered -> +provisions.declared -> provisions.reported), so once the log reads true end to end, Jaeger is where you +follow the cargo from order to arrival and find where it goes astray.

` }, + { title: "Repair the Log, Then the Cargo", content: `

Both repairs live in the vessel commissioning template:

+
backstage/templates/vessel-commissioning-template/
+
+

Start with the log. Read how a commission carries its trace context out to the pipeline, and how the pipeline +picks it back up off the push it reacts to; the two need to line up on the same commit. With the voyage whole, +the trace shows the cargo at each checkpoint (provisions.ordered -> provisions.declared -> +provisions.reported): follow it and let it tell you which stage the cargo survives and which one it doesn't.

+

Test a fix by commissioning a fresh vessel and watching it sail. If you edited template.yaml, reload it into +Backstage first so the next commission picks up your change:

+
make reload-template
+
` }, + ], + helpfulLinks: [ + { title: "W3C Trace Context", url: "https://www.w3.org/TR/trace-context/", description: "The traceparent format that carries a trace across service boundaries" }, + { title: "OpenTelemetry: Context Propagation", url: "https://opentelemetry.io/docs/concepts/context-propagation/", description: "How spans in different processes are stitched into one trace by passing context between them" }, + { title: "OpenTelemetry: Traces", url: "https://opentelemetry.io/docs/concepts/signals/traces/", description: "What a trace and its spans are, and why they capture causal, data-carrying detail logs don't" }, + { title: "Jaeger: Documentation", url: "https://www.jaegertracing.io/docs/latest/", description: "Searching for and reading distributed traces across services" }, + { title: "Backstage: Software Templates", url: "https://backstage.io/docs/features/software-templates/", description: "How a scaffolder template runs its steps and passes values between them" }, + ], + verification: { + command: "make verify", + description: "Grades the most recently commissioned vessel against the two end-states: its commission is one connected trace in Jaeger, and the running vessel reports the cargo its deployment declares. Each check reports on its own, so you see which half of the log still reads false.", + }, + metaDescription: "The Chronometer: Repair the fleet's broken navigation log, then use the complete trace it produces to find why vessels arrive carrying the wrong cargo.", + }, ], }; diff --git a/src/data/adventures/dead-reckoning/adventure.yaml b/src/data/adventures/dead-reckoning/adventure.yaml index 28e3cdde3..763a0fb31 100644 --- a/src/data/adventures/dead-reckoning/adventure.yaml +++ b/src/data/adventures/dead-reckoning/adventure.yaml @@ -28,10 +28,6 @@ contributor: about: DevRel at Dynatrace and co-organizer of Cloud Native Linz. Passionate about building user-friendly Cloud Native and Kubernetes solutions, with a background in mobile and backend development. Found in tech and sports communities, inline skating rinks, and quiz nights across Europe. -upcoming_levels: - - level: expert - name: Expert - difficulty: Expert levels: - level: beginner emoji: 🟢 @@ -215,7 +211,7 @@ levels: **harbor master** is Argo CD; Argo Events is the lookout that summons the shipyard when new code is filed. A vessel "reaching open water" just means a commissioned service made it all the way to a running, reachable deployment.' - architecture_diagram: "dead-reckoning-intermediate.svg" + architecture_diagram: dead-reckoning-intermediate.svg diagram_alt: "Left-to-right delivery pipeline: Backstage creates the repositories, Argo Events triggers the CI build, Argo Workflows builds the image and updates the tag, Argo CD syncs the deployment, and the vessel's app is up and running." @@ -326,3 +322,183 @@ levels: url: https://argo-cd.readthedocs.io/en/stable/user-guide/auto_sync/ description: How Argo CD reconciles an Application's desired state into the cluster deadline: 2026-07-28T23:59:00+01:00 + - level: expert + emoji: 🔴 + title: The Chronometer + devcontainer: dead-reckoning_expert + community_url: "" + summary: Repair the fleet's broken navigation log, then use the complete trace it produces to find why vessels arrive + carrying the wrong cargo. + topics: + - Backstage + - Argo Workflows + - Argo CD + - OpenTelemetry + - Jaeger + audience: Platform and DevOps engineers who already know how the delivery pipeline fits together and want to see how a + distributed trace ties it into one story. You should be comfortable with Kubernetes, YAML, and reading a tool's + logs and UI. Prior exposure to OpenTelemetry, trace context propagation, and a trace viewer like Jaeger helps, but + the focus here is using a trace to reason across service boundaries, not any one tool. + backstory: + - "Every commission the office issues is supposed to leave one clean line in the navigation log: the moment a + captain fills in the papers, the yards that build and deliver the vessel, and the harbor master bringing it into + formation, all recorded as a single voyage you can read end to end. Read the log and you know exactly what + happened to any vessel, and when." + - "Lately the log lies. It records the commission office plainly enough, then goes dark the instant a vessel + leaves for the yards: the shipyard's and harbor master's work never appears on the same line. And at the far end + of the voyage, captains keep signing for the wrong cargo, salt-pork where citrus was ordered, though every yard + along the route reported a clean, successful run. No single tool shows anything wrong." + - "Your mission: repair the log so a commission reads as one unbroken voyage again, from the office all the way to + open water, then use that complete picture to find where the cargo goes astray, and set it right." + objective: + - Every commission appears in the navigation log (Jaeger) as a single, connected trace, unbroken from the + commission office (Backstage) through the shipyard (Argo Workflows) and the harbor master (Argo CD) + - Every vessel sails carrying the provisions it was commissioned to carry + what_you_learn: + - "How trace context crosses an asynchronous boundary with no call chain: a commission carries its [W3C + traceparent](https://www.w3.org/TR/trace-context/) to a push-triggered pipeline, so its spans [continue the same + trace](https://opentelemetry.io/docs/concepts/context-propagation/) instead of starting a new one" + - "Why a [distributed trace](https://opentelemetry.io/docs/concepts/signals/traces/) reveals what per-tool logs + cannot: the value that flowed through each step, so a fault surfaces where the data diverges" + - How to read that trace in [Jaeger](https://www.jaegertracing.io/docs/latest/) to localise a fault to a single + service by following one attribute across the whole voyage + architecture: + - "This level adds a tracing overlay to the Sea Trial delivery pipeline: every stage now reports spans to an + **OpenTelemetry Collector**, which forwards them to **Jaeger**. The commission office opens the trace and hands + its context to the pipeline, so one commission should read as a single connected voyage: `commission ` + -> `enter parameters` and `scaffold repos` (Backstage) -> `ci pipeline` (Argo Workflows) -> `rollout` (Argo + CD)." + - "The cargo rides that trace at three checkpoints, so you see not just *that* it is wrong but *where* it changed: + `provisions.ordered` (root span, what was selected), `provisions.declared` (rollout span, what the deployment + sets), and `provisions.reported` (rollout span, what the running vessel says it carries). In a healthy voyage + all three agree." + - "Your repairs live in the vessel commissioning template under + `backstage/templates/vessel-commissioning-template/` (`template.yaml` and the files under `content/`). + Everything else, the `platform/` manifests and the Backstage tracing setup, is working: read it to see how the + trace is carried out to sea, but you won't need to change it." + - This level runs a real container build, so your Codespace uses a larger (**4-core / 16 GB**) machine. Give the + pipeline a few minutes after commissioning; the delivery spans land in Jaeger once the rollout completes. + - "> A quick translation from the story to the tools: a **vessel** is a small service you deploy; its **cargo** + (**provisions**) is a value it is commissioned to carry, set in its deployment and reported by the running + service. The **commission office** is Backstage, the **shipyard** is Argo Workflows, the **harbor master** is + Argo CD, and the **navigation log** is Jaeger. A commission's **voyage** is the single distributed trace that + should span all of them." + diagram_alt: "The delivery pipeline runs left to right across the top: Backstage creates the repositories, Argo Events + triggers the CI build, Argo Workflows builds the image and updates the tag, Argo CD syncs the deployment, and the + vessel's app is up and running. A W3C traceparent thread runs through the pipeline. Backstage, Argo Workflows, and + Argo CD each report spans down to the OpenTelemetry Collector, which feeds Jaeger, where a single commission + appears as one connected trace: a Commission Vessel root span over Backstage, Argo Workflows, and Argo CD spans." + toolbox: + - name: Jaeger + url: https://www.jaegertracing.io/docs/latest/ + description: The navigation log (port 30103). Shows each commission's trace; search by service `backstage` and operation + `commission ` to open a voyage, then read its spans and their attributes. + - name: Backstage + url: https://backstage.io/docs/features/software-templates/ + description: The commission office and your cockpit (port 3000). Commission a vessel from Create; its page carries a + Voyage log card that links to the trace. + - name: Argo Workflows + url: https://argo-workflows.readthedocs.io/en/latest/ + description: The shipyard (port 30113). Runs the multi-step build-and-deliver workflow and emits the `ci pipeline` spans. + - name: Argo CD + url: https://argo-cd.readthedocs.io/en/stable/ + description: The harbor master (port 30100). Reconciles each vessel into the cluster and emits the `rollout` span. + - name: OpenTelemetry Collector + url: https://opentelemetry.io/docs/collector/ + description: The signal station every component reports spans to; it forwards them on to Jaeger. Part of the working + tracing setup, here to read, not to change. + services: + - name: Backstage + port: 3000 + description: The commission office and your cockpit. Start it with `make backstage`, then commission vessels. Signs in + as a guest, no credentials needed. + - name: Jaeger + port: 30103 + description: "The navigation log: each commission's distributed trace, across Backstage, Argo Workflows, and Argo CD. No + sign-in required." + - name: Gitea + port: 30112 + credentials: admin / a-super-secure-password + description: "The archives: each vessel's code and deployment repositories and the container registry." + - name: Argo Workflows + port: 30113 + description: "The shipyard: the delivery workflow runs, step by step, with per-step logs. No sign-in required." + - name: Argo CD + port: 30100 + credentials: readonly / a-super-secure-password + description: "The harbor master: each vessel's Application, sync status, and health." + how_to_play: + - id: start + title: Open the Commission Office + content: > + Start Backstage with `make backstage`. The first run compiles for ~30-60s; once it's up, the commission + + office is available in your browser on port 3000. Leave it running in that terminal; restart any time with + + Ctrl-C then `make backstage`. + + + The rest of the platform (Gitea, Argo Events, Argo Workflows, Argo CD, the OpenTelemetry Collector, and + Jaeger) + + is already running in the cluster. + - id: explore + title: Sail a Commission and Read the Log + content: | + In Backstage, go to **Create** and run the **Commission a Vessel** template. Pick a cargo you'll remember (say + **Citrus**), and let the vessel sail. Delivery still works, but the records don't add up. You have two + instruments to check what really happened: + + - **Greet the vessel.** Once it's running, `make ahoi` reports the cargo it's actually carrying. + Is it what you ordered? + - **Open the log.** In **Jaeger** (port 30103), search service `backstage`, operation `commission `, + and open the trace. Read it from the commission office outward: how much of the voyage actually reached the + log? + + The trace is your instrument for both. It carries the cargo along the voyage (`provisions.ordered` -> + `provisions.declared` -> `provisions.reported`), so once the log reads true end to end, Jaeger is where you + follow the cargo from order to arrival and find where it goes astray. + - id: fix + title: Repair the Log, Then the Cargo + content: | + Both repairs live in the vessel commissioning template: + + ```text + backstage/templates/vessel-commissioning-template/ + ``` + + Start with the log. Read how a commission carries its trace context out to the pipeline, and how the pipeline + picks it back up off the push it reacts to; the two need to line up on the same commit. With the voyage whole, + the trace shows the cargo at each checkpoint (`provisions.ordered` -> `provisions.declared` -> + `provisions.reported`): follow it and let it tell you which stage the cargo survives and which one it doesn't. + + Test a fix by commissioning a fresh vessel and watching it sail. If you edited `template.yaml`, reload it into + Backstage first so the next commission picks up your change: + + ```bash + make reload-template + ``` + verification: + command: make verify + description: "Grades the most recently commissioned vessel against the two end-states: its commission is one connected + trace in Jaeger, and the running vessel reports the cargo its deployment declares. Each check reports on its + own, so you see which half of the log still reads false." + helpful_links: + - title: W3C Trace Context + url: https://www.w3.org/TR/trace-context/ + description: The traceparent format that carries a trace across service boundaries + - title: "OpenTelemetry: Context Propagation" + url: https://opentelemetry.io/docs/concepts/context-propagation/ + description: How spans in different processes are stitched into one trace by passing context between them + - title: "OpenTelemetry: Traces" + url: https://opentelemetry.io/docs/concepts/signals/traces/ + description: What a trace and its spans are, and why they capture causal, data-carrying detail logs don't + - title: "Jaeger: Documentation" + url: https://www.jaegertracing.io/docs/latest/ + description: Searching for and reading distributed traces across services + - title: "Backstage: Software Templates" + url: https://backstage.io/docs/features/software-templates/ + description: How a scaffolder template runs its steps and passes values between them + codespaces_machine: 4core + deadline: 2026-07-28T23:59:00+01:00 + architecture_diagram: dead-reckoning-expert.svg diff --git a/src/data/adventures/dead-reckoning/expert-posts.json b/src/data/adventures/dead-reckoning/expert-posts.json new file mode 100644 index 000000000..bacedaacf --- /dev/null +++ b/src/data/adventures/dead-reckoning/expert-posts.json @@ -0,0 +1,5 @@ +{ + "discussionUrl": "", + "discussionPosts": [], + "totalReplies": 0 +} diff --git a/src/data/adventures/summaries.ts b/src/data/adventures/summaries.ts index dc4a9a94b..207734e60 100644 --- a/src/data/adventures/summaries.ts +++ b/src/data/adventures/summaries.ts @@ -41,6 +41,17 @@ export const ADVENTURE_SUMMARIES: AdventureCardSummary[] = [ "How to trace a silent failure across tools from each one's logs and UI", ], }, + { + id: "expert", + name: "The Chronometer", + difficulty: "Expert", + topics: ["Backstage", "Argo Workflows", "Argo CD", "OpenTelemetry", "Jaeger"], + learnings: [ + "How trace context crosses an asynchronous boundary with no call chain: a commission carries its W3C traceparent to a push-triggered pipeline, so its spans continue the same trace instead of starting a new one", + "Why a distributed trace reveals what per-tool logs cannot: the value that flowed through each step, so a fault surfaces where the data diverges", + "How to read that trace in Jaeger to localise a fault to a single service by following one attribute across the whole voyage", + ], + }, ], }, { diff --git a/src/test/prerender.test.ts b/src/test/prerender.test.ts index 716566242..fdbeedac2 100644 --- a/src/test/prerender.test.ts +++ b/src/test/prerender.test.ts @@ -71,6 +71,10 @@ const pages: PageSpec[] = [ file: "adventures/dead-reckoning/levels/intermediate/index.html", check: { type: "contains", value: "Sea Trial" }, }, + { + file: "adventures/dead-reckoning/levels/expert/index.html", + check: { type: "contains", value: "The Chronometer" }, + }, { file: "adventures/lex-imperfecta/index.html", check: { type: "contains", value: "Lex Imperfecta" }, diff --git a/src/test/seo.test.ts b/src/test/seo.test.ts index 8f40c3669..cf5c2c038 100644 --- a/src/test/seo.test.ts +++ b/src/test/seo.test.ts @@ -23,6 +23,7 @@ const ROUTES = [ "/adventures/dead-reckoning", "/adventures/dead-reckoning/levels/beginner", "/adventures/dead-reckoning/levels/intermediate", + "/adventures/dead-reckoning/levels/expert", "/adventures/lex-imperfecta", "/adventures/lex-imperfecta/levels/beginner", "/adventures/lex-imperfecta/levels/intermediate",