From 746ea2ce41df95e6a5351d1d4f78d544a118b5d3 Mon Sep 17 00:00:00 2001 From: Cervator Date: Tue, 14 Jul 2026 14:41:39 -0400 Subject: [PATCH] feat(examples): DevEx team + portal dogfood, demo visir, practice retype, local TechDocs MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Post-merge demo hardening, born from the first real demo attempt (which died on Node versions and then had no tour to follow). The demo visir moves into the repo proper as docs/demo-visir.md — the Guildhall grand tour: setup (with the Node 22/24 gotcha called out), verify checklist, timed click-path, honesty lines, fallbacks, Q&A. It attaches to the catalog through a new DevEx slice of Ravenline: team-devex (+ Freya) owns guildhall-portal, a Component representing this very Backstage instance — the seed's one non-fiction entity — whose visir annotation and entity links point at the tour. New users find the tour from inside the thing it tours. The practice Component is retyped per Cervator's steer: spec.type practice (a clear noun in Component-type position), entity renamed security-practice. Its entity links now jump straight to the standard, the paved-road template, and the remediation docs — the practice -> standard -> trials tie was previously invisible from the UI (file-only), which made demo surfing frustrating. The gildi Group gets matching links. The scorecard engine later turns this navigational tie into live data. TechDocs, fully local: both mock repos gain mkdocs.yml + index pages, and their Components carry backstage.io/techdocs-ref dir refs — no Git provider involved (answering the live-site question: not needed). Operational visar nest as docs/runbooks/ for now so plain TechDocs renders them — an interim convention noted in the design doc section 3.5, the seed README, and both index pages — until the parameterized runbooks plugin restores the top-level /runbooks home. smoke-catalog grows two checks (portal ingested with type portal, ownedBy team-devex): 19 checks, all passing. Full ws test gate green. Co-Authored-By: Claude Fable 5 --- docs/demo-visir.md | 75 +++++++++++++++++++ ...26-07-10-guilds-skills-standards-design.md | 2 +- examples/mock-org/README.md | 13 +++- .../standards/release-readiness.yaml | 2 +- examples/mock-org/org.yaml | 21 +++++- .../repos/security-practice/docs/index.md | 10 +++ .../runbooks/rotate-leaked-credential.md | 0 .../repos/security-practice/mkdocs.yml | 12 +++ .../repos/security-practice/standard.yaml | 4 +- .../mock-org/repos/tracking-api/docs/index.md | 10 +++ .../repos/tracking-api/docs/oncall-primer.md | 2 +- .../{ => docs}/runbooks/queue-backlog.md | 0 .../mock-org/repos/tracking-api/mkdocs.yml | 9 +++ examples/mock-org/software.yaml | 46 ++++++++++-- scripts/smoke-catalog.sh | 8 +- 15 files changed, 194 insertions(+), 20 deletions(-) create mode 100644 docs/demo-visir.md create mode 100644 examples/mock-org/repos/security-practice/docs/index.md rename examples/mock-org/repos/security-practice/{ => docs}/runbooks/rotate-leaked-credential.md (100%) create mode 100644 examples/mock-org/repos/security-practice/mkdocs.yml create mode 100644 examples/mock-org/repos/tracking-api/docs/index.md rename examples/mock-org/repos/tracking-api/{ => docs}/runbooks/queue-backlog.md (100%) create mode 100644 examples/mock-org/repos/tracking-api/mkdocs.yml diff --git a/docs/demo-visir.md b/docs/demo-visir.md new file mode 100644 index 0000000..f27cc79 --- /dev/null +++ b/docs/demo-visir.md @@ -0,0 +1,75 @@ +# Vísir: the Guildhall Grand Tour + +*A teaching vísir owned by the DevEx team (`group:default/team-devex` in the Ravenline seed): the guided tour for demos and for introducing new users to this Backstage instance. In the catalog, the `guildhall-portal` Component links here — the tour is discoverable from inside the thing it tours.* + +Say the corporate words out loud ("Practice", "Guild", "Check") and let the screen show the canonical names (aspect, gildi, trial) — narrating that gap *is* the kenning-layer pitch. + +--- + +## Setup (once per machine, ~15 min) + +Prereqs: git, **Node 22 or 24** (check `node --version` — this is the classic demo-day gotcha; the repo's `engines` field rejects anything else), and a browser. `make` is convenient but optional. + +```bash +git clone https://github.com/SiliconSaga/leidangr.git +cd leidangr +corepack enable # once per machine; activates the pinned Yarn +make doctor # env sanity: Node, Corepack, ports (or: node scripts/lib/run-doctor.mjs) +make deps # or: corepack yarn install --immutable +make dev # or: corepack yarn start — stub mode: zero secrets, no cluster +``` + +App: `http://localhost:3000` (backend on 7007). Sign in as **Guest**. First boot takes a minute or two; the seeds ingest ~30s after "Listening on" — if the Kind dropdown lacks Cycle/Saga, wait and refresh. + +**TechDocs (optional but nice):** the mock repos render as real doc sites, fully locally — no Git provider involved. Generation needs either **Docker running** (the scaffold default) or one config flip (`techdocs.generator.runIn: local` in `app-config.yaml`) plus `pip install mkdocs-techdocs-core`. If neither is available on the demo machine, skip it — the entity links cover the same ground. + +**Verify checklist** (run the day before a demo, not the morning of): + +- [ ] Catalog loads; the Kind dropdown includes **Cycle** and **Saga** +- [ ] `ravenline` Group shows the org tree plus two `gildi`-typed Groups +- [ ] `guildhall-portal` Component exists, owned by `team-devex`, linking to this vísir +- [ ] `security-practice` Component (type `practice`) shows its links to the standard and paved road +- [ ] `tracking-2026-2` Cycle shows the curated overview card +- [ ] `make smoke-catalog` passes (your offline proof, and the fallback if the UI misbehaves live) + +## The tour (~15 min as a demo; self-paced for new users) + +**1. The pitch (2 min, no screen).** Three familiar symptoms: focus areas with no org-chart shape ("teams" that aren't teams), production readiness living in tribal knowledge, docs and runbooks conflated. Spotify sells two disconnected products here (Skill Exchange, Soundcheck); the claim is they're two pieces of one thing — a **Practice** — plus a third piece nobody shipped: written procedure. + +**2. Catalog tour (6 min).** + +- *Catalog → Kind dropdown*: **Cycle** and **Saga** next to Component/Group. Talking point: two custom kinds total; the entire practice layer adds **zero** more — typed Groups, vocabularies, annotations, links. +- *`ravenline` Group → relations graph*: the org tree plus two **guilds** (`spec.type: gildi`) cross-cutting it — one practice-aligned (Security), one role-aligned (Release Captains). A guild is deliberately just a typed Group: membership, rollups, and the graph come free. +- *`team-devex` → `guildhall-portal`*: the portal you are standing in is itself cataloged, owned by the DevEx team, and its vísir is this document. Dogfood moment. +- *`security-practice` Component (type `practice`)*: **where the practice lives.** Its links go straight to the standard (tiers of checks), the paved-road pipeline template, and the remediation docs — the practice → standard → checks tie, one click each. +- *`tracking-api` Component*: enrollment annotations (`siliconsaga.org/aspects`) — which practices apply to this service. Description carries the demo narrative: silver. If TechDocs generation is available, open its **Docs tab**: the on-call primer and the queue-backlog runbook render as a real doc site (runbooks nest under docs as an interim convention until the parameterized-runbooks plugin exists — say that out loud, it's a roadmap point). +- *`tracking-2026-2` Cycle*: a release as a first-class bounded effort. Then *`dependency-scanning-drive`*: a time-bound push — Soundcheck sells this as "Campaigns"; here it's a Cycle of type drive. +- *`saga-tracking-2026-2`*: the retrospective as a catalog citizen — authored by a person, linked to everything it touched, body in Git. Open `examples/mock-org/sagas/tracking-2026-2.md` and read two sentences aloud; the May 14th incident sets up the next stop. + +**3. Files tour (4 min).** In an editor, `examples/mock-org/`: + +- `repos/security-practice/`: `standard.yaml` (tiered checks, *each declaring its remediation doc*), `pipeline-templates/dependency-scan.yml` (the paved road: one include line), `docs/` + `runbooks/`. +- The loop, told on `carrier-gateway` (bronze in the narrative): failing check → remediation doc → whose entire instruction is the one-line include → next pipeline run reports facts → check flips green. **When the requirement, the tooling, and the measurement share one owner, the cheapest way to comply is the paved road.** Land this sentence. +- `repos/tracking-api/docs/runbooks/queue-backlog.md`: docs teach, **runbooks are followed under pressure** — parameterized placeholders (`{{cluster}}`) filled at read time so every command copy-pastes exactly right. Born from the incident the Saga describes. + +**4. The kicker (1 min).** Filter Groups again → the **MTL soccer league** in the same instance: seasons are Cycles, season-readiness is a standard measuring a Cycle. The same five primitives running a youth sports league and a software org — the evidence the model is general, not a one-off. + +**5. Close (1 min).** Where an org starts: name 2–3 real practices and stand up their guilds; move one existing scorecard under its practice with remediation links; pilot the parameterized-runbook convention on one service. Advisory before mandatory, always. + +## Honesty lines (quote verbatim if asked) + +- "The **model and catalog are real** — everything you saw ingested is running code with tests." +- "**Check evaluation is not implemented yet** — bronze/silver in descriptions is demo narrative; the standards files are the frozen input for that engine, and the expected results already sit in the repo as its future test fixtures." +- "Display terminology is configurable **by design** (one canonical vocabulary, per-org display terms); the UI shows canonical names today — the display layer is future work." + +## Fallbacks + +- **App won't boot** (wrong Node, port conflict, corporate proxy): `make smoke-catalog` prints the headless ingestion proof — narrate over its output plus the files tour, which alone carries most of the story. +- **No laptop at all**: the design doc (`docs/plans/2026-07-10-guilds-skills-standards-design.md`), ADR 0009, and `examples/mock-org/README.md` (ingests-vs-waits table) make a solid paper demo. + +## Q&A ammo + +- *"Is this Soundcheck?"* — Same measurement bones (facts → checks → tiers → certification, deliberately compatible thinking), but connected to the people side (skills, guilds) and the procedure side (runbooks) that Spotify ships separately or not at all — on open Backstage, with no custom kinds for the practice layer itself. +- *"What would it take to run this in our org?"* — Any Backstage instance: guilds are typed Groups, vocabularies are YAML, standards are Git files, runbooks are repo markdown. The evaluation engine is the only real build (Tech Insights first). +- *"Who maintains a practice?"* — Its guild: a fellowship, not a reporting line. The practice home repo makes stewardship concrete — requirements, paved road, and remediation docs live together with one owner. +- *"How do practices connect to checks and ratings?"* — Practice (aspect) holds the standard; the standard's tiers hold the checks; every check links its remediation. Today that chain is Git files plus entity links; the scorecard engine makes it live data on entity pages. diff --git a/docs/plans/2026-07-10-guilds-skills-standards-design.md b/docs/plans/2026-07-10-guilds-skills-standards-design.md index 5c605e4..95efa74 100644 --- a/docs/plans/2026-07-10-guilds-skills-standards-design.md +++ b/docs/plans/2026-07-10-guilds-skills-standards-design.md @@ -74,7 +74,7 @@ Crafts and aspects are different **axes**, not levels of one hierarchy: a craft One artifact concept, two grades — the separation matters, but both attach with the same flexibility (the annotation's referrer defines the scope: a skill entry, a craft, an aspect, a Component, a facility, a Cycle): - **Teaching vísar** — static explanatory material ("intro to field-lining," the treasurer's season guide). Homed in `/docs`, rendered by TechDocs. -- **Operational vísar** — procedures executed under conditions, often environment-specific ("scoreboard won't boot," the known-outage runbook). Still plenty of instructive text — the difference is capability, not genre: they carry **placeholders for environmental details** filled at read time (e.g. via URL parameters), so the reader can copy-paste completely accurate commands. Homed in `/runbooks` alongside `/docs` in the owning repo, rendered by a dedicated runbooks plugin (a pre-existing plugin concept of Cervator's that slots in here directly). +- **Operational vísar** — procedures executed under conditions, often environment-specific ("scoreboard won't boot," the known-outage runbook). Still plenty of instructive text — the difference is capability, not genre: they carry **placeholders for environmental details** filled at read time (e.g. via URL parameters), so the reader can copy-paste completely accurate commands. Homed in `/runbooks` alongside `/docs` in the owning repo, rendered by a dedicated runbooks plugin (a pre-existing plugin concept of Cervator's that slots in here directly). *Interim, until that plugin exists:* they nest as a `docs/runbooks/` subsection so plain TechDocs renders them; the top-level home returns with the plugin. Whether the two grades deserve distinct *terms* (e.g. **Fræði** — lore — for teaching material, reserving **Vísir** for the dynamic way-shower; or plain "docs" for teaching with Vísir as the only named artifact) is an open question (§8). An open `type` vocabulary (guide / runbook / drill / …) discriminates further, in the house style of `Cycle.spec.type`, without minting new kinds of thing per scope. diff --git a/examples/mock-org/README.md b/examples/mock-org/README.md index d795934..e96d822 100644 --- a/examples/mock-org/README.md +++ b/examples/mock-org/README.md @@ -4,11 +4,12 @@ Ravenline is a fictional small parcel-logistics SaaS (~20 people) used as the ru ## The cast -- **Org tree** (`org.yaml`): `ravenline` (organization) → `rl-engineering` (department) → `team-tracking`, `team-shipping`, `team-platform`. Six users spread across them. +- **Org tree** (`org.yaml`): `ravenline` (organization) → `rl-engineering` (department) → `team-tracking`, `team-shipping`, `team-platform`, `team-devex`. Seven users spread across them. - **Two gildi** (`org.yaml`), one of each form from the design: - `security-gildi` — **aspect-aligned** (stewards the `security` aspect). Members: Astrid, Leif. - `release-captains-gildi` — **craft-aligned** (stewards the `release-captain` craft). Members: Bjorn, Runa. -- **Software graph** (`software.yaml`): systems `parcel-tracking` and `shipping`, components `tracking-api`, `tracking-web`, `shipping-orchestrator`, `carrier-gateway`, the `prod-cluster` Resource, and `security-practice-home` — the practice home repo modeled as a Component owned by the security gildi. +- **Software graph** (`software.yaml`): systems `parcel-tracking` and `shipping`, components `tracking-api`, `tracking-web`, `shipping-orchestrator`, `carrier-gateway`, the `prod-cluster` Resource, and `security-practice` — the practice as a catalog citizen (`spec.type: practice`), owned by the security gildi, whose entity **links** point straight at its standard, paved road, and remediation docs. +- **The portal itself** (`software.yaml`): `guildhall-portal`, owned by `team-devex` — the one **non-fiction** entity in the seed: it is this very Backstage instance, and its vísir is the demo/onboarding grand tour (`docs/demo-visir.md`, at the repo root — start there). - **Cycles + Saga** (`cycles.yaml`): a `release` Cycle (`tracking-2026-2`), a `drive` Cycle (`dependency-scanning-drive` — the Soundcheck-Campaign analog), and a Saga narrated by Runa about the release (`sagas/tracking-2026-2.md`). ## The story the data tells @@ -23,8 +24,10 @@ The `guildhall/` and `repos/` trees are **plain YAML/markdown, deliberately not - `guildhall/crafts.yaml` — `release-captain` (skills + a teaching vísir) and `incident-commander` (skills only — vísar are optional). - `guildhall/aspects.yaml` — `security` (steward gildi + home repo + standard) and `operational-readiness` (**no steward** — an aspect can exist before a gildi forms around it). - `guildhall/standards/release-readiness.yaml` — a standard that measures **Cycles**, the software twin of the community "season-readiness" checklist. -- `repos/security-practice/` — the **practice home repo**: the security standard (tiered trials, each with its own remediation ref), the paved road (`pipeline-templates/dependency-scan.yml`), teaching vísar (`docs/`), and a parameterized operational vísir (`runbooks/`). -- `repos/tracking-api/` — a product repo showing the `/docs` + `/runbooks` convention: a static on-call primer and a parameterized queue-backlog runbook. +- `repos/security-practice/` — the **practice home repo**: the security standard (tiered trials, each with its own remediation ref), the paved road (`pipeline-templates/dependency-scan.yml`), teaching vísar (`docs/`), and a parameterized operational vísir (`docs/runbooks/`). +- `repos/tracking-api/` — a product repo with a static on-call primer and a parameterized queue-backlog runbook. + +**TechDocs, fully local:** both repos carry `mkdocs.yml` and their Components carry `backstage.io/techdocs-ref: dir:…` — TechDocs renders them with **no Git provider involved** (dir refs resolve relative to this file-based seed). Generation needs either Docker running (the scaffold default) or `techdocs.generator.runIn: local` + `pip install mkdocs-techdocs-core`. *Interim convention:* operational vísar sit at `docs/runbooks/` so TechDocs renders them today; the design's top-level `/runbooks` home returns when the dedicated runbooks plugin (URL-parameterized rendering) exists. ## What ingests, what waits @@ -34,4 +37,6 @@ The `guildhall/` and `repos/` trees are **plain YAML/markdown, deliberately not | Software graph, enrollment + vísir annotations (inert but present) | Standards evaluation / scorecards (Tech Insights or custom) | | `Cycle` (release + drive) and `Saga` with relations | Runbooks plugin (parameterized vísar) | +Until the scorecard engine exists, the **practice → standard → trials tie is navigational**: the `security-practice` Component's and `security-gildi` Group's entity links jump straight to the standard, the paved-road template, and the remediation docs. The scorecard plugin later turns that chain into live data on entity pages. + `make smoke-catalog` asserts the mock org ingests at runtime alongside the MTL seed (gildi Group typed, release Cycle with its relations, the Saga touching it). diff --git a/examples/mock-org/guildhall/standards/release-readiness.yaml b/examples/mock-org/guildhall/standards/release-readiness.yaml index a9e39da..9877771 100644 --- a/examples/mock-org/guildhall/standards/release-readiness.yaml +++ b/examples/mock-org/guildhall/standards/release-readiness.yaml @@ -17,7 +17,7 @@ standard: - id: rollback-runbook-linked rule: every Component in the Cycle's system links an operational vísir factSource: catalog-annotations - remediation: ../../repos/tracking-api/runbooks/queue-backlog.md # exemplar + remediation: ../../repos/tracking-api/docs/runbooks/queue-backlog.md # exemplar - id: previous-cycle-saga-exists rule: the previous release Cycle has at least one Saga factSource: catalog diff --git a/examples/mock-org/org.yaml b/examples/mock-org/org.yaml index 825f454..6e978dd 100644 --- a/examples/mock-org/org.yaml +++ b/examples/mock-org/org.yaml @@ -13,7 +13,7 @@ spec: apiVersion: backstage.io/v1alpha1 kind: Group metadata: { name: rl-engineering } -spec: { type: department, parent: ravenline, children: [team-tracking, team-shipping, team-platform] } +spec: { type: department, parent: ravenline, children: [team-tracking, team-shipping, team-platform, team-devex] } --- apiVersion: backstage.io/v1alpha1 kind: Group @@ -30,6 +30,15 @@ kind: Group metadata: { name: team-platform } spec: { type: team, parent: rl-engineering, children: [] } --- +# DevEx — the team that runs the portal itself. Owns guildhall-portal (see +# software.yaml) and stewards the demo/onboarding vísir new users start from. +apiVersion: backstage.io/v1alpha1 +kind: Group +metadata: + name: team-devex + description: 'Developer experience — maintains this Backstage instance and onboards its users' +spec: { type: team, parent: rl-engineering, children: [] } +--- # Gildi — the Guildhall's fellowship concept (design §3.2/§5): plain # typed Groups, cross-cutting the team tree. What a gildi stewards is an # annotation, not a new relation type. @@ -40,6 +49,11 @@ metadata: description: The Security guild — stewards the security aspect (aspect-aligned gildi) annotations: siliconsaga.org/stewards: 'aspect:security' + links: # the aspect→standard tie, one click from the guild's page + - url: https://github.com/SiliconSaga/leidangr/blob/main/examples/mock-org/repos/security-practice/standard.yaml + title: Security standard (trials in tiers) + - url: https://github.com/SiliconSaga/leidangr/blob/main/examples/mock-org/repos/security-practice/pipeline-templates/dependency-scan.yml + title: Paved road — dependency-scan pipeline template spec: type: gildi parent: ravenline @@ -88,3 +102,8 @@ apiVersion: backstage.io/v1alpha1 kind: User metadata: { name: egil, description: 'Platform engineer' } spec: { memberOf: [team-platform] } +--- +apiVersion: backstage.io/v1alpha1 +kind: User +metadata: { name: freya, description: 'DevEx engineer — runs the portal, gives the tours' } +spec: { memberOf: [team-devex] } diff --git a/examples/mock-org/repos/security-practice/docs/index.md b/examples/mock-org/repos/security-practice/docs/index.md new file mode 100644 index 0000000..6a9a740 --- /dev/null +++ b/examples/mock-org/repos/security-practice/docs/index.md @@ -0,0 +1,10 @@ +# The Security Practice + +Welcome to the Security practice's home. Everything the practice holds lives in this one repo, with one steward (the Security guild): + +- **The standard** — [`standard.yaml`](https://github.com/SiliconSaga/leidangr/blob/main/examples/mock-org/repos/security-practice/standard.yaml): the checks, in tiers (bronze/silver/gold), each linking its remediation page here. +- **The paved road** — [`pipeline-templates/dependency-scan.yml`](https://github.com/SiliconSaga/leidangr/blob/main/examples/mock-org/repos/security-practice/pipeline-templates/dependency-scan.yml): adopt it with a one-line include, and the dependency-scanning check satisfies itself. +- **Remediation guides** — one per check (see the nav): each failing check on your scorecard links straight to the fix. +- **Runbooks** — operational vísar followed under pressure. *Interim note:* these render here as a docs subsection until the dedicated runbooks plugin (parameterized placeholders filled via URL) exists; the top-level `/runbooks` convention returns with it. + +Questions → `#security-gildi`. If your service isn't enrolled yet, add `security` to its `siliconsaga.org/aspects` annotation and start at bronze. diff --git a/examples/mock-org/repos/security-practice/runbooks/rotate-leaked-credential.md b/examples/mock-org/repos/security-practice/docs/runbooks/rotate-leaked-credential.md similarity index 100% rename from examples/mock-org/repos/security-practice/runbooks/rotate-leaked-credential.md rename to examples/mock-org/repos/security-practice/docs/runbooks/rotate-leaked-credential.md diff --git a/examples/mock-org/repos/security-practice/mkdocs.yml b/examples/mock-org/repos/security-practice/mkdocs.yml new file mode 100644 index 0000000..02d16dd --- /dev/null +++ b/examples/mock-org/repos/security-practice/mkdocs.yml @@ -0,0 +1,12 @@ +site_name: Security Practice +site_description: The Security practice's standard, paved road, and vísar — TechDocs-rendered. +nav: + - Overview: index.md + - Remediation: + - Dependency scanning: dependency-scanning.md + - Security contact: security-contact.md + - Threat modeling: threat-modeling.md + - Runbooks: + - Rotate a leaked credential: runbooks/rotate-leaked-credential.md +plugins: + - techdocs-core diff --git a/examples/mock-org/repos/security-practice/standard.yaml b/examples/mock-org/repos/security-practice/standard.yaml index 93429ad..cb48da0 100644 --- a/examples/mock-org/repos/security-practice/standard.yaml +++ b/examples/mock-org/repos/security-practice/standard.yaml @@ -18,7 +18,7 @@ standard: - id: no-secrets-in-repo rule: secret scanning reports zero findings factSource: ci-pipeline-results - remediation: ./runbooks/rotate-leaked-credential.md + remediation: ./docs/runbooks/rotate-leaked-credential.md - name: silver trials: - id: no-critical-vulns-30d @@ -33,5 +33,5 @@ standard: trials: - id: threat-model-current rule: a threat model is on file and reviewed within the last year - factSource: practice-home-repo + factSource: practice-repo remediation: ./docs/threat-modeling.md diff --git a/examples/mock-org/repos/tracking-api/docs/index.md b/examples/mock-org/repos/tracking-api/docs/index.md new file mode 100644 index 0000000..a65f3cd --- /dev/null +++ b/examples/mock-org/repos/tracking-api/docs/index.md @@ -0,0 +1,10 @@ +# tracking-api + +Ingests carrier webhook events onto the `parcel-events` queue and serves tracking queries for the parcel-tracking product. + +- New to the rotation? Start with the [on-call primer](oncall-primer.md) — it explains the system; the runbooks are what you follow at 3am. +- Paged right now? Go straight to [queue backlog](runbooks/queue-backlog.md), the thing that actually pages. + +*Interim note:* runbooks render here as a docs subsection until the dedicated runbooks plugin (parameterized placeholders filled via URL) exists; the top-level `/runbooks` convention returns with it. + +Security posture: enrolled in the Security practice's standard (silver — demo narrative). Owner: team-tracking. diff --git a/examples/mock-org/repos/tracking-api/docs/oncall-primer.md b/examples/mock-org/repos/tracking-api/docs/oncall-primer.md index 9880ece..01f3f43 100644 --- a/examples/mock-org/repos/tracking-api/docs/oncall-primer.md +++ b/examples/mock-org/repos/tracking-api/docs/oncall-primer.md @@ -2,4 +2,4 @@ *Teaching vísir (static, docs-homed): read before your first rotation — this explains the system; the runbooks next door are what you follow at 3am.* -tracking-api ingests carrier webhook events onto the `parcel-events` queue and serves tracking queries. The two things that actually page: **queue backlog** (consumer lag — see `../runbooks/queue-backlog.md`) and **carrier webhook auth failures** (usually a carrier rotated a signing key). Dashboards live on the component's Backstage page; the lag alert pages at 20 minutes of sustained growth (tightened after the May 2026 incident — see the 2026.2 Saga). +tracking-api ingests carrier webhook events onto the `parcel-events` queue and serves tracking queries. The two things that actually page: **queue backlog** (consumer lag — see [the runbook](runbooks/queue-backlog.md)) and **carrier webhook auth failures** (usually a carrier rotated a signing key). Dashboards live on the component's Backstage page; the lag alert pages at 20 minutes of sustained growth (tightened after the May 2026 incident — see the 2026.2 Saga). diff --git a/examples/mock-org/repos/tracking-api/runbooks/queue-backlog.md b/examples/mock-org/repos/tracking-api/docs/runbooks/queue-backlog.md similarity index 100% rename from examples/mock-org/repos/tracking-api/runbooks/queue-backlog.md rename to examples/mock-org/repos/tracking-api/docs/runbooks/queue-backlog.md diff --git a/examples/mock-org/repos/tracking-api/mkdocs.yml b/examples/mock-org/repos/tracking-api/mkdocs.yml new file mode 100644 index 0000000..c471c06 --- /dev/null +++ b/examples/mock-org/repos/tracking-api/mkdocs.yml @@ -0,0 +1,9 @@ +site_name: tracking-api +site_description: Tracking event ingest + query API — docs and runbooks, TechDocs-rendered. +nav: + - Overview: index.md + - On-call primer: oncall-primer.md + - Runbooks: + - Queue backlog: runbooks/queue-backlog.md +plugins: + - techdocs-core diff --git a/examples/mock-org/software.yaml b/examples/mock-org/software.yaml index 49f1c2b..3d9761c 100644 --- a/examples/mock-org/software.yaml +++ b/examples/mock-org/software.yaml @@ -19,7 +19,8 @@ metadata: description: 'Tracking event ingest + query API. Security standard: silver.' annotations: siliconsaga.org/aspects: 'security, operational-readiness' - siliconsaga.org/visir: './repos/tracking-api/runbooks/queue-backlog.md' + siliconsaga.org/visir: './repos/tracking-api/docs/runbooks/queue-backlog.md' + backstage.io/techdocs-ref: dir:./repos/tracking-api spec: { type: service, lifecycle: production, owner: group:default/team-tracking, system: parcel-tracking } --- apiVersion: backstage.io/v1alpha1 @@ -60,14 +61,43 @@ kind: Resource metadata: { name: prod-cluster, description: Production Kubernetes cluster } spec: { type: cluster, owner: group:default/team-platform, system: rl-platform } --- -# The practice home repo (design §3.4 paved-road loop), modeled as a Component -# owned by the gildi: the standard, the paved road, and the remediation vísar -# live together — see repos/security-practice/. +# The practice, as a catalog citizen (design §3.4 paved-road loop): a Component +# of type `practice`, owned by the steward gildi. Its home repo holds the +# standard, the paved road, and the remediation vísar together — and the links +# below ARE the practice→standard→trials tie, one click from the entity page. apiVersion: backstage.io/v1alpha1 kind: Component metadata: - name: security-practice-home - description: 'Security practice home: standard + pipeline templates + remediation vísar' + name: security-practice + description: 'The Security practice: its standard, paved road, and remediation vísar' annotations: - siliconsaga.org/visir: './repos/security-practice/runbooks/rotate-leaked-credential.md' -spec: { type: practice-home, lifecycle: production, owner: group:default/security-gildi, system: rl-platform } + siliconsaga.org/aspect: 'security' + siliconsaga.org/visir: './repos/security-practice/docs/runbooks/rotate-leaked-credential.md' + backstage.io/techdocs-ref: dir:./repos/security-practice + links: + - url: https://github.com/SiliconSaga/leidangr/blob/main/examples/mock-org/repos/security-practice/standard.yaml + title: Security standard — trials in tiers (bronze/silver/gold) + - url: https://github.com/SiliconSaga/leidangr/blob/main/examples/mock-org/repos/security-practice/pipeline-templates/dependency-scan.yml + title: Paved road — dependency-scan pipeline template + - url: https://github.com/SiliconSaga/leidangr/blob/main/examples/mock-org/repos/security-practice/docs/dependency-scanning.md + title: Remediation — dependency scanning + - url: https://github.com/SiliconSaga/leidangr/blob/main/examples/mock-org/repos/security-practice/docs/runbooks/rotate-leaked-credential.md + title: Runbook — rotate a leaked credential +spec: { type: practice, lifecycle: production, owner: group:default/security-gildi, system: rl-platform } +--- +# The portal itself, cataloged — the one NON-fiction entity in the Ravenline +# seed: this is the Backstage instance you are browsing, owned by the DevEx +# team, and its vísir is the demo/onboarding grand tour. +apiVersion: backstage.io/v1alpha1 +kind: Component +metadata: + name: guildhall-portal + description: 'This Backstage instance — the Guildhall portal (yes, the one you are looking at)' + annotations: + siliconsaga.org/visir: '../../docs/demo-visir.md' + links: + - url: https://github.com/SiliconSaga/leidangr/blob/main/docs/demo-visir.md + title: Grand tour vísir (start here) + - url: https://github.com/SiliconSaga/leidangr/blob/main/docs/plans/2026-07-10-guilds-skills-standards-design.md + title: Guildhall design doc +spec: { type: portal, lifecycle: production, owner: group:default/team-devex, system: rl-platform } diff --git a/scripts/smoke-catalog.sh b/scripts/smoke-catalog.sh index 9ed0dec..0103c61 100644 --- a/scripts/smoke-catalog.sh +++ b/scripts/smoke-catalog.sh @@ -63,7 +63,7 @@ byname() { curl -fsS --connect-timeout 3 --max-time 5 "${hdr[@]}" "http://localh # The wall-clock deadline bounds the worst case: six lookups per iteration could # each burn their 5s curl timeout when the catalog is wedged, so iteration count # alone is not a real bound. -CYCLE='{}'; SAGA='{}'; GROUP='{}'; RLCYCLE='{}'; RLSAGA='{}'; GILDI='{}' +CYCLE='{}'; SAGA='{}'; GROUP='{}'; RLCYCLE='{}'; RLSAGA='{}'; GILDI='{}'; PORTAL='{}' deadline=$((SECONDS + 300)) for _ in $(seq 1 120); do if (( SECONDS >= deadline )); then break; fi @@ -73,12 +73,14 @@ for _ in $(seq 1 120); do RLCYCLE="$(byname cycle/default/tracking-2026-2)" RLSAGA="$(byname saga/default/saga-tracking-2026-2)" GILDI="$(byname group/default/security-gildi)" + PORTAL="$(byname component/default/guildhall-portal)" if printf '%s' "$CYCLE" | grep -q 'soccer-2026-spring' \ && printf '%s' "$SAGA" | grep -q 'saga-soccer-2026-spring' \ && printf '%s' "$GROUP" | grep -q '"name":"mtl"' \ && printf '%s' "$RLCYCLE" | grep -q 'tracking-2026-2' \ && printf '%s' "$RLSAGA" | grep -q 'saga-tracking-2026-2' \ - && printf '%s' "$GILDI" | grep -q 'security-gildi'; then break; fi + && printf '%s' "$GILDI" | grep -q 'security-gildi' \ + && printf '%s' "$PORTAL" | grep -q 'guildhall-portal'; then break; fi sleep 1 done @@ -116,6 +118,8 @@ check "Ravenline Cycle ingested (release)" "$RLCYCLE" '"type":"release check_rel "Ravenline Cycle partOf parcel-tracking" "$RLCYCLE" partOf system:default/parcel-tracking || pass=0 check_rel "Ravenline Cycle dependsOn prod-cluster" "$RLCYCLE" dependsOn resource:default/prod-cluster || pass=0 check "Gildi Group ingested (type gildi)" "$GILDI" '"type":"gildi"' || pass=0 +check "Portal ingested (type portal)" "$PORTAL" '"type":"portal"' || pass=0 +check_rel "Portal ownedBy team-devex" "$PORTAL" ownedBy group:default/team-devex || pass=0 check "Ravenline Saga ingested" "$RLSAGA" '"kind":"Saga"' || pass=0 check_rel "Ravenline Saga ownedBy skald (runa)" "$RLSAGA" ownedBy user:default/runa || pass=0 check_rel "Ravenline Saga dependsOn its Cycle" "$RLSAGA" dependsOn cycle:default/tracking-2026-2 || pass=0