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