From 69edecd38fc10fbe5bb078af1d628e666088b8ed Mon Sep 17 00:00:00 2001 From: Cervator Date: Fri, 10 Jul 2026 18:12:57 -0400 Subject: [PATCH 1/8] =?UTF-8?q?docs(plans):=20practice-layer=20terminology?= =?UTF-8?q?=20design=20=E2=80=94=20guilds,=20skills,=20standards?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Design doc for the practice layer: the conceptual model and vocabulary relating Skill-Exchange-style skills, crafts (skill bundles a muster calls for), gildi/guilds (the practice hub with people, process, and measurement faces), Soundcheck-style standards with trials, and visir procedure guides — plus how they connect to the shipped Cycle and Saga kinds. Layered per the brainstorm: an abstract, portable model first, then the Backstage mapping (typed Group for gildi, vocabularies for skills and crafts, Git-backed YAML standards via Tech-Insights-first, annotation- referenced visir docs, muster calls deferred to the Phase 4 store). No new custom kinds. A kennings display layer maps the canonical technical terms to per-instance lexicons (norse or plain), which also keeps parent-facing Ting surfaces on Tone-Guide-safe plain language. Grounded in fresh research on Spotify's premium Soundcheck and Skill Exchange plugins (exact upstream vocabulary captured in the doc). Vocabulary lands now — mechanics are Phase 6 (scorecards, profiles) and Phase 4 (calls) work. Co-Authored-By: Claude Fable 5 --- ...26-07-10-guilds-skills-standards-design.md | 186 ++++++++++++++++++ 1 file changed, 186 insertions(+) create mode 100644 docs/plans/2026-07-10-guilds-skills-standards-design.md diff --git a/docs/plans/2026-07-10-guilds-skills-standards-design.md b/docs/plans/2026-07-10-guilds-skills-standards-design.md new file mode 100644 index 0000000..0010594 --- /dev/null +++ b/docs/plans/2026-07-10-guilds-skills-standards-design.md @@ -0,0 +1,186 @@ +# Leiðangr — Guilds, Skills, and Standards: the Practice Layer (Design) + +**Date:** 2026-07-10 +**Status:** Draft +**Scope:** Terminology and conceptual model for the "practice layer" — how skills (Skill-Exchange-style), +crafts, guilds/practices, maturity standards (Soundcheck-style), and procedure guides relate to each +other and to the shipped `Cycle`/`Saga` kinds. Layered deliverable: an abstract model first (portable +beyond Leiðangr), then its concrete Backstage mapping. Vocabulary lands now; mechanics are Phase 6 +(scorecards, skill profiles) and Phase 4 (muster calls) work. +**Related:** `2026-07-06-leidangr-phase3-community-domain-design.md` (two-family model, typed Group +tree), ADR 0007 (`Cycle`), ADR 0008 (`Saga`), the umbrella design +(`realms/.../2026-06-09-leidangr-design.md` §6 Phase 6), and the Backstage DevEx reference doc +(§ Scorecards and Poor Man's Soundcheck). + +--- + +## 1. What This Is + +Two premium Spotify Backstage plugins inspired this layer: **Skill Exchange** (skills attach to user +profiles; opportunities are posted and browsed) and **Soundcheck** (entities are measured against +tiered check-based standards). Spotify ships them as unconnected products. This design's claim is +that they are two faces of one concept — the **practice** (here: the **Gildi**) — and that a third +face, written procedure, completes it. A prior-art data point: an internal grouped-checks system at +Cervator's day job independently grew a "Grid" concept (themed collections of check-blocks — +security, scalability, maintainability) that converges on Soundcheck's "Track"; and a team there +independently subdivided into discipline areas mislabeled "teams" — groping toward the same missing +noun. The noun is the practice/guild, and this doc names the whole family. + +## 2. Research Grounding (exact upstream vocabulary) + +**Soundcheck** (no custom catalog kinds; operates on existing entities): **Fact Collectors** gather +**Facts** → **Checks** (atomic pass/fail/not-applicable, boolean rules over facts) → **Levels** +(strictly ordered groups of checks; a level completes when all its checks pass and all prior levels +are complete) → **Track** ("a long-term health initiative"). Passing a level = **Certification**, +badged bronze/silver/gold. A **Campaign** is a time-bound track with start/target dates and +milestones. Org rollup ("Tech Health") drills compliance % through the standard Group hierarchy. + +**Skill Exchange** (no custom kinds; decorates catalog `User` entities): **Skills** are an +admin-defined YAML vocabulary (name + category). Users tag their **skill profile** under two +buckets: **"I can help with"** and **"I'm learning."** Opportunities are **Gigs**: **Embed** +(short-term staffing, with requested skills), **Mentorship** (offering / seeking), **Hack** +(passion projects). Matching is browse/search, not algorithmic. + +Two direct mappings: the internal **Grid ≈ Soundcheck Track** (a themed measurement initiative an +entity enrolls in), and **Soundcheck Campaign ≈ `Cycle`** — a time-bound, dated push; Leiðangr +already owns that primitive. + +## 3. The Abstract Model (layer 1 — portable) + +### 3.1 The three faces of a practice + +A practice (Security, Safety, Fundraising, Logistics, Coaching…) is one concept with three faces: + +1. **People** — those who profess it: skills cluster under it, mentorship happens inside it. It is + a fellowship. +2. **Process** — the procedures performed in its name, written down so a newcomer can perform them. +3. **Measurement** — the standard it holds *other things* to: tiered checks, certifying at + bronze/silver/gold. + +Skill Exchange ships face 1; Soundcheck ships face 3; runbooks/SOPs are face 2. Unifying them is +the design's core move. + +### 3.2 The concepts + +| Concept | Definition | +|---|---| +| **Skill** | An atomic capability a *person* carries, with a have/learning axis ("can help with" / "learning"). English *skill* is itself Old Norse (*skil*) — it needs no rename. | +| **Craft** | A demand-side bundle of skills (+ its guides): Electrician, HVAC tech; Coach, Treasurer, Field Marshal. What a muster asks for — nobody posts "need carpentry 3, wiring 2"; they post "need an electrician." | +| **Gildi** | The practice hub. Old Norse *gildi* means both **guild** (the fellowship of a craft) and **worth/value** — one word carrying the people face and the measurement face. | +| **Standard** | The gildi's measurement face (the Grid/Track analog): tiered groups of trials applied to an enrolled entity, certifying at bronze/silver/gold. *Standard* means both the banner a muster rallies under and the norm you are held to — the double meaning is the point. | +| **Trial** | The atomic measurement unit (Soundcheck's Check): evaluated against collected facts, yielding pass/fail/not-applicable. | +| **Vísir** | The written procedure handed to a volunteer or operator — the cash-register-at-the-PTA-event sheet. Short for *Leiðarvísir* ("way-shower"), the modern Icelandic word for a guide/manual and the title of Abbot Nikulás's 12th-century pilgrim itinerary; it shares the *leið-* (way) root with *Leiðangr* itself. The enterprise kenning is "runbook." | +| **Cycle**, **Saga** | Already shipped (ADRs 0007/0008). A Cycle *calls for* crafts; a Standard can measure a Cycle (season-readiness); a Saga narrates the outcome. | + +### 3.3 The relations + +- A person **carries** skills (have/learning axis). +- A craft **bundles** skills and **references** vísar (its procedures). +- A gildi **curates** skills (a skill can serve several gildi), **stewards** vísar, and **holds** + one or more standards. +- A standard **measures** entities — apps, teams, facilities, or Cycles — through its tiered trials. +- A cycle **issues calls** for crafts (the muster); people whose skills satisfy a craft answer. +- A saga **narrates** what happened, and may cite certifications attained. + +Crafts and gildi are different **axes**, not levels of one hierarchy: a craft draws skills from +several gildi (HVAC = ductwork + electrical + safety), and a gildi curates skills used by many +crafts. That is why both exist. + +### 3.4 Worked examples + +**DIY:** a person's profile lists skills (wiring, duct-shaping, carpentry). "Electrician" is a +craft bundling wiring + code-knowledge + safety basics. The Safety gildi does not do the wiring — +it holds the standard the finished work is measured against (the inspection: its trials, at +bronze/silver/gold). + +**Season:** the spring season `Cycle` spins up and issues calls for crafts — coach, treasurer, +field marshal. The muster matches volunteers whose skills satisfy them; each volunteer gets the +relevant vísir. The Logistics gildi's "season-readiness" standard measures the Cycle itself +(fields booked? treasurer named? first-aid kit stocked?). When the season ends, a skald may write +the Saga. + +**Software:** identical bones — the Security gildi curates security skills, stewards the +incident-response vísir, and holds the security standard that measures Components at +bronze/silver/gold. This is the umbrella design's Phase 6 "season-readiness scorecards" and the +day-job Grid, expressed once. + +## 4. The Kenning Layer (display terminology) + +Technical identifiers commit to **one canonical vocabulary** (below). The UI never hard-codes those +strings: it renders through a **kennings map** — a configurable lexicon resolving each technical +term to a display term (a *kenning* being the Old Norse device of calling a thing by another name). + +- Ships with two built-in lexicons: **norse** (Gildi, Vísir, Trial, Saga…) and **plain** (Guild, + Guide/Runbook, Check, Report…), selected per instance in app-config. +- A per-user lexicon preference is a **later enhancement** (Backstage user settings can hold it), + not a launch requirement. +- The parent-facing Ting surface pins the **plain** lexicon — satisfying the realm Tone Guide with + zero special-casing. +- A corporate instance can pin its own custom lexicon (Practice, Grid, Check) over the identical + model — same bones, different skin. + +### Canonical vocabulary + +| Canonical (technical) | Norse display | Plain display | Notes | +|---|---|---|---| +| `skill` | Skill | Skill | Already Old Norse. | +| `craft` | Craft | Craft / Role | *Iðn* available as a norse-lexicon skin. | +| `gildi` | Gildi | Guild | The one deliberate ON anchor at the technical layer (mirrors `spec.skald`). | +| `standard` | Standard | Standard / Scorecard | *Merki* (banner/mark) available as a norse skin. | +| `trial` | Trial | Check | *Raun* / *Þraut* available as norse skins. | +| `visir` | Vísir | Guide / Runbook | Full *Leiðarvísir* in prose/docs where flavor has room. | +| `cycle`, `saga` | (as shipped) | (as shipped) | Unchanged. | + +**Reserved future flavor** (named now so later features inherit consistent vocabulary): **Afrek** +(a recognized feat/deed — recognition mechanics, if ever), **Fóstr** (mentorship gig — Norse +fosterage was *the* mentorship institution), **Útboð** (a muster call — the actual term for calling +out the leiðangr levy, and modern Icelandic for a tender/RFP). + +## 5. The Leiðangr Mapping (layer 2 — Backstage mechanics) + +Follows the established discipline: no kind introduced merely to filter; nothing unique lives only +in the Backstage DB; volatile data stays out of the catalog. **This design introduces no new custom +kinds** — `Cycle` and `Saga` remain the only two. + +| Concept | Realization | +|---|---| +| Gildi | **`Group` with `spec.type: gildi`** — joins the typed-Group tree (organization/sport/…/gildi). Membership (`memberOf`), ownership rollups, and the graph come free. Dovetails with the parked CODEOWNERS-virtual-team idea: a gildi is a virtual team that is *supposed* to exist. | +| Skill | A **vocabulary, not entities** (Skill Exchange's exact shape): YAML-defined skill list; a profile decorator attaches selections to `User` entities so search indexes them. Matches the ResourceType-as-vocabulary precedent. | +| Craft | **Vocabulary-first**: a named bundle (skill refs + vísir refs) in the same YAML family. Promotable to something heavier only if matching mechanics demand it — the cheapest commitment while the structure is still finding its shape. | +| Standard + trials | **Git-backed YAML consumed by the scorecard plugin.** Evaluate `@backstage-community/plugin-tech-insights` first (facts/checks/fact-retrievers); fall back to a custom grouped-checks plugin if it constrains (per the DevEx reference doc). Each standard is `ownedBy` its gildi Group; applicability is two-layered per Soundcheck (static catalog filter + enrollment annotation) so broad trials never ambush entities. Results/history are plugin data — rebuildable, like the Saga discipline. | +| Vísir | **Git markdown, TechDocs-rendered**, referenced via `siliconsaga.org/visir` annotations from gildi Groups, crafts, facilities, or Cycles — the same thin-index-over-Git pattern as `saga-doc`. | +| Muster calls | **Not catalog.** Calls are volatile marketplace data → the Phase 4 store (the issue-tracker-as-store contender fits: a call *is* an issue with labels). A call references a Cycle + a craft. Deferred with Phases 4/6. | +| Certifications / badges | Plugin data surfaced on entity pages, bronze/silver/gold. Community-side certifications are **advisory, never gates** (umbrella design §8: trust over gamification). | + +## 6. Deliberate Non-Goals + +- **No matching algorithm.** Browse + moderator matching first (same posture as Skill Exchange and + the umbrella design §5.3). +- **No Afrek/feat mechanics.** Recognition is reserved vocabulary only, gated on the §8 + trust-over-gamification line. +- **No skill levels on people** beyond the have/learning axis. (Bronze/silver/gold rate *things + against standards*, not people. The Rígsþula rank ladder — þræll/karl/jarl — was considered for + tiers and rejected: "thrall" as an unrated tier is exactly the shaming §8 warns against.) +- **No new custom kinds**, no custom relation types — built-ins only, per ADR 0007 precedent. + +## 7. Phasing & Next Steps + +1. **Now:** this doc fixes the vocabulary; fold the settled terms into the planned + `docs/catalog-model.md` reference doc when it is written. +2. **Phase 4:** muster calls ride the marketplace-store decision (§5.1 of the umbrella design), + referencing Cycles + crafts. +3. **Phase 6:** skill profiles + vocabulary, the first gildi Groups, the first standard + (season-readiness, measuring a Cycle), and the kennings map in app-config. Tech Insights + evaluation happens here. +4. **ADR distillation** once mechanics ship (the gildi-as-typed-Group and kennings decisions are + ADR-shaped). + +## 8. Open Questions + +- **Ordered levels vs. unordered blocks** inside a standard: Soundcheck levels are strictly + sequential; the day-job Blocks are thematic groupings. Decide when the scorecard plugin is built + (Tech Insights' model may decide it for us). +- **Where craft definitions live** long-term if matching gets real (vocabulary → entity promotion + path). +- **Kennings scope**: exact config shape, and whether spec *field* names (not just kind/type + display) participate in display mapping. From 66ec0987fd547df7dad7b1bb9452e55fbae70814 Mon Sep 17 00:00:00 2001 From: Cervator Date: Fri, 10 Jul 2026 20:19:19 -0400 Subject: [PATCH 2/8] =?UTF-8?q?docs(plans):=20practice=20layer=20=E2=80=94?= =?UTF-8?q?=20aspects=20first-class,=20gildi=20as=20pure=20fellowship,=20v?= =?UTF-8?q?isir=20grades?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Review feedback from Cervator untangled a conflation in the first draft: the gildi was carrying both the medieval fellowship role (guilds gather around crafts) and the cross-cutting-concern role (Safety applies to many things). This revision splits them. Aspect becomes the first-class cross-cutting concern in the full AOP sense and now holds the standards. Gildi becomes purely the fellowship (craft- or aspect-aligned), which is exactly why it maps to a typed Group. Skills become explicitly unowned shared vocabulary — crafts and aspects reference them, and pointing is not owning. The three-faces framing becomes the anatomy-of-a-practice constellation. Visir gains two grades per Cervator's steer: teaching visar are static material in /docs (TechDocs), while operational visar are parameterized templates in /runbooks rendered by a dedicated runbooks plugin (placeholders for environment details filled via URL parameters — a pre-existing plugin concept that slots in here). Thattr joins the kennings table as the norse skin for aspect. Co-Authored-By: Claude Fable 5 --- ...26-07-10-guilds-skills-standards-design.md | 123 +++++++++++------- 1 file changed, 79 insertions(+), 44 deletions(-) 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 0010594..900365b 100644 --- a/docs/plans/2026-07-10-guilds-skills-standards-design.md +++ b/docs/plans/2026-07-10-guilds-skills-standards-design.md @@ -19,12 +19,13 @@ tree), ADR 0007 (`Cycle`), ADR 0008 (`Saga`), the umbrella design Two premium Spotify Backstage plugins inspired this layer: **Skill Exchange** (skills attach to user profiles; opportunities are posted and browsed) and **Soundcheck** (entities are measured against tiered check-based standards). Spotify ships them as unconnected products. This design's claim is -that they are two faces of one concept — the **practice** (here: the **Gildi**) — and that a third -face, written procedure, completes it. A prior-art data point: an internal grouped-checks system at -Cervator's day job independently grew a "Grid" concept (themed collections of check-blocks — -security, scalability, maintainability) that converges on Soundcheck's "Track"; and a team there -independently subdivided into discipline areas mislabeled "teams" — groping toward the same missing -noun. The noun is the practice/guild, and this doc names the whole family. +that they are two sides of one thing — the **practice** — and that a third side, written procedure, +completes it. A practice is not a single entity but a small constellation of nouns (§3). A +prior-art data point: an internal grouped-checks system at Cervator's day job independently grew a +"Grid" concept (themed collections of check-blocks — security, scalability, maintainability) that +converges on Soundcheck's "Track"; and a team there independently subdivided into discipline areas +mislabeled "teams" — groping toward the same missing noun. The missing noun is the **aspect** (§3), +and this doc names the whole family around it. ## 2. Research Grounding (exact upstream vocabulary) @@ -47,62 +48,89 @@ already owns that primitive. ## 3. The Abstract Model (layer 1 — portable) -### 3.1 The three faces of a practice +### 3.1 The anatomy of a practice -A practice (Security, Safety, Fundraising, Logistics, Coaching…) is one concept with three faces: +A practice (Security, Safety, Fundraising, Logistics, Coaching…) is not one entity — it is a small +constellation: -1. **People** — those who profess it: skills cluster under it, mentorship happens inside it. It is - a fellowship. -2. **Process** — the procedures performed in its name, written down so a newcomer can perform them. -3. **Measurement** — the standard it holds *other things* to: tiered checks, certifying at - bronze/silver/gold. +1. **An Aspect** — the cross-cutting concern itself, the thing *applied to* other entities in the + AOP sense ("the Security aspect applies to component X, at silver"). The aspect holds the + practice's **standards**. +2. **A Gildi** — the fellowship of practitioners who steward it. +3. **Crafts and skills** — its enactment by people. +4. **Vísar** — its written form. -Skill Exchange ships face 1; Soundcheck ships face 3; runbooks/SOPs are face 2. Unifying them is -the design's core move. +Skill Exchange ships the people side; Soundcheck ships the measurement side; runbooks/SOPs are the +written side. Unifying them is the design's core move — and the load-bearing split is: +**crafts are what people do; aspects are what things must uphold.** Wiring the concession stand is +a craft's work; the wiring passing inspection is an aspect's standard. ### 3.2 The concepts | Concept | Definition | |---|---| -| **Skill** | An atomic capability a *person* carries, with a have/learning axis ("can help with" / "learning"). English *skill* is itself Old Norse (*skil*) — it needs no rename. | -| **Craft** | A demand-side bundle of skills (+ its guides): Electrician, HVAC tech; Coach, Treasurer, Field Marshal. What a muster asks for — nobody posts "need carpentry 3, wiring 2"; they post "need an electrician." | -| **Gildi** | The practice hub. Old Norse *gildi* means both **guild** (the fellowship of a craft) and **worth/value** — one word carrying the people face and the measurement face. | -| **Standard** | The gildi's measurement face (the Grid/Track analog): tiered groups of trials applied to an enrolled entity, certifying at bronze/silver/gold. *Standard* means both the banner a muster rallies under and the norm you are held to — the double meaning is the point. | +| **Skill** | An atomic capability a *person* carries, with a have/learning axis ("can help with" / "learning"). **Shared vocabulary owned by no one** — crafts and aspects reference skills; pointing is not owning. English *skill* is itself Old Norse (*skil*) — it needs no rename. | +| **Craft** | A demand-side bundle of skills (+ its vísar) a person can act as: Electrician, HVAC tech; Coach, Treasurer, Field Marshal. What a muster asks for — nobody posts "need carpentry 3, wiring 2"; they post "need an electrician." | +| **Gildi** | The fellowship — **purely people**. A gildi gathers around a craft (the Electricians' gildi — the historic form) or around an aspect (the Safety gildi). Membership, mentorship (fóstr), and stewardship live here, and nothing else does. Old Norse *gildi* means both **guild** and **worth/value**. | +| **Aspect** | The cross-cutting concern: Security, Safety, Scalability, season-readiness. Applied to entities in the AOP sense, and it **holds the standards** that measure them. May be stewarded by a gildi, or by nobody yet. (*Þáttr* — a strand of a rope, and a short tale woven into a saga compilation — is the available norse kenning skin.) | +| **Standard** | An aspect's measurement instrument (the Grid/Track analog): tiered groups of trials applied to an enrolled entity, certifying at bronze/silver/gold. *Standard* means both the banner a muster rallies under and the norm you are held to — the double meaning is the point. | | **Trial** | The atomic measurement unit (Soundcheck's Check): evaluated against collected facts, yielding pass/fail/not-applicable. | -| **Vísir** | The written procedure handed to a volunteer or operator — the cash-register-at-the-PTA-event sheet. Short for *Leiðarvísir* ("way-shower"), the modern Icelandic word for a guide/manual and the title of Abbot Nikulás's 12th-century pilgrim itinerary; it shares the *leið-* (way) root with *Leiðangr* itself. The enterprise kenning is "runbook." | +| **Vísir** | The written procedure handed to a volunteer or operator — the cash-register-at-the-PTA-event sheet. Short for *Leiðarvísir* ("way-shower"), the modern Icelandic word for a guide/manual and the title of Abbot Nikulás's 12th-century pilgrim itinerary; it shares the *leið-* (way) root with *Leiðangr* itself. Comes in two grades (§3.5): **teaching** (static, docs-homed) and **operational** (parameterized, runbooks-homed). The enterprise kenning is "runbook." | | **Cycle**, **Saga** | Already shipped (ADRs 0007/0008). A Cycle *calls for* crafts; a Standard can measure a Cycle (season-readiness); a Saga narrates the outcome. | ### 3.3 The relations - A person **carries** skills (have/learning axis). - A craft **bundles** skills and **references** vísar (its procedures). -- A gildi **curates** skills (a skill can serve several gildi), **stewards** vísar, and **holds** - one or more standards. -- A standard **measures** entities — apps, teams, facilities, or Cycles — through its tiered trials. +- A gildi **gathers** practitioners and **stewards** crafts and/or aspects (and their vísar). +- An aspect **holds** standards; entities **enroll in** (carry) aspects. +- A standard **measures** its enrolled entities — apps, teams, facilities, or Cycles — through its + tiered trials. - A cycle **issues calls** for crafts (the muster); people whose skills satisfy a craft answer. - A saga **narrates** what happened, and may cite certifications attained. +- Skills are **referenced, never owned** — by crafts, aspects, and people's profiles alike. -Crafts and gildi are different **axes**, not levels of one hierarchy: a craft draws skills from -several gildi (HVAC = ductwork + electrical + safety), and a gildi curates skills used by many -crafts. That is why both exist. +Crafts and aspects are different **axes**, not levels of one hierarchy: a craft draws skills from +anywhere (HVAC = ductwork + electrical + safety basics), and an aspect judges entities of any kind. +The gildi is orthogonal to both — it is simply whichever fellowship formed around a craft or an +aspect, which is exactly why it maps to a plain typed `Group` (§5). ### 3.4 Worked examples **DIY:** a person's profile lists skills (wiring, duct-shaping, carpentry). "Electrician" is a -craft bundling wiring + code-knowledge + safety basics. The Safety gildi does not do the wiring — -it holds the standard the finished work is measured against (the inspection: its trials, at -bronze/silver/gold). +craft bundling wiring + code-knowledge + safety basics. An Electricians' gildi — if the community +has enough practitioners to form one — fosters apprentices and keeps the craft's vísar. The Safety +**aspect** does not do the wiring — it holds the standard the finished work is measured against +(the inspection: its trials, at bronze/silver/gold), stewarded by a Safety gildi if one exists. **Season:** the spring season `Cycle` spins up and issues calls for crafts — coach, treasurer, field marshal. The muster matches volunteers whose skills satisfy them; each volunteer gets the -relevant vísir. The Logistics gildi's "season-readiness" standard measures the Cycle itself +relevant vísir. The Logistics **aspect**'s "season-readiness" standard measures the Cycle itself (fields booked? treasurer named? first-aid kit stocked?). When the season ends, a skald may write the Saga. -**Software:** identical bones — the Security gildi curates security skills, stewards the -incident-response vísir, and holds the security standard that measures Components at -bronze/silver/gold. This is the umbrella design's Phase 6 "season-readiness scorecards" and the -day-job Grid, expressed once. +**Software:** identical bones — the Security **aspect** holds the standard that measures +Components at bronze/silver/gold; the Security gildi gathers the practitioners who steward it and +its incident-response vísir. The day-job Grid is an aspect's standard, and the meeting's +mislabeled "sub-teams" are gildi stewarding aspects. This is the umbrella design's Phase 6 +"season-readiness scorecards" and the day-job Grid, expressed once. + +### 3.5 Vísir grades: teaching vs. operational + +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). These are **templates, not static pages**: + they carry placeholders for environmental details filled at read time (e.g. via URL parameters). + 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). + +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. ## 4. The Kenning Layer (display terminology) @@ -126,6 +154,7 @@ term to a display term (a *kenning* being the Old Norse device of calling a thin | `skill` | Skill | Skill | Already Old Norse. | | `craft` | Craft | Craft / Role | *Iðn* available as a norse-lexicon skin. | | `gildi` | Gildi | Guild | The one deliberate ON anchor at the technical layer (mirrors `spec.skald`). | +| `aspect` | Aspect | Practice / Aspect | *Þáttr* (a strand; a tale within a saga) available as a norse skin. | | `standard` | Standard | Standard / Scorecard | *Merki* (banner/mark) available as a norse skin. | | `trial` | Trial | Check | *Raun* / *Þraut* available as norse skins. | | `visir` | Vísir | Guide / Runbook | Full *Leiðarvísir* in prose/docs where flavor has room. | @@ -144,11 +173,13 @@ kinds** — `Cycle` and `Saga` remain the only two. | Concept | Realization | |---|---| -| Gildi | **`Group` with `spec.type: gildi`** — joins the typed-Group tree (organization/sport/…/gildi). Membership (`memberOf`), ownership rollups, and the graph come free. Dovetails with the parked CODEOWNERS-virtual-team idea: a gildi is a virtual team that is *supposed* to exist. | +| Gildi | **`Group` with `spec.type: gildi`** — joins the typed-Group tree (organization/sport/…/gildi). Membership (`memberOf`), ownership rollups, and the graph come free. What the gildi stewards (craft or aspect refs) is a `siliconsaga.org/*` annotation. Dovetails with the parked CODEOWNERS-virtual-team idea: a gildi is a virtual team that is *supposed* to exist. | | Skill | A **vocabulary, not entities** (Skill Exchange's exact shape): YAML-defined skill list; a profile decorator attaches selections to `User` entities so search indexes them. Matches the ResourceType-as-vocabulary precedent. | | Craft | **Vocabulary-first**: a named bundle (skill refs + vísir refs) in the same YAML family. Promotable to something heavier only if matching mechanics demand it — the cheapest commitment while the structure is still finding its shape. | -| Standard + trials | **Git-backed YAML consumed by the scorecard plugin.** Evaluate `@backstage-community/plugin-tech-insights` first (facts/checks/fact-retrievers); fall back to a custom grouped-checks plugin if it constrains (per the DevEx reference doc). Each standard is `ownedBy` its gildi Group; applicability is two-layered per Soundcheck (static catalog filter + enrollment annotation) so broad trials never ambush entities. Results/history are plugin data — rebuildable, like the Saga discipline. | -| Vísir | **Git markdown, TechDocs-rendered**, referenced via `siliconsaga.org/visir` annotations from gildi Groups, crafts, facilities, or Cycles — the same thin-index-over-Git pattern as `saga-doc`. | +| Aspect | **Vocabulary-first**, same YAML family: id, description, standard refs, optional steward-gildi ref. No new kind — an aspect an entity carries is an enrollment annotation on that entity. | +| Standard + trials | **Git-backed YAML consumed by the scorecard plugin.** Evaluate `@backstage-community/plugin-tech-insights` first (facts/checks/fact-retrievers); fall back to a custom grouped-checks plugin if it constrains (per the DevEx reference doc). Each standard declares its **aspect**, plus an `ownerEntityRef` to the steward gildi Group when one exists; applicability is two-layered per Soundcheck (static catalog filter + enrollment annotation) so broad trials never ambush entities. Results/history are plugin data — rebuildable, like the Saga discipline. | +| Vísir (teaching) | **Git markdown in `/docs`, TechDocs-rendered**, referenced via `siliconsaga.org/visir` annotations from gildi Groups, craft/skill vocabulary entries, facilities, or Cycles — the same thin-index-over-Git pattern as `saga-doc`. | +| Vísir (operational) | **Parameterized templates in `/runbooks`** alongside `/docs` in the owning repo, rendered by a dedicated runbooks plugin (placeholders for environmental details filled via URL parameters — the pre-existing plugin concept). Component/aspect-scoped runbooks live with the component they serve. | | Muster calls | **Not catalog.** Calls are volatile marketplace data → the Phase 4 store (the issue-tracker-as-store contender fits: a call *is* an issue with labels). A call references a Cycle + a craft. Deferred with Phases 4/6. | | Certifications / badges | Plugin data surfaced on entity pages, bronze/silver/gold. Community-side certifications are **advisory, never gates** (umbrella design §8: trust over gamification). | @@ -169,18 +200,22 @@ kinds** — `Cycle` and `Saga` remain the only two. `docs/catalog-model.md` reference doc when it is written. 2. **Phase 4:** muster calls ride the marketplace-store decision (§5.1 of the umbrella design), referencing Cycles + crafts. -3. **Phase 6:** skill profiles + vocabulary, the first gildi Groups, the first standard - (season-readiness, measuring a Cycle), and the kennings map in app-config. Tech Insights - evaluation happens here. -4. **ADR distillation** once mechanics ship (the gildi-as-typed-Group and kennings decisions are - ADR-shaped). +3. **Phase 6:** skill profiles + vocabulary, the first gildi Groups and aspects, the first + standard (season-readiness, measuring a Cycle), and the kennings map in app-config. Tech + Insights evaluation happens here. +4. **Runbooks plugin** (operational vísar: `/runbooks` convention + URL-parameter placeholders) is + its own plugin effort — general-purpose Backstage value like `Cycle`, sequenced independently. +5. **ADR distillation** once mechanics ship (the gildi-as-typed-Group, aspect-holds-standards, and + kennings decisions are ADR-shaped). ## 8. Open Questions - **Ordered levels vs. unordered blocks** inside a standard: Soundcheck levels are strictly sequential; the day-job Blocks are thematic groupings. Decide when the scorecard plugin is built (Tech Insights' model may decide it for us). -- **Where craft definitions live** long-term if matching gets real (vocabulary → entity promotion - path). +- **Where craft and aspect definitions live** long-term if matching/enrollment gets real + (vocabulary → entity promotion path). - **Kennings scope**: exact config shape, and whether spec *field* names (not just kind/type display) participate in display mapping. +- **Runbooks plugin shape**: parameter syntax, URL-parameter contract, and how `/runbooks` + coexists with TechDocs (separate renderer vs. TechDocs extension). From 510178381d0f9c47d89891ee76ae13ddf93149da Mon Sep 17 00:00:00 2001 From: Cervator Date: Fri, 10 Jul 2026 21:21:58 -0400 Subject: [PATCH 3/8] =?UTF-8?q?docs(plans):=20practice=20layer=20=E2=80=94?= =?UTF-8?q?=20soft=20wrap,=20aspect=20skin=20+=20visir=20grade=20terms=20n?= =?UTF-8?q?ow=20open=20items?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Mobile-review feedback pass. Reflowed the whole doc to soft wrap (one line per paragraph) so display tools control word wrap instead of the ~100-column hard breaks fighting narrow screens. Thattr is rejected as the aspect kenning skin — it sound-collides with a rude Danish word. The norse skin for aspect is now an explicit open question with live candidates (thradr, hattr, sidr, grein), and a lexicon-review discipline note records the false-friend check as standing practice. The visir grade term split (Fraedi-as-lore vs plain docs vs adjectives only) also moves to open questions rather than being settled prematurely. Also fixed the stale two-sides/third-side counting in section 1 (the constellation has four pieces since the aspect rework) and clarified that operational visar differ from teaching visar by capability (placeholder insertion for copy-paste-accurate commands), not genre. Co-Authored-By: Claude Fable 5 --- ...26-07-10-guilds-skills-standards-design.md | 167 +++++------------- 1 file changed, 44 insertions(+), 123 deletions(-) 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 900365b..eee829c 100644 --- a/docs/plans/2026-07-10-guilds-skills-standards-design.md +++ b/docs/plans/2026-07-10-guilds-skills-standards-design.md @@ -2,68 +2,35 @@ **Date:** 2026-07-10 **Status:** Draft -**Scope:** Terminology and conceptual model for the "practice layer" — how skills (Skill-Exchange-style), -crafts, guilds/practices, maturity standards (Soundcheck-style), and procedure guides relate to each -other and to the shipped `Cycle`/`Saga` kinds. Layered deliverable: an abstract model first (portable -beyond Leiðangr), then its concrete Backstage mapping. Vocabulary lands now; mechanics are Phase 6 -(scorecards, skill profiles) and Phase 4 (muster calls) work. -**Related:** `2026-07-06-leidangr-phase3-community-domain-design.md` (two-family model, typed Group -tree), ADR 0007 (`Cycle`), ADR 0008 (`Saga`), the umbrella design -(`realms/.../2026-06-09-leidangr-design.md` §6 Phase 6), and the Backstage DevEx reference doc -(§ Scorecards and Poor Man's Soundcheck). +**Scope:** Terminology and conceptual model for the "practice layer" — how skills (Skill-Exchange-style), crafts, guilds/practices, maturity standards (Soundcheck-style), and procedure guides relate to each other and to the shipped `Cycle`/`Saga` kinds. Layered deliverable: an abstract model first (portable beyond Leiðangr), then its concrete Backstage mapping. Vocabulary lands now; mechanics are Phase 6 (scorecards, skill profiles) and Phase 4 (muster calls) work. +**Related:** `2026-07-06-leidangr-phase3-community-domain-design.md` (two-family model, typed Group tree), ADR 0007 (`Cycle`), ADR 0008 (`Saga`), the umbrella design (`realms/.../2026-06-09-leidangr-design.md` §6 Phase 6), and the Backstage DevEx reference doc (§ Scorecards and Poor Man's Soundcheck). --- ## 1. What This Is -Two premium Spotify Backstage plugins inspired this layer: **Skill Exchange** (skills attach to user -profiles; opportunities are posted and browsed) and **Soundcheck** (entities are measured against -tiered check-based standards). Spotify ships them as unconnected products. This design's claim is -that they are two sides of one thing — the **practice** — and that a third side, written procedure, -completes it. A practice is not a single entity but a small constellation of nouns (§3). A -prior-art data point: an internal grouped-checks system at Cervator's day job independently grew a -"Grid" concept (themed collections of check-blocks — security, scalability, maintainability) that -converges on Soundcheck's "Track"; and a team there independently subdivided into discipline areas -mislabeled "teams" — groping toward the same missing noun. The missing noun is the **aspect** (§3), -and this doc names the whole family around it. +Two premium Spotify Backstage plugins inspired this layer: **Skill Exchange** (skills attach to user profiles; opportunities are posted and browsed) and **Soundcheck** (entities are measured against tiered check-based standards). Spotify ships them as unconnected products. This design's claim is that they are two pieces of one thing — the **practice** — completed by a third piece Spotify never shipped: written procedure. A practice is not a single entity but a small constellation of nouns (§3). A prior-art data point: an internal grouped-checks system at Cervator's day job independently grew a "Grid" concept (themed collections of check-blocks — security, scalability, maintainability) that converges on Soundcheck's "Track"; and a team there independently subdivided into discipline areas mislabeled "teams" — groping toward the same missing noun. The missing noun is the **aspect** (§3), and this doc names the whole family around it. ## 2. Research Grounding (exact upstream vocabulary) -**Soundcheck** (no custom catalog kinds; operates on existing entities): **Fact Collectors** gather -**Facts** → **Checks** (atomic pass/fail/not-applicable, boolean rules over facts) → **Levels** -(strictly ordered groups of checks; a level completes when all its checks pass and all prior levels -are complete) → **Track** ("a long-term health initiative"). Passing a level = **Certification**, -badged bronze/silver/gold. A **Campaign** is a time-bound track with start/target dates and -milestones. Org rollup ("Tech Health") drills compliance % through the standard Group hierarchy. +**Soundcheck** (no custom catalog kinds; operates on existing entities): **Fact Collectors** gather **Facts** → **Checks** (atomic pass/fail/not-applicable, boolean rules over facts) → **Levels** (strictly ordered groups of checks; a level completes when all its checks pass and all prior levels are complete) → **Track** ("a long-term health initiative"). Passing a level = **Certification**, badged bronze/silver/gold. A **Campaign** is a time-bound track with start/target dates and milestones. Org rollup ("Tech Health") drills compliance % through the standard Group hierarchy. -**Skill Exchange** (no custom kinds; decorates catalog `User` entities): **Skills** are an -admin-defined YAML vocabulary (name + category). Users tag their **skill profile** under two -buckets: **"I can help with"** and **"I'm learning."** Opportunities are **Gigs**: **Embed** -(short-term staffing, with requested skills), **Mentorship** (offering / seeking), **Hack** -(passion projects). Matching is browse/search, not algorithmic. +**Skill Exchange** (no custom kinds; decorates catalog `User` entities): **Skills** are an admin-defined YAML vocabulary (name + category). Users tag their **skill profile** under two buckets: **"I can help with"** and **"I'm learning."** Opportunities are **Gigs**: **Embed** (short-term staffing, with requested skills), **Mentorship** (offering / seeking), **Hack** (passion projects). Matching is browse/search, not algorithmic. -Two direct mappings: the internal **Grid ≈ Soundcheck Track** (a themed measurement initiative an -entity enrolls in), and **Soundcheck Campaign ≈ `Cycle`** — a time-bound, dated push; Leiðangr -already owns that primitive. +Two direct mappings: the internal **Grid ≈ Soundcheck Track** (a themed measurement initiative an entity enrolls in), and **Soundcheck Campaign ≈ `Cycle`** — a time-bound, dated push; Leiðangr already owns that primitive. ## 3. The Abstract Model (layer 1 — portable) ### 3.1 The anatomy of a practice -A practice (Security, Safety, Fundraising, Logistics, Coaching…) is not one entity — it is a small -constellation: +A practice (Security, Safety, Fundraising, Logistics, Coaching…) is not one entity — it is a small constellation: -1. **An Aspect** — the cross-cutting concern itself, the thing *applied to* other entities in the - AOP sense ("the Security aspect applies to component X, at silver"). The aspect holds the - practice's **standards**. +1. **An Aspect** — the cross-cutting concern itself, the thing *applied to* other entities in the AOP sense ("the Security aspect applies to component X, at silver"). The aspect holds the practice's **standards**. 2. **A Gildi** — the fellowship of practitioners who steward it. 3. **Crafts and skills** — its enactment by people. 4. **Vísar** — its written form. -Skill Exchange ships the people side; Soundcheck ships the measurement side; runbooks/SOPs are the -written side. Unifying them is the design's core move — and the load-bearing split is: -**crafts are what people do; aspects are what things must uphold.** Wiring the concession stand is -a craft's work; the wiring passing inspection is an aspect's standard. +Skill Exchange ships the people piece; Soundcheck ships the measurement piece; runbooks/SOPs are the written piece. Unifying them is the design's core move — and the load-bearing split is: **crafts are what people do; aspects are what things must uphold.** Wiring the concession stand is a craft's work; the wiring passing inspection is an aspect's standard. ### 3.2 The concepts @@ -72,10 +39,10 @@ a craft's work; the wiring passing inspection is an aspect's standard. | **Skill** | An atomic capability a *person* carries, with a have/learning axis ("can help with" / "learning"). **Shared vocabulary owned by no one** — crafts and aspects reference skills; pointing is not owning. English *skill* is itself Old Norse (*skil*) — it needs no rename. | | **Craft** | A demand-side bundle of skills (+ its vísar) a person can act as: Electrician, HVAC tech; Coach, Treasurer, Field Marshal. What a muster asks for — nobody posts "need carpentry 3, wiring 2"; they post "need an electrician." | | **Gildi** | The fellowship — **purely people**. A gildi gathers around a craft (the Electricians' gildi — the historic form) or around an aspect (the Safety gildi). Membership, mentorship (fóstr), and stewardship live here, and nothing else does. Old Norse *gildi* means both **guild** and **worth/value**. | -| **Aspect** | The cross-cutting concern: Security, Safety, Scalability, season-readiness. Applied to entities in the AOP sense, and it **holds the standards** that measure them. May be stewarded by a gildi, or by nobody yet. (*Þáttr* — a strand of a rope, and a short tale woven into a saga compilation — is the available norse kenning skin.) | +| **Aspect** | The cross-cutting concern: Security, Safety, Scalability, season-readiness. Applied to entities in the AOP sense, and it **holds the standards** that measure them. May be stewarded by a gildi, or by nobody yet. (Norse kenning skin: open — see §8.) | | **Standard** | An aspect's measurement instrument (the Grid/Track analog): tiered groups of trials applied to an enrolled entity, certifying at bronze/silver/gold. *Standard* means both the banner a muster rallies under and the norm you are held to — the double meaning is the point. | | **Trial** | The atomic measurement unit (Soundcheck's Check): evaluated against collected facts, yielding pass/fail/not-applicable. | -| **Vísir** | The written procedure handed to a volunteer or operator — the cash-register-at-the-PTA-event sheet. Short for *Leiðarvísir* ("way-shower"), the modern Icelandic word for a guide/manual and the title of Abbot Nikulás's 12th-century pilgrim itinerary; it shares the *leið-* (way) root with *Leiðangr* itself. Comes in two grades (§3.5): **teaching** (static, docs-homed) and **operational** (parameterized, runbooks-homed). The enterprise kenning is "runbook." | +| **Vísir** | The written procedure handed to a volunteer or operator — the cash-register-at-the-PTA-event sheet. Short for *Leiðarvísir* ("way-shower"), the modern Icelandic word for a guide/manual and the title of Abbot Nikulás's 12th-century pilgrim itinerary; it shares the *leið-* (way) root with *Leiðangr* itself. Comes in two grades (§3.5): **teaching** (static, docs-homed) and **operational** (parameterized, runbooks-homed); whether the grades get distinct terms is open (§8). The enterprise kenning is "runbook." | | **Cycle**, **Saga** | Already shipped (ADRs 0007/0008). A Cycle *calls for* crafts; a Standard can measure a Cycle (season-readiness); a Saga narrates the outcome. | ### 3.3 The relations @@ -84,68 +51,38 @@ a craft's work; the wiring passing inspection is an aspect's standard. - A craft **bundles** skills and **references** vísar (its procedures). - A gildi **gathers** practitioners and **stewards** crafts and/or aspects (and their vísar). - An aspect **holds** standards; entities **enroll in** (carry) aspects. -- A standard **measures** its enrolled entities — apps, teams, facilities, or Cycles — through its - tiered trials. +- A standard **measures** its enrolled entities — apps, teams, facilities, or Cycles — through its tiered trials. - A cycle **issues calls** for crafts (the muster); people whose skills satisfy a craft answer. - A saga **narrates** what happened, and may cite certifications attained. - Skills are **referenced, never owned** — by crafts, aspects, and people's profiles alike. -Crafts and aspects are different **axes**, not levels of one hierarchy: a craft draws skills from -anywhere (HVAC = ductwork + electrical + safety basics), and an aspect judges entities of any kind. -The gildi is orthogonal to both — it is simply whichever fellowship formed around a craft or an -aspect, which is exactly why it maps to a plain typed `Group` (§5). +Crafts and aspects are different **axes**, not levels of one hierarchy: a craft draws skills from anywhere (HVAC = ductwork + electrical + safety basics), and an aspect judges entities of any kind. The gildi is orthogonal to both — it is simply whichever fellowship formed around a craft or an aspect, which is exactly why it maps to a plain typed `Group` (§5). ### 3.4 Worked examples -**DIY:** a person's profile lists skills (wiring, duct-shaping, carpentry). "Electrician" is a -craft bundling wiring + code-knowledge + safety basics. An Electricians' gildi — if the community -has enough practitioners to form one — fosters apprentices and keeps the craft's vísar. The Safety -**aspect** does not do the wiring — it holds the standard the finished work is measured against -(the inspection: its trials, at bronze/silver/gold), stewarded by a Safety gildi if one exists. +**DIY:** a person's profile lists skills (wiring, duct-shaping, carpentry). "Electrician" is a craft bundling wiring + code-knowledge + safety basics. An Electricians' gildi — if the community has enough practitioners to form one — fosters apprentices and keeps the craft's vísar. The Safety **aspect** does not do the wiring — it holds the standard the finished work is measured against (the inspection: its trials, at bronze/silver/gold), stewarded by a Safety gildi if one exists. -**Season:** the spring season `Cycle` spins up and issues calls for crafts — coach, treasurer, -field marshal. The muster matches volunteers whose skills satisfy them; each volunteer gets the -relevant vísir. The Logistics **aspect**'s "season-readiness" standard measures the Cycle itself -(fields booked? treasurer named? first-aid kit stocked?). When the season ends, a skald may write -the Saga. +**Season:** the spring season `Cycle` spins up and issues calls for crafts — coach, treasurer, field marshal. The muster matches volunteers whose skills satisfy them; each volunteer gets the relevant vísir. The Logistics **aspect**'s "season-readiness" standard measures the Cycle itself (fields booked? treasurer named? first-aid kit stocked?). When the season ends, a skald may write the Saga. -**Software:** identical bones — the Security **aspect** holds the standard that measures -Components at bronze/silver/gold; the Security gildi gathers the practitioners who steward it and -its incident-response vísir. The day-job Grid is an aspect's standard, and the meeting's -mislabeled "sub-teams" are gildi stewarding aspects. This is the umbrella design's Phase 6 -"season-readiness scorecards" and the day-job Grid, expressed once. +**Software:** identical bones — the Security **aspect** holds the standard that measures Components at bronze/silver/gold; the Security gildi gathers the practitioners who steward it and its incident-response vísir. The day-job Grid is an aspect's standard, and the meeting's mislabeled "sub-teams" are gildi stewarding aspects. This is the umbrella design's Phase 6 "season-readiness scorecards" and the day-job Grid, expressed once. ### 3.5 Vísir grades: teaching vs. operational -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): +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). These are **templates, not static pages**: - they carry placeholders for environmental details filled at read time (e.g. via URL parameters). - 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). +- **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). -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. +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. ## 4. The Kenning Layer (display terminology) -Technical identifiers commit to **one canonical vocabulary** (below). The UI never hard-codes those -strings: it renders through a **kennings map** — a configurable lexicon resolving each technical -term to a display term (a *kenning* being the Old Norse device of calling a thing by another name). +Technical identifiers commit to **one canonical vocabulary** (below). The UI never hard-codes those strings: it renders through a **kennings map** — a configurable lexicon resolving each technical term to a display term (a *kenning* being the Old Norse device of calling a thing by another name). -- Ships with two built-in lexicons: **norse** (Gildi, Vísir, Trial, Saga…) and **plain** (Guild, - Guide/Runbook, Check, Report…), selected per instance in app-config. -- A per-user lexicon preference is a **later enhancement** (Backstage user settings can hold it), - not a launch requirement. -- The parent-facing Ting surface pins the **plain** lexicon — satisfying the realm Tone Guide with - zero special-casing. -- A corporate instance can pin its own custom lexicon (Practice, Grid, Check) over the identical - model — same bones, different skin. +- Ships with two built-in lexicons: **norse** (Gildi, Vísir, Trial, Saga…) and **plain** (Guild, Guide/Runbook, Check, Report…), selected per instance in app-config. +- A per-user lexicon preference is a **later enhancement** (Backstage user settings can hold it), not a launch requirement. +- The parent-facing Ting surface pins the **plain** lexicon — satisfying the realm Tone Guide with zero special-casing. +- A corporate instance can pin its own custom lexicon (Practice, Grid, Check) over the identical model — same bones, different skin. ### Canonical vocabulary @@ -154,22 +91,19 @@ term to a display term (a *kenning* being the Old Norse device of calling a thin | `skill` | Skill | Skill | Already Old Norse. | | `craft` | Craft | Craft / Role | *Iðn* available as a norse-lexicon skin. | | `gildi` | Gildi | Guild | The one deliberate ON anchor at the technical layer (mirrors `spec.skald`). | -| `aspect` | Aspect | Practice / Aspect | *Þáttr* (a strand; a tale within a saga) available as a norse skin. | +| `aspect` | Aspect | Practice / Aspect | Norse skin open (§8) — *þáttr* rejected for a Danish false-friend collision. | | `standard` | Standard | Standard / Scorecard | *Merki* (banner/mark) available as a norse skin. | | `trial` | Trial | Check | *Raun* / *Þraut* available as norse skins. | | `visir` | Vísir | Guide / Runbook | Full *Leiðarvísir* in prose/docs where flavor has room. | | `cycle`, `saga` | (as shipped) | (as shipped) | Unchanged. | -**Reserved future flavor** (named now so later features inherit consistent vocabulary): **Afrek** -(a recognized feat/deed — recognition mechanics, if ever), **Fóstr** (mentorship gig — Norse -fosterage was *the* mentorship institution), **Útboð** (a muster call — the actual term for calling -out the leiðangr levy, and modern Icelandic for a tender/RFP). +**Reserved future flavor** (named now so later features inherit consistent vocabulary): **Afrek** (a recognized feat/deed — recognition mechanics, if ever), **Fóstr** (mentorship gig — Norse fosterage was *the* mentorship institution), **Útboð** (a muster call — the actual term for calling out the leiðangr levy, and modern Icelandic for a tender/RFP), **Fræði** (lore — candidate term for teaching-grade vísar, §8). + +**Lexicon review discipline:** kenning candidates get a false-friend check across the languages the community actually speaks — *þáttr* looked perfect (a strand of a rope; a short tale woven into a saga compilation) until its Danish sound-alike disqualified it. ## 5. The Leiðangr Mapping (layer 2 — Backstage mechanics) -Follows the established discipline: no kind introduced merely to filter; nothing unique lives only -in the Backstage DB; volatile data stays out of the catalog. **This design introduces no new custom -kinds** — `Cycle` and `Saga` remain the only two. +Follows the established discipline: no kind introduced merely to filter; nothing unique lives only in the Backstage DB; volatile data stays out of the catalog. **This design introduces no new custom kinds** — `Cycle` and `Saga` remain the only two. | Concept | Realization | |---|---| @@ -185,37 +119,24 @@ kinds** — `Cycle` and `Saga` remain the only two. ## 6. Deliberate Non-Goals -- **No matching algorithm.** Browse + moderator matching first (same posture as Skill Exchange and - the umbrella design §5.3). -- **No Afrek/feat mechanics.** Recognition is reserved vocabulary only, gated on the §8 - trust-over-gamification line. -- **No skill levels on people** beyond the have/learning axis. (Bronze/silver/gold rate *things - against standards*, not people. The Rígsþula rank ladder — þræll/karl/jarl — was considered for - tiers and rejected: "thrall" as an unrated tier is exactly the shaming §8 warns against.) +- **No matching algorithm.** Browse + moderator matching first (same posture as Skill Exchange and the umbrella design §5.3). +- **No Afrek/feat mechanics.** Recognition is reserved vocabulary only, gated on the §8 trust-over-gamification line. +- **No skill levels on people** beyond the have/learning axis. (Bronze/silver/gold rate *things against standards*, not people. The Rígsþula rank ladder — þræll/karl/jarl — was considered for tiers and rejected: "thrall" as an unrated tier is exactly the shaming §8 warns against.) - **No new custom kinds**, no custom relation types — built-ins only, per ADR 0007 precedent. ## 7. Phasing & Next Steps -1. **Now:** this doc fixes the vocabulary; fold the settled terms into the planned - `docs/catalog-model.md` reference doc when it is written. -2. **Phase 4:** muster calls ride the marketplace-store decision (§5.1 of the umbrella design), - referencing Cycles + crafts. -3. **Phase 6:** skill profiles + vocabulary, the first gildi Groups and aspects, the first - standard (season-readiness, measuring a Cycle), and the kennings map in app-config. Tech - Insights evaluation happens here. -4. **Runbooks plugin** (operational vísar: `/runbooks` convention + URL-parameter placeholders) is - its own plugin effort — general-purpose Backstage value like `Cycle`, sequenced independently. -5. **ADR distillation** once mechanics ship (the gildi-as-typed-Group, aspect-holds-standards, and - kennings decisions are ADR-shaped). +1. **Now:** this doc fixes the vocabulary; fold the settled terms into the planned `docs/catalog-model.md` reference doc when it is written. +2. **Phase 4:** muster calls ride the marketplace-store decision (§5.1 of the umbrella design), referencing Cycles + crafts. +3. **Phase 6:** skill profiles + vocabulary, the first gildi Groups and aspects, the first standard (season-readiness, measuring a Cycle), and the kennings map in app-config. Tech Insights evaluation happens here. +4. **Runbooks plugin** (operational vísar: `/runbooks` convention + URL-parameter placeholders) is its own plugin effort — general-purpose Backstage value like `Cycle`, sequenced independently. +5. **ADR distillation** once mechanics ship (the gildi-as-typed-Group, aspect-holds-standards, and kennings decisions are ADR-shaped). ## 8. Open Questions -- **Ordered levels vs. unordered blocks** inside a standard: Soundcheck levels are strictly - sequential; the day-job Blocks are thematic groupings. Decide when the scorecard plugin is built - (Tech Insights' model may decide it for us). -- **Where craft and aspect definitions live** long-term if matching/enrollment gets real - (vocabulary → entity promotion path). -- **Kennings scope**: exact config shape, and whether spec *field* names (not just kind/type - display) participate in display mapping. -- **Runbooks plugin shape**: parameter syntax, URL-parameter contract, and how `/runbooks` - coexists with TechDocs (separate renderer vs. TechDocs extension). +- **Norse kenning skin for `aspect`**: *þáttr* (strand; tale-within-a-saga) fit best but is rejected — it sound-collides with a rude Danish word. Live candidates: *þráðr* (thread — keeps the woven-through imagery, Danish-safe *tråd*), *háttr* (manner/mode/verse-form — Snorri's *Háttatal* is a catalog of patterns), *siðr* (custom/practice, as in *forn siðr*), *grein* (branch/discipline — most legible). No urgency: `aspect` is canonical and the skin is display-only. +- **Term-splitting the vísir grades**: keep one noun with grade adjectives, adopt **Fræði** (lore) for teaching material with **Vísir** reserved for the dynamic runbook, or leave teaching material as plain "docs." Revisit once the runbooks plugin takes shape. +- **Ordered levels vs. unordered blocks** inside a standard: Soundcheck levels are strictly sequential; the day-job Blocks are thematic groupings. Decide when the scorecard plugin is built (Tech Insights' model may decide it for us). +- **Where craft and aspect definitions live** long-term if matching/enrollment gets real (vocabulary → entity promotion path). +- **Kennings scope**: exact config shape, and whether spec *field* names (not just kind/type display) participate in display mapping. +- **Runbooks plugin shape**: parameter syntax, URL-parameter contract, and how `/runbooks` coexists with TechDocs (separate renderer vs. TechDocs extension). From 853a2c004d9db77ed188322fe74a6bf2685b109d Mon Sep 17 00:00:00 2001 From: Cervator Date: Fri, 10 Jul 2026 22:58:42 -0400 Subject: [PATCH 4/8] =?UTF-8?q?docs(plans):=20practice=20layer=20=E2=80=94?= =?UTF-8?q?=20paved-road=20loop,=20trial-to-remediation=20links,=20practic?= =?UTF-8?q?e=20home=20repo?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Harvested from drafting the day-job presentation intro, which surfaced the first concrete answer to "what does a gildi actually do, and where does it work." New worked example: the paved-road loop. A gildi works out of a practice home repo holding the standard (trials in tiers), the paved road (reusable techniques such as CI pipeline template steps adopted with a one-line include), and the remediation visar every trial links to. Enrolling a Component, following a failing trial's remediation visir, and having the next pipeline run's facts flip the trial green closes the loop with no manual chasing — when the requirement, the tooling, and the measurement share one steward, the cheapest way to comply is the paved road. The community translation (Logistics gildi pre-stocking the first-aid-kit checklist) is included to keep the model dual-domain. Model additions that fell out: aspects ship both the bar and the paved road to clear it, trials declare remediation-visir refs (a failing check is always one click from the fix), and the aspect mapping row gains the practice-home-repo convention. Also swapped one lingering "load-bearing" phrasing per Cervator's wording feedback. Co-Authored-By: Claude Fable 5 --- .../2026-07-10-guilds-skills-standards-design.md | 11 +++++++---- 1 file changed, 7 insertions(+), 4 deletions(-) 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 eee829c..eccba0b 100644 --- a/docs/plans/2026-07-10-guilds-skills-standards-design.md +++ b/docs/plans/2026-07-10-guilds-skills-standards-design.md @@ -30,7 +30,7 @@ A practice (Security, Safety, Fundraising, Logistics, Coaching…) is not one en 3. **Crafts and skills** — its enactment by people. 4. **Vísar** — its written form. -Skill Exchange ships the people piece; Soundcheck ships the measurement piece; runbooks/SOPs are the written piece. Unifying them is the design's core move — and the load-bearing split is: **crafts are what people do; aspects are what things must uphold.** Wiring the concession stand is a craft's work; the wiring passing inspection is an aspect's standard. +Skill Exchange ships the people piece; Soundcheck ships the measurement piece; runbooks/SOPs are the written piece. Unifying them is the design's core move — and the split everything rests on is: **crafts are what people do; aspects are what things must uphold.** Wiring the concession stand is a craft's work; the wiring passing inspection is an aspect's standard. ### 3.2 The concepts @@ -39,7 +39,7 @@ Skill Exchange ships the people piece; Soundcheck ships the measurement piece; r | **Skill** | An atomic capability a *person* carries, with a have/learning axis ("can help with" / "learning"). **Shared vocabulary owned by no one** — crafts and aspects reference skills; pointing is not owning. English *skill* is itself Old Norse (*skil*) — it needs no rename. | | **Craft** | A demand-side bundle of skills (+ its vísar) a person can act as: Electrician, HVAC tech; Coach, Treasurer, Field Marshal. What a muster asks for — nobody posts "need carpentry 3, wiring 2"; they post "need an electrician." | | **Gildi** | The fellowship — **purely people**. A gildi gathers around a craft (the Electricians' gildi — the historic form) or around an aspect (the Safety gildi). Membership, mentorship (fóstr), and stewardship live here, and nothing else does. Old Norse *gildi* means both **guild** and **worth/value**. | -| **Aspect** | The cross-cutting concern: Security, Safety, Scalability, season-readiness. Applied to entities in the AOP sense, and it **holds the standards** that measure them. May be stewarded by a gildi, or by nobody yet. (Norse kenning skin: open — see §8.) | +| **Aspect** | The cross-cutting concern: Security, Safety, Scalability, season-readiness. Applied to entities in the AOP sense, and it **holds the standards** that measure them. A mature aspect ships both **the bar and the paved road to clear it** — reusable techniques (e.g. CI pipeline template steps) whose adoption satisfies its trials (§3.4). May be stewarded by a gildi, or by nobody yet. (Norse kenning skin: open — see §8.) | | **Standard** | An aspect's measurement instrument (the Grid/Track analog): tiered groups of trials applied to an enrolled entity, certifying at bronze/silver/gold. *Standard* means both the banner a muster rallies under and the norm you are held to — the double meaning is the point. | | **Trial** | The atomic measurement unit (Soundcheck's Check): evaluated against collected facts, yielding pass/fail/not-applicable. | | **Vísir** | The written procedure handed to a volunteer or operator — the cash-register-at-the-PTA-event sheet. Short for *Leiðarvísir* ("way-shower"), the modern Icelandic word for a guide/manual and the title of Abbot Nikulás's 12th-century pilgrim itinerary; it shares the *leið-* (way) root with *Leiðangr* itself. Comes in two grades (§3.5): **teaching** (static, docs-homed) and **operational** (parameterized, runbooks-homed); whether the grades get distinct terms is open (§8). The enterprise kenning is "runbook." | @@ -52,6 +52,7 @@ Skill Exchange ships the people piece; Soundcheck ships the measurement piece; r - A gildi **gathers** practitioners and **stewards** crafts and/or aspects (and their vísar). - An aspect **holds** standards; entities **enroll in** (carry) aspects. - A standard **measures** its enrolled entities — apps, teams, facilities, or Cycles — through its tiered trials. +- A trial **links to** the vísir that remediates it — a failing check is always one click from "here is exactly how to fix it." - A cycle **issues calls** for crafts (the muster); people whose skills satisfy a craft answer. - A saga **narrates** what happened, and may cite certifications attained. - Skills are **referenced, never owned** — by crafts, aspects, and people's profiles alike. @@ -66,6 +67,8 @@ Crafts and aspects are different **axes**, not levels of one hierarchy: a craft **Software:** identical bones — the Security **aspect** holds the standard that measures Components at bronze/silver/gold; the Security gildi gathers the practitioners who steward it and its incident-response vísir. The day-job Grid is an aspect's standard, and the meeting's mislabeled "sub-teams" are gildi stewarding aspects. This is the umbrella design's Phase 6 "season-readiness scorecards" and the day-job Grid, expressed once. +**The paved-road loop (what a gildi does, and where):** the Security gildi works out of the practice's home repo, which holds three kinds of things — the **standard** (trials in tiers), the **paved road** (reusable techniques, e.g. CI pipeline template steps any Component can adopt with a one-line include), and the **remediation vísar** every trial links to. A team enrolls a Component, sees bronze with a failing dependency-scanning trial, follows its remediation vísir (whose entire instruction is "add this include line"), and the next pipeline run's collected facts flip the trial green automatically — no audit meeting, no spreadsheet, no chasing. When the requirement, the tooling that satisfies it, and the measurement that verifies it share one steward, the cheapest way to comply *is* the paved road. The community translation holds too: the Logistics gildi's paved road is the pre-stocked first-aid-kit checklist and supplier list that make the season-readiness trial trivially passable. + ### 3.5 Vísir grades: teaching vs. operational 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): @@ -110,8 +113,8 @@ Follows the established discipline: no kind introduced merely to filter; nothing | Gildi | **`Group` with `spec.type: gildi`** — joins the typed-Group tree (organization/sport/…/gildi). Membership (`memberOf`), ownership rollups, and the graph come free. What the gildi stewards (craft or aspect refs) is a `siliconsaga.org/*` annotation. Dovetails with the parked CODEOWNERS-virtual-team idea: a gildi is a virtual team that is *supposed* to exist. | | Skill | A **vocabulary, not entities** (Skill Exchange's exact shape): YAML-defined skill list; a profile decorator attaches selections to `User` entities so search indexes them. Matches the ResourceType-as-vocabulary precedent. | | Craft | **Vocabulary-first**: a named bundle (skill refs + vísir refs) in the same YAML family. Promotable to something heavier only if matching mechanics demand it — the cheapest commitment while the structure is still finding its shape. | -| Aspect | **Vocabulary-first**, same YAML family: id, description, standard refs, optional steward-gildi ref. No new kind — an aspect an entity carries is an enrollment annotation on that entity. | -| Standard + trials | **Git-backed YAML consumed by the scorecard plugin.** Evaluate `@backstage-community/plugin-tech-insights` first (facts/checks/fact-retrievers); fall back to a custom grouped-checks plugin if it constrains (per the DevEx reference doc). Each standard declares its **aspect**, plus an `ownerEntityRef` to the steward gildi Group when one exists; applicability is two-layered per Soundcheck (static catalog filter + enrollment annotation) so broad trials never ambush entities. Results/history are plugin data — rebuildable, like the Saga discipline. | +| Aspect | **Vocabulary-first**, same YAML family: id, description, standard refs, optional steward-gildi ref. No new kind — an aspect an entity carries is an enrollment annotation on that entity. An aspect's assets (standard YAML, paved-road templates, remediation vísar) live together in a **practice home repo** stewarded by its gildi (§3.4). | +| Standard + trials | **Git-backed YAML consumed by the scorecard plugin.** Evaluate `@backstage-community/plugin-tech-insights` first (facts/checks/fact-retrievers); fall back to a custom grouped-checks plugin if it constrains (per the DevEx reference doc). Each standard declares its **aspect**, plus an `ownerEntityRef` to the steward gildi Group when one exists; **each trial declares a remediation-vísir ref** so failing checks always link to the fix; applicability is two-layered per Soundcheck (static catalog filter + enrollment annotation) so broad trials never ambush entities. Results/history are plugin data — rebuildable, like the Saga discipline. | | Vísir (teaching) | **Git markdown in `/docs`, TechDocs-rendered**, referenced via `siliconsaga.org/visir` annotations from gildi Groups, craft/skill vocabulary entries, facilities, or Cycles — the same thin-index-over-Git pattern as `saga-doc`. | | Vísir (operational) | **Parameterized templates in `/runbooks`** alongside `/docs` in the owning repo, rendered by a dedicated runbooks plugin (placeholders for environmental details filled via URL parameters — the pre-existing plugin concept). Component/aspect-scoped runbooks live with the component they serve. | | Muster calls | **Not catalog.** Calls are volatile marketplace data → the Phase 4 store (the issue-tracker-as-store contender fits: a call *is* an issue with labels). A call references a Cycle + a craft. Deferred with Phases 4/6. | From 3e2569a81a5b4def68b8d52d6aed25a7466d28c5 Mon Sep 17 00:00:00 2001 From: Cervator Date: Sat, 11 Jul 2026 07:38:05 -0400 Subject: [PATCH 5/8] =?UTF-8?q?feat(examples):=20Ravenline=20mock=20softwa?= =?UTF-8?q?re=20org=20=E2=80=94=20practice-layer=20running=20example?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit A whole mock software org (Ravenline, a small parcel-logistics SaaS) paired with the practice-layer design doc as its running example — demo data now, fixtures for future practice-layer features later. The catalog half ingests with ZERO new code, demonstrating the design's no-new-custom-kinds claim: an org tree with two gildi-typed Groups (one aspect-aligned, one craft-aligned), six users, a software graph with aspect-enrollment and visir annotations, a release Cycle, a drive Cycle (the Soundcheck-Campaign analog), and a Saga narrated by a user. The non-catalog half freezes the design section-5 file shapes as plain YAML/markdown deliberately not ingested: skill/craft/aspect vocabularies, two standards (security measuring Components in three tiers, release-readiness measuring Cycles — the season-readiness twin), the security practice home repo with its paved-road pipeline template, and teaching vs operational (parameterized) visar showing the /docs-vs-/runbooks convention. The demo data tells the design's paved-road story: tracking-api at silver, carrier-gateway stuck at bronze with the dependency-scanning trial failing and a remediation doc whose entire instruction is the one-line template include. smoke-catalog now also asserts the Ravenline entities ingest at runtime (gildi Group typed, release Cycle with partOf/dependsOn relations, Saga owned by its skald and touching its Cycle) — 17 checks, all passing. Co-Authored-By: Claude Fable 5 --- app-config.yaml | 17 ++++ ...26-07-10-guilds-skills-standards-design.md | 2 +- examples/mock-org/README.md | 37 ++++++++ examples/mock-org/cycles.yaml | 42 +++++++++ examples/mock-org/org.yaml | 90 +++++++++++++++++++ examples/mock-org/practice-layer/aspects.yaml | 16 ++++ examples/mock-org/practice-layer/crafts.yaml | 13 +++ examples/mock-org/practice-layer/skills.yaml | 23 +++++ .../standards/release-readiness.yaml | 23 +++++ .../handbook/docs/release-captain-guide.md | 11 +++ .../docs/dependency-scanning.md | 15 ++++ .../pipeline-templates/dependency-scan.yml | 11 +++ .../runbooks/rotate-leaked-credential.md | 24 +++++ .../repos/security-practice/standard.yaml | 37 ++++++++ .../repos/tracking-api/docs/oncall-primer.md | 5 ++ .../tracking-api/runbooks/queue-backlog.md | 25 ++++++ examples/mock-org/sagas/tracking-2026-2.md | 11 +++ examples/mock-org/software.yaml | 73 +++++++++++++++ scripts/smoke-catalog.sh | 22 ++++- 19 files changed, 493 insertions(+), 4 deletions(-) create mode 100644 examples/mock-org/README.md create mode 100644 examples/mock-org/cycles.yaml create mode 100644 examples/mock-org/org.yaml create mode 100644 examples/mock-org/practice-layer/aspects.yaml create mode 100644 examples/mock-org/practice-layer/crafts.yaml create mode 100644 examples/mock-org/practice-layer/skills.yaml create mode 100644 examples/mock-org/practice-layer/standards/release-readiness.yaml create mode 100644 examples/mock-org/repos/handbook/docs/release-captain-guide.md create mode 100644 examples/mock-org/repos/security-practice/docs/dependency-scanning.md create mode 100644 examples/mock-org/repos/security-practice/pipeline-templates/dependency-scan.yml create mode 100644 examples/mock-org/repos/security-practice/runbooks/rotate-leaked-credential.md create mode 100644 examples/mock-org/repos/security-practice/standard.yaml create mode 100644 examples/mock-org/repos/tracking-api/docs/oncall-primer.md create mode 100644 examples/mock-org/repos/tracking-api/runbooks/queue-backlog.md create mode 100644 examples/mock-org/sagas/tracking-2026-2.md create mode 100644 examples/mock-org/software.yaml diff --git a/app-config.yaml b/app-config.yaml index 3bd5f7e..ca0bead 100644 --- a/app-config.yaml +++ b/app-config.yaml @@ -127,6 +127,23 @@ catalog: rules: - allow: [Group, Domain, System, Resource, Component, Cycle, Saga] + # Mock software org "Ravenline" — the practice-layer design's running example + # (org tree + gildi Groups, software graph, release/drive Cycles, one Saga). + # See examples/mock-org/README.md; the practice-layer/ vocabularies there are + # deliberately NOT ingested (future plugin input). + - type: file + target: ../../examples/mock-org/org.yaml + rules: + - allow: [User, Group] + - type: file + target: ../../examples/mock-org/software.yaml + rules: + - allow: [Domain, System, Resource, Component] + - type: file + target: ../../examples/mock-org/cycles.yaml + rules: + - allow: [Cycle, Saga] + ## Uncomment these lines to add more example data # - type: url # target: https://github.com/backstage/backstage/blob/master/packages/catalog-model/examples/all.yaml 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 eccba0b..3263ae6 100644 --- a/docs/plans/2026-07-10-guilds-skills-standards-design.md +++ b/docs/plans/2026-07-10-guilds-skills-standards-design.md @@ -129,7 +129,7 @@ Follows the established discipline: no kind introduced merely to filter; nothing ## 7. Phasing & Next Steps -1. **Now:** this doc fixes the vocabulary; fold the settled terms into the planned `docs/catalog-model.md` reference doc when it is written. +1. **Now:** this doc fixes the vocabulary; fold the settled terms into the planned `docs/catalog-model.md` reference doc when it is written. A mock software org (**Ravenline**, `examples/mock-org/`) ships alongside as the running example: it ingests with zero new code — the "no new custom kinds" claim, demonstrated — and freezes the vocabulary/standard/vísir file shapes as fixtures for the future plugins. 2. **Phase 4:** muster calls ride the marketplace-store decision (§5.1 of the umbrella design), referencing Cycles + crafts. 3. **Phase 6:** skill profiles + vocabulary, the first gildi Groups and aspects, the first standard (season-readiness, measuring a Cycle), and the kennings map in app-config. Tech Insights evaluation happens here. 4. **Runbooks plugin** (operational vísar: `/runbooks` convention + URL-parameter placeholders) is its own plugin effort — general-purpose Backstage value like `Cycle`, sequenced independently. diff --git a/examples/mock-org/README.md b/examples/mock-org/README.md new file mode 100644 index 0000000..9e59b9f --- /dev/null +++ b/examples/mock-org/README.md @@ -0,0 +1,37 @@ +# Mock Org: Ravenline — the Practice-Layer Running Example + +Ravenline is a fictional small parcel-logistics SaaS (~20 people) used as the running example for the practice-layer design (`docs/plans/2026-07-10-guilds-skills-standards-design.md`). It exists to demo the model end to end and to test future practice-layer features against. Everything here uses **built-in kinds plus the shipped `Cycle`/`Saga`** — the design introduces no new custom kinds, and this seed is the proof. + +## The cast + +- **Org tree** (`org.yaml`): `ravenline` (organization) → `rl-engineering` (department) → `team-tracking`, `team-shipping`, `team-platform`. Six 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. +- **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 + +`tracking-api` is enrolled in both aspects (`siliconsaga.org/aspects` annotation) and sits at **silver** on the security standard. `carrier-gateway` is enrolled in security only and is stuck at **bronze** with the `dependency-scanning` trial failing — its remediation doc says, in full: *add the one-line include of the paved-road pipeline template.* That is the paved-road loop from design §3.4, frozen as demo data. Meanwhile the `dependency-scanning-drive` Cycle is the security gildi's time-bound push to get every service's scanning green, and the release Saga cites how the release went. + +## Practice-layer files (not catalog entities — future plugin input) + +The `practice-layer/` and `repos/` trees are **plain YAML/markdown, deliberately not ingested**. They document the exact shapes design §5 assigns to vocabularies and Git-backed standards, so future plugins have fixtures waiting: + +- `practice-layer/skills.yaml` — the skill vocabulary + mock profile selections (in the real system, profiles live in the plugin store and decorate `User` entities). +- `practice-layer/crafts.yaml` — `release-captain` (skills + a teaching vísir) and `incident-commander` (skills only — vísar are optional). +- `practice-layer/aspects.yaml` — `security` (steward gildi + home repo + standard) and `operational-readiness` (**no steward** — an aspect can exist before a gildi forms around it). +- `practice-layer/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 a remediation ref), the paved road (`pipeline-templates/dependency-scan.yml`), a teaching vísir (`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. + +## What ingests, what waits + +| Ingests today (catalog) | Waits for plugins | +|---|---| +| Org tree, gildi Groups (`spec.type: gildi`), Users | Skill profiles decorating Users | +| 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) | + +`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/cycles.yaml b/examples/mock-org/cycles.yaml new file mode 100644 index 0000000..6dd0d3c --- /dev/null +++ b/examples/mock-org/cycles.yaml @@ -0,0 +1,42 @@ +--- +# A software release as a Cycle (type: release) — the same primitive as an MTL +# season, on the software side of the two-family model. +apiVersion: siliconsaga.org/v1alpha1 +kind: Cycle +metadata: { name: tracking-2026-2, description: 'Parcel Tracking release 2026.2' } +spec: + type: release + timeframe: { start: '2026-04-01', end: '2026-06-30' } + of: system:default/parcel-tracking + owner: group:default/team-tracking + happensAt: [resource:default/prod-cluster] +--- +# A drive Cycle — the Soundcheck-Campaign analog (design §2): the security +# gildi's time-bound push to get every service's dependency scanning green. +apiVersion: siliconsaga.org/v1alpha1 +kind: Cycle +metadata: + name: dependency-scanning-drive + description: 'Drive: dependency scanning green on every service (paved-road adoption push)' +spec: + type: drive + timeframe: { start: '2026-05-01', end: '2026-07-31' } + of: group:default/security-gildi + owner: group:default/security-gildi +--- +# The release retrospective as a Saga — narrated by Runa, Git-backed body. +apiVersion: siliconsaga.org/v1alpha1 +kind: Saga +metadata: + name: saga-tracking-2026-2 + description: 'The Saga of Parcel Tracking 2026.2' + annotations: + siliconsaga.org/saga-doc: ./sagas/tracking-2026-2.md +spec: + skald: user:default/runa + timeframe: { start: '2026-04-01', end: '2026-06-30' } + touches: + - cycle:default/tracking-2026-2 + - component:default/tracking-api + - group:default/release-captains-gildi + owner: group:default/team-tracking diff --git a/examples/mock-org/org.yaml b/examples/mock-org/org.yaml new file mode 100644 index 0000000..fc1a619 --- /dev/null +++ b/examples/mock-org/org.yaml @@ -0,0 +1,90 @@ +--- +# Ravenline org tree — organization → department → team (typed Group tree, +# same discipline as the MTL seed's organization → sport → division → team). +apiVersion: backstage.io/v1alpha1 +kind: Group +metadata: + name: ravenline + description: Ravenline — parcel-logistics SaaS (mock org, practice-layer demo) +spec: + type: organization + children: [rl-engineering, security-gildi, release-captains-gildi] +--- +apiVersion: backstage.io/v1alpha1 +kind: Group +metadata: { name: rl-engineering } +spec: { type: department, parent: ravenline, children: [team-tracking, team-shipping, team-platform] } +--- +apiVersion: backstage.io/v1alpha1 +kind: Group +metadata: { name: team-tracking } +spec: { type: team, parent: rl-engineering, children: [] } +--- +apiVersion: backstage.io/v1alpha1 +kind: Group +metadata: { name: team-shipping } +spec: { type: team, parent: rl-engineering, children: [] } +--- +apiVersion: backstage.io/v1alpha1 +kind: Group +metadata: { name: team-platform } +spec: { type: team, parent: rl-engineering, children: [] } +--- +# Gildi — the fellowship form of the practice layer (design §3.2/§5): plain +# typed Groups, cross-cutting the team tree. What a gildi stewards is an +# annotation, not a new relation type. +apiVersion: backstage.io/v1alpha1 +kind: Group +metadata: + name: security-gildi + description: The Security guild — stewards the security aspect (aspect-aligned gildi) + annotations: + siliconsaga.org/stewards: 'aspect:security' +spec: + type: gildi + parent: ravenline + children: [] +--- +apiVersion: backstage.io/v1alpha1 +kind: Group +metadata: + name: release-captains-gildi + description: The Release Captains guild — stewards the release-captain craft (craft-aligned gildi) + annotations: + siliconsaga.org/stewards: 'craft:release-captain' +spec: + type: gildi + parent: ravenline + children: [] +--- +# People — membership carries both team and gildi affiliation via memberOf. +# Skill profiles are NOT entity fields: see practice-layer/skills.yaml. +apiVersion: backstage.io/v1alpha1 +kind: User +metadata: { name: astrid, description: 'Platform engineer, security-inclined' } +spec: { memberOf: [team-platform, security-gildi] } +--- +apiVersion: backstage.io/v1alpha1 +kind: User +metadata: { name: bjorn, description: 'Shipping engineer, runs releases' } +spec: { memberOf: [team-shipping, release-captains-gildi] } +--- +apiVersion: backstage.io/v1alpha1 +kind: User +metadata: { name: runa, description: 'Tracking engineer, writes the sagas' } +spec: { memberOf: [team-tracking, release-captains-gildi] } +--- +apiVersion: backstage.io/v1alpha1 +kind: User +metadata: { name: leif, description: 'Tracking engineer, learning threat modeling' } +spec: { memberOf: [team-tracking, security-gildi] } +--- +apiVersion: backstage.io/v1alpha1 +kind: User +metadata: { name: sigrid, description: 'Shipping engineer' } +spec: { memberOf: [team-shipping] } +--- +apiVersion: backstage.io/v1alpha1 +kind: User +metadata: { name: egil, description: 'Platform engineer' } +spec: { memberOf: [team-platform] } diff --git a/examples/mock-org/practice-layer/aspects.yaml b/examples/mock-org/practice-layer/aspects.yaml new file mode 100644 index 0000000..cd07f6b --- /dev/null +++ b/examples/mock-org/practice-layer/aspects.yaml @@ -0,0 +1,16 @@ +# Aspect vocabulary — the cross-cutting concerns (design §3.2): each holds +# standards applied to enrolled entities. Vocabulary-first; NOT catalog +# entities. Enrollment is the siliconsaga.org/aspects annotation on the +# enrolled entity (see ../software.yaml). +aspects: + - id: security + description: Services uphold the security bar; the gildi ships the paved road that clears it. + steward: group:default/security-gildi + home: ./repos/security-practice + standards: + - ./repos/security-practice/standard.yaml + - id: operational-readiness + description: Releases and services are ready to run — the software twin of season-readiness. + steward: null # an aspect can exist before a gildi forms around it (design §3.2) + standards: + - ./practice-layer/standards/release-readiness.yaml diff --git a/examples/mock-org/practice-layer/crafts.yaml b/examples/mock-org/practice-layer/crafts.yaml new file mode 100644 index 0000000..fbb3359 --- /dev/null +++ b/examples/mock-org/practice-layer/crafts.yaml @@ -0,0 +1,13 @@ +# Craft vocabulary — demand-side skill bundles (design §3.2): what a muster +# calls for. Vocabulary-first; promotable to entities only if matching +# mechanics demand it. NOT catalog entities. +crafts: + - id: release-captain + description: Runs a release Cycle end to end — coordinates the cut, watches the rollout, calls the rollback. + skills: [ci-pipelines, incident-command] + visar: + - ./repos/handbook/docs/release-captain-guide.md + - id: incident-commander + description: Owns an active incident — coordinates responders, communicates status, runs the retro. + skills: [incident-command, kubernetes] + # No vísar yet — they are optional; the craft is still callable-for. diff --git a/examples/mock-org/practice-layer/skills.yaml b/examples/mock-org/practice-layer/skills.yaml new file mode 100644 index 0000000..2606c71 --- /dev/null +++ b/examples/mock-org/practice-layer/skills.yaml @@ -0,0 +1,23 @@ +# Skill vocabulary — Skill Exchange's exact shape (design §2/§5): admin-defined +# list, categories from a small enum. NOT catalog entities; consumed by the +# future skill-profile plugin. +skills: + - { name: kubernetes, category: infrastructure } + - { name: ci-pipelines, category: infrastructure } + - { name: postgres, category: infrastructure } + - { name: typescript, category: languages } + - { name: threat-modeling, category: techniques } + - { name: incident-command, category: techniques } + - { name: technical-writing, category: techniques } + +# Mock profile selections — DEMO STAND-IN. In the real system these live in the +# plugin's store and decorate User entities for search (design §5); they are +# frozen here so demos and future plugin tests have fixtures. Two buckets per +# Skill Exchange: canHelpWith ("I can help with") / learning ("I'm learning"). +profiles: + astrid: { canHelpWith: [kubernetes, threat-modeling, ci-pipelines], learning: [incident-command] } + bjorn: { canHelpWith: [ci-pipelines, incident-command], learning: [kubernetes] } + runa: { canHelpWith: [typescript, technical-writing], learning: [threat-modeling] } + leif: { canHelpWith: [typescript, postgres], learning: [threat-modeling] } + sigrid: { canHelpWith: [postgres], learning: [ci-pipelines] } + egil: { canHelpWith: [kubernetes, postgres], learning: [] } diff --git a/examples/mock-org/practice-layer/standards/release-readiness.yaml b/examples/mock-org/practice-layer/standards/release-readiness.yaml new file mode 100644 index 0000000..9b090f9 --- /dev/null +++ b/examples/mock-org/practice-layer/standards/release-readiness.yaml @@ -0,0 +1,23 @@ +# The release-readiness standard — measures CYCLES, not components: the +# software twin of the community season-readiness checklist (design §3.4). +# Git-backed YAML in the shape design §5 assigns; consumed by the future +# scorecard plugin. Single tier: readiness is pass/fail, not a ladder. +standard: + id: release-readiness + aspect: operational-readiness + filter: { kind: Cycle, spec.type: release } + tiers: + - name: ready + trials: + - id: release-captain-named + rule: the Cycle's craft call for release-captain is filled + factSource: muster-store # Phase 4 marketplace store + remediation: ./repos/handbook/docs/release-captain-guide.md + - 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 + - id: previous-cycle-saga-exists + rule: the previous release Cycle has at least one Saga + factSource: catalog + remediation: ./repos/handbook/docs/release-captain-guide.md diff --git a/examples/mock-org/repos/handbook/docs/release-captain-guide.md b/examples/mock-org/repos/handbook/docs/release-captain-guide.md new file mode 100644 index 0000000..9147b21 --- /dev/null +++ b/examples/mock-org/repos/handbook/docs/release-captain-guide.md @@ -0,0 +1,11 @@ +# Release captain's guide + +*Teaching vísir (craft-scoped): the guide handed to whoever answers the release-captain call. Referenced by `practice-layer/crafts.yaml`.* + +You're captaining a release Cycle. The job is coordination, not heroics: + +1. **Before the cut:** confirm the release-readiness trials are green on the Cycle (captain named — that's you; rollback runbooks linked; previous cycle's Saga exists). +2. **The cut:** tag, let the pipeline do the work, announce in the release channel. +3. **The watch:** own the dashboards for the first two hours; you decide rollback, nobody else has to. +4. **Handover or close:** if the watch outlives your day, hand over explicitly (the May 2026 co-captain onboarding worked with zero meetings — this guide is why). +5. **After:** nudge a skald. The Cycle happened; whether it becomes a Saga is up to whoever writes it. diff --git a/examples/mock-org/repos/security-practice/docs/dependency-scanning.md b/examples/mock-org/repos/security-practice/docs/dependency-scanning.md new file mode 100644 index 0000000..00f50ed --- /dev/null +++ b/examples/mock-org/repos/security-practice/docs/dependency-scanning.md @@ -0,0 +1,15 @@ +# Dependency Scanning — how to satisfy the trial + +*Teaching vísir (static, docs-homed). Remediation target of the `dependency-scanning` trial.* + +Add the paved-road template to your pipeline: + +```yaml +include: + - project: ravenline/security-practice + file: pipeline-templates/dependency-scan.yml +``` + +That is the entire change. The template runs on your default branch, reports results to the practice's collector, and the trial flips green on your next pipeline run — no ticket, no review meeting. + +If the scan finds something: criticals fail the pipeline immediately; anything else appears on your component's scorecard with a 30-day clock (the `no-critical-vulns-30d` trial at silver). Questions → `#security-gildi`. diff --git a/examples/mock-org/repos/security-practice/pipeline-templates/dependency-scan.yml b/examples/mock-org/repos/security-practice/pipeline-templates/dependency-scan.yml new file mode 100644 index 0000000..0722cf1 --- /dev/null +++ b/examples/mock-org/repos/security-practice/pipeline-templates/dependency-scan.yml @@ -0,0 +1,11 @@ +# The paved road (design §3.4): a reusable CI pipeline template step any team +# adopts with a one-line include. Adopting it is what flips the +# dependency-scanning trial green — the requirement, the tooling, and the +# measurement share one steward. (Mock stub — GitLab CI include shape.) +dependency-scan: + stage: test + image: registry.ravenline.example/security/dep-scan:stable + script: + - dep-scan --fail-on critical --report-to "${SCAN_RESULTS_ENDPOINT}" + rules: + - if: '$CI_COMMIT_BRANCH == $CI_DEFAULT_BRANCH' diff --git a/examples/mock-org/repos/security-practice/runbooks/rotate-leaked-credential.md b/examples/mock-org/repos/security-practice/runbooks/rotate-leaked-credential.md new file mode 100644 index 0000000..6e9eea9 --- /dev/null +++ b/examples/mock-org/repos/security-practice/runbooks/rotate-leaked-credential.md @@ -0,0 +1,24 @@ +# Runbook: rotate a leaked credential + + + +**When:** secret scanning flags a credential in `{{service}}`'s history, or one is reported leaked. + +1. Revoke the credential at its source immediately — before cleanup, before comms. +2. Issue the replacement and store it: + + ``` + bao kv put secret/{{secret_path}} value= + ``` + +3. Restart the consuming workload so it picks up the new value: + + ``` + kubectl --context {{cluster}} -n {{namespace}} rollout restart deploy/{{service}} + ``` + +4. Verify the old credential is dead (a request using it must fail), then note the incident in `#security-gildi`. +5. If the leak was in Git history: the scrub procedure is a separate escalation — page the security gildi steward rather than improvising it. diff --git a/examples/mock-org/repos/security-practice/standard.yaml b/examples/mock-org/repos/security-practice/standard.yaml new file mode 100644 index 0000000..f52f5db --- /dev/null +++ b/examples/mock-org/repos/security-practice/standard.yaml @@ -0,0 +1,37 @@ +# The security standard — lives in the practice home repo beside the paved +# road and the remediation vísar it references (design §3.4). Git-backed YAML +# in the shape design §5 assigns; consumed by the future scorecard plugin. +# Every trial declares its remediation vísir: a failing check is always one +# click from the fix. +standard: + id: security + aspect: security + owner: group:default/security-gildi + filter: { kind: Component, spec.type: service } + tiers: + - name: bronze + trials: + - id: dependency-scanning + rule: the default-branch pipeline runs the dependency-scan template + factSource: ci-pipeline-results + remediation: ./docs/dependency-scanning.md + - id: no-secrets-in-repo + rule: secret scanning reports zero findings + factSource: ci-pipeline-results + remediation: ./runbooks/rotate-leaked-credential.md + - name: silver + trials: + - id: no-critical-vulns-30d + rule: no critical finding older than 30 days + factSource: ci-pipeline-results + remediation: ./docs/dependency-scanning.md + - id: security-contact-declared + rule: the Component declares a security contact + factSource: catalog-annotations + remediation: ./docs/dependency-scanning.md + - name: gold + trials: + - id: threat-model-current + rule: a threat model is on file and reviewed within the last year + factSource: practice-home-repo + remediation: ./docs/dependency-scanning.md diff --git a/examples/mock-org/repos/tracking-api/docs/oncall-primer.md b/examples/mock-org/repos/tracking-api/docs/oncall-primer.md new file mode 100644 index 0000000..9880ece --- /dev/null +++ b/examples/mock-org/repos/tracking-api/docs/oncall-primer.md @@ -0,0 +1,5 @@ +# tracking-api on-call primer + +*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). diff --git a/examples/mock-org/repos/tracking-api/runbooks/queue-backlog.md b/examples/mock-org/repos/tracking-api/runbooks/queue-backlog.md new file mode 100644 index 0000000..c80a45a --- /dev/null +++ b/examples/mock-org/repos/tracking-api/runbooks/queue-backlog.md @@ -0,0 +1,25 @@ +# Runbook: parcel-events queue backlog + + + +**When:** consumer lag on `parcel-events` alerts (sustained growth ≥ 20 min). + +1. Confirm it's consumption, not a poison message — check the consumer error rate: + + ``` + kubectl --context {{cluster}} -n {{namespace}} logs deploy/tracking-consumer --since=10m + ``` + + Repeating crash on one offset → poison message: skip to step 4. + +2. Scale out the consumers: + + ``` + kubectl --context {{cluster}} -n {{namespace}} scale deploy/tracking-consumer --replicas=6 + ``` + +3. Watch lag drain; scale back to 2 replicas once under 1 minute. +4. Poison message: park it to the dead-letter topic and file the bug — do not delete it. +5. Note the event in the release Cycle's channel; if customer-visible, the incident-commander craft call goes out. diff --git a/examples/mock-org/sagas/tracking-2026-2.md b/examples/mock-org/sagas/tracking-2026-2.md new file mode 100644 index 0000000..be45be0 --- /dev/null +++ b/examples/mock-org/sagas/tracking-2026-2.md @@ -0,0 +1,11 @@ +# The Saga of Parcel Tracking 2026.2 + +*Skald: Runa · April–June 2026* + +The 2026.2 release set out to ship webhook-based tracking events and retire the polling API. It shipped both, one week late, and the lateness taught us more than the shipping did. + +Bjorn captained the release. The mid-cycle surprise was the queue backlog incident of May 14th: consumer lag on `parcel-events` hit four hours before anyone noticed, and the recovery was slowed by the fact that the scaling commands lived in Egil's head. The queue-backlog runbook in `tracking-api/runbooks/` exists because of that afternoon — the next person gets copy-paste commands, not archaeology. + +The security silver certification held through the release: dependency scanning caught a vulnerable transitive dependency in week two, and the paved-road template meant the fix was a version bump, not a scramble. The `dependency-scanning-drive` was running in parallel — `carrier-gateway` is the last service still at bronze, and Sigrid has the include-line change queued. + +**What worked:** the paved road; the release captain's guide (Bjorn onboarded Runa as co-captain mid-cycle with zero meetings). **What broke:** queue observability — the lag alert now pages at 20 minutes. **Next cycle:** retire the polling API's last two consumers, and get carrier-gateway to silver so the drive can close. diff --git a/examples/mock-org/software.yaml b/examples/mock-org/software.yaml new file mode 100644 index 0000000..49f1c2b --- /dev/null +++ b/examples/mock-org/software.yaml @@ -0,0 +1,73 @@ +--- +# Ravenline software graph — built-in kinds only. Aspect enrollment and vísir +# references ride annotations (design §5): inert today, consumed by the future +# scorecard/runbooks plugins. +apiVersion: backstage.io/v1alpha1 +kind: Domain +metadata: { name: ravenline } +spec: { owner: group:default/ravenline } +--- +apiVersion: backstage.io/v1alpha1 +kind: System +metadata: { name: parcel-tracking, description: Parcel tracking product } +spec: { owner: group:default/team-tracking, domain: ravenline } +--- +apiVersion: backstage.io/v1alpha1 +kind: Component +metadata: + name: tracking-api + 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' +spec: { type: service, lifecycle: production, owner: group:default/team-tracking, system: parcel-tracking } +--- +apiVersion: backstage.io/v1alpha1 +kind: Component +metadata: { name: tracking-web, description: Customer-facing tracking page } +spec: { type: website, lifecycle: production, owner: group:default/team-tracking, system: parcel-tracking } +--- +apiVersion: backstage.io/v1alpha1 +kind: System +metadata: { name: shipping, description: Shipping orchestration product } +spec: { owner: group:default/team-shipping, domain: ravenline } +--- +apiVersion: backstage.io/v1alpha1 +kind: Component +metadata: + name: shipping-orchestrator + description: 'Books carriers, prints labels. Security standard: silver.' + annotations: + siliconsaga.org/aspects: 'security' +spec: { type: service, lifecycle: production, owner: group:default/team-shipping, system: shipping } +--- +apiVersion: backstage.io/v1alpha1 +kind: Component +metadata: + name: carrier-gateway + description: 'Adapters for carrier APIs. Security standard: bronze — dependency-scanning trial failing; remediation = adopt the paved-road pipeline template.' + annotations: + siliconsaga.org/aspects: 'security' +spec: { type: service, lifecycle: production, owner: group:default/team-shipping, system: shipping } +--- +apiVersion: backstage.io/v1alpha1 +kind: System +metadata: { name: rl-platform, description: Shared platform } +spec: { owner: group:default/team-platform, domain: ravenline } +--- +apiVersion: backstage.io/v1alpha1 +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/. +apiVersion: backstage.io/v1alpha1 +kind: Component +metadata: + name: security-practice-home + description: 'Security practice home: standard + pipeline templates + 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 } diff --git a/scripts/smoke-catalog.sh b/scripts/smoke-catalog.sh index 96db81c..c2b28a5 100644 --- a/scripts/smoke-catalog.sh +++ b/scripts/smoke-catalog.sh @@ -60,14 +60,20 @@ byname() { curl -fsS --connect-timeout 3 --max-time 5 "${hdr[@]}" "http://localh # Backend readiness != catalog-ingestion readiness. Poll until the custom entities # appear (or the timeout expires) rather than sleeping once and querying once. -CYCLE='{}'; SAGA='{}'; GROUP='{}' +CYCLE='{}'; SAGA='{}'; GROUP='{}'; RLCYCLE='{}'; RLSAGA='{}'; GILDI='{}' for _ in $(seq 1 120); do CYCLE="$(byname cycle/default/soccer-2026-spring)" SAGA="$(byname saga/default/saga-soccer-2026-spring)" GROUP="$(byname group/default/mtl)" + RLCYCLE="$(byname cycle/default/tracking-2026-2)" + RLSAGA="$(byname saga/default/saga-tracking-2026-2)" + GILDI="$(byname group/default/security-gildi)" 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"'; then break; fi + && 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 sleep 1 done @@ -98,6 +104,16 @@ check_rel "Saga ownedBy skald (guest)" "$SAGA" ownedBy user:default/gues check_rel "Saga ownedBy owner (mtl-soccer)" "$SAGA" ownedBy group:default/mtl-soccer || pass=0 check_rel "Saga dependsOn Cycle (touches)" "$SAGA" dependsOn cycle:default/soccer-2026-spring || pass=0 check "Saga doc annotation preserved" "$SAGA" 'siliconsaga.org/saga-doc' || pass=0 +# Mock software org (Ravenline — practice-layer running example): the software +# side of the two-family model plus a gildi-typed Group, ingesting with the +# same machinery and zero new code. +check "Ravenline Cycle ingested (release)" "$RLCYCLE" '"type":"release"' || pass=0 +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 "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 # Surface any catalog processing errors for the seed. echo "--- catalog errors mentioning mtl/cycle/saga (if any) ---" @@ -106,7 +122,7 @@ echo "(end errors)" # Backend teardown is handled by the EXIT trap registered above. if [[ "$pass" == 1 ]]; then - echo "smoke-catalog PASS: Cycle + Saga + Group tree ingested at runtime with their relations" + echo "smoke-catalog PASS: MTL + Ravenline seeds ingested at runtime with their relations" exit 0 fi echo "smoke-catalog FAIL: expected entities/relations missing. Recent log:" >&2 From f20270e801742eeb6bf15c9f7b73be6d9e0d9e43 Mon Sep 17 00:00:00 2001 From: Cervator Date: Sat, 11 Jul 2026 08:40:15 -0400 Subject: [PATCH 6/8] docs: name the system Guildhall + address CR #5 review round 1 MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit The system gets its proper name: the Guildhall (norse kenning skin Gildaskali, the historic guild-hall). "Practice layer" was the working name and kept reading as a verb — practicing — which is one ambiguity too many for a terminology design. The doc title, the kennings table (new guildhall row), the mock-org README, and the examples/mock-org vocabulary directory (practice-layer/ → guildhall/) all follow. Review fixes (CodeRabbit + Copilot, round 1): - Design doc section 5: teaching-visir referrer list now includes Components and practice homes, matching the Ravenline fixtures. - Per-trial remediation alignment: new security-contact.md and threat-modeling.md docs in the practice home; standard.yaml points each silver/gold trial at its own fix (the 30-day-vulns trial keeps dependency-scanning.md, which documents that clock). - rotate-leaked-credential runbook: the replacement secret now goes in via stdin (read -rs + value=-) instead of the command line — the security practice's own runbook should not leak into shell history. - bash language identifiers on all runbook fences (markdownlint MD040). - Copilot path findings: guildhall/*.yaml fixture paths are now file-relative (the ./repos/... refs did not resolve from inside the vocabulary tree), each file stating the convention. - smoke-catalog: wall-clock deadline bounds the poll loop worst case (six lookups x 5s curl timeout x 120 iterations was unbounded in practice), and the failure-diagnostic error grep now also matches the Ravenline seed terms. - Umbrella-design reference in the doc header spells the real realm path and notes it lives in the yggdrasil workspace, not this repo. Validated: make smoke-catalog 17/17 PASS, full ws test gate green. Co-Authored-By: Claude Fable 5 --- app-config.yaml | 4 ++-- ...026-07-10-guilds-skills-standards-design.md | 11 ++++++----- examples/mock-org/README.md | 18 +++++++++--------- .../{practice-layer => guildhall}/aspects.yaml | 8 ++++---- .../{practice-layer => guildhall}/crafts.yaml | 4 ++-- .../{practice-layer => guildhall}/skills.yaml | 0 .../standards/release-readiness.yaml | 7 ++++--- examples/mock-org/org.yaml | 6 +++--- .../handbook/docs/release-captain-guide.md | 2 +- .../security-practice/docs/security-contact.md | 13 +++++++++++++ .../security-practice/docs/threat-modeling.md | 10 ++++++++++ .../runbooks/rotate-leaked-credential.md | 10 ++++++---- .../repos/security-practice/standard.yaml | 6 +++--- .../tracking-api/runbooks/queue-backlog.md | 4 ++-- scripts/smoke-catalog.sh | 13 +++++++++---- 15 files changed, 74 insertions(+), 42 deletions(-) rename examples/mock-org/{practice-layer => guildhall}/aspects.yaml (75%) rename examples/mock-org/{practice-layer => guildhall}/crafts.yaml (86%) rename examples/mock-org/{practice-layer => guildhall}/skills.yaml (100%) rename examples/mock-org/{practice-layer => guildhall}/standards/release-readiness.yaml (75%) create mode 100644 examples/mock-org/repos/security-practice/docs/security-contact.md create mode 100644 examples/mock-org/repos/security-practice/docs/threat-modeling.md diff --git a/app-config.yaml b/app-config.yaml index ca0bead..6bd6dbe 100644 --- a/app-config.yaml +++ b/app-config.yaml @@ -127,9 +127,9 @@ catalog: rules: - allow: [Group, Domain, System, Resource, Component, Cycle, Saga] - # Mock software org "Ravenline" — the practice-layer design's running example + # Mock software org "Ravenline" — the Guildhall design's running example # (org tree + gildi Groups, software graph, release/drive Cycles, one Saga). - # See examples/mock-org/README.md; the practice-layer/ vocabularies there are + # See examples/mock-org/README.md; the guildhall/ vocabularies there are # deliberately NOT ingested (future plugin input). - type: file target: ../../examples/mock-org/org.yaml 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 3263ae6..66d3c68 100644 --- a/docs/plans/2026-07-10-guilds-skills-standards-design.md +++ b/docs/plans/2026-07-10-guilds-skills-standards-design.md @@ -1,15 +1,15 @@ -# Leiðangr — Guilds, Skills, and Standards: the Practice Layer (Design) +# Leiðangr — the Guildhall: Guilds, Skills, and Standards (Design) **Date:** 2026-07-10 **Status:** Draft -**Scope:** Terminology and conceptual model for the "practice layer" — how skills (Skill-Exchange-style), crafts, guilds/practices, maturity standards (Soundcheck-style), and procedure guides relate to each other and to the shipped `Cycle`/`Saga` kinds. Layered deliverable: an abstract model first (portable beyond Leiðangr), then its concrete Backstage mapping. Vocabulary lands now; mechanics are Phase 6 (scorecards, skill profiles) and Phase 4 (muster calls) work. -**Related:** `2026-07-06-leidangr-phase3-community-domain-design.md` (two-family model, typed Group tree), ADR 0007 (`Cycle`), ADR 0008 (`Saga`), the umbrella design (`realms/.../2026-06-09-leidangr-design.md` §6 Phase 6), and the Backstage DevEx reference doc (§ Scorecards and Poor Man's Soundcheck). +**Scope:** Terminology and conceptual model for the **Guildhall** — the system relating skills (Skill-Exchange-style), crafts, guilds/practices, maturity standards (Soundcheck-style), and procedure guides to each other and to the shipped `Cycle`/`Saga` kinds. Layered deliverable: an abstract model first (portable beyond Leiðangr), then its concrete Backstage mapping. Vocabulary lands now; mechanics are Phase 6 (scorecards, skill profiles) and Phase 4 (muster calls) work. +**Related:** `2026-07-06-leidangr-phase3-community-domain-design.md` (two-family model, typed Group tree), ADR 0007 (`Cycle`), ADR 0008 (`Saga`), the umbrella design (`realms/realm-siliconsaga/docs/plans/2026-06-09-leidangr-design.md` in the yggdrasil workspace — not in this repo; §6 Phase 6), and the Backstage DevEx reference doc (§ Scorecards and Poor Man's Soundcheck). --- ## 1. What This Is -Two premium Spotify Backstage plugins inspired this layer: **Skill Exchange** (skills attach to user profiles; opportunities are posted and browsed) and **Soundcheck** (entities are measured against tiered check-based standards). Spotify ships them as unconnected products. This design's claim is that they are two pieces of one thing — the **practice** — completed by a third piece Spotify never shipped: written procedure. A practice is not a single entity but a small constellation of nouns (§3). A prior-art data point: an internal grouped-checks system at Cervator's day job independently grew a "Grid" concept (themed collections of check-blocks — security, scalability, maintainability) that converges on Soundcheck's "Track"; and a team there independently subdivided into discipline areas mislabeled "teams" — groping toward the same missing noun. The missing noun is the **aspect** (§3), and this doc names the whole family around it. +This system is the **Guildhall** — the hall where the guild rosters, the craft rolls, the standards, and the guides all hang together. ("Practice layer" was the working name; it read as a verb — *practicing* — one ambiguity too many for a terminology design. *Gildaskáli*, the historic guild-hall, is its norse kenning skin.) Two premium Spotify Backstage plugins inspired it: **Skill Exchange** (skills attach to user profiles; opportunities are posted and browsed) and **Soundcheck** (entities are measured against tiered check-based standards). Spotify ships them as unconnected products. This design's claim is that they are two pieces of one thing — the **practice** — completed by a third piece Spotify never shipped: written procedure. A practice is not a single entity but a small constellation of nouns (§3). A prior-art data point: an internal grouped-checks system at Cervator's day job independently grew a "Grid" concept (themed collections of check-blocks — security, scalability, maintainability) that converges on Soundcheck's "Track"; and a team there independently subdivided into discipline areas mislabeled "teams" — groping toward the same missing noun. The missing noun is the **aspect** (§3), and this doc names the whole family around it. ## 2. Research Grounding (exact upstream vocabulary) @@ -91,6 +91,7 @@ Technical identifiers commit to **one canonical vocabulary** (below). The UI nev | Canonical (technical) | Norse display | Plain display | Notes | |---|---|---|---| +| `guildhall` | Gildaskáli | Practices / Practice Hub | The system's own name — the whole assembly of the rows below. | | `skill` | Skill | Skill | Already Old Norse. | | `craft` | Craft | Craft / Role | *Iðn* available as a norse-lexicon skin. | | `gildi` | Gildi | Guild | The one deliberate ON anchor at the technical layer (mirrors `spec.skald`). | @@ -115,7 +116,7 @@ Follows the established discipline: no kind introduced merely to filter; nothing | Craft | **Vocabulary-first**: a named bundle (skill refs + vísir refs) in the same YAML family. Promotable to something heavier only if matching mechanics demand it — the cheapest commitment while the structure is still finding its shape. | | Aspect | **Vocabulary-first**, same YAML family: id, description, standard refs, optional steward-gildi ref. No new kind — an aspect an entity carries is an enrollment annotation on that entity. An aspect's assets (standard YAML, paved-road templates, remediation vísar) live together in a **practice home repo** stewarded by its gildi (§3.4). | | Standard + trials | **Git-backed YAML consumed by the scorecard plugin.** Evaluate `@backstage-community/plugin-tech-insights` first (facts/checks/fact-retrievers); fall back to a custom grouped-checks plugin if it constrains (per the DevEx reference doc). Each standard declares its **aspect**, plus an `ownerEntityRef` to the steward gildi Group when one exists; **each trial declares a remediation-vísir ref** so failing checks always link to the fix; applicability is two-layered per Soundcheck (static catalog filter + enrollment annotation) so broad trials never ambush entities. Results/history are plugin data — rebuildable, like the Saga discipline. | -| Vísir (teaching) | **Git markdown in `/docs`, TechDocs-rendered**, referenced via `siliconsaga.org/visir` annotations from gildi Groups, craft/skill vocabulary entries, facilities, or Cycles — the same thin-index-over-Git pattern as `saga-doc`. | +| Vísir (teaching) | **Git markdown in `/docs`, TechDocs-rendered**, referenced via `siliconsaga.org/visir` annotations from gildi Groups, craft/skill vocabulary entries, Components (including practice homes), facilities, or Cycles — the same thin-index-over-Git pattern as `saga-doc`. | | Vísir (operational) | **Parameterized templates in `/runbooks`** alongside `/docs` in the owning repo, rendered by a dedicated runbooks plugin (placeholders for environmental details filled via URL parameters — the pre-existing plugin concept). Component/aspect-scoped runbooks live with the component they serve. | | Muster calls | **Not catalog.** Calls are volatile marketplace data → the Phase 4 store (the issue-tracker-as-store contender fits: a call *is* an issue with labels). A call references a Cycle + a craft. Deferred with Phases 4/6. | | Certifications / badges | Plugin data surfaced on entity pages, bronze/silver/gold. Community-side certifications are **advisory, never gates** (umbrella design §8: trust over gamification). | diff --git a/examples/mock-org/README.md b/examples/mock-org/README.md index 9e59b9f..d795934 100644 --- a/examples/mock-org/README.md +++ b/examples/mock-org/README.md @@ -1,6 +1,6 @@ -# Mock Org: Ravenline — the Practice-Layer Running Example +# Mock Org: Ravenline — the Guildhall Running Example -Ravenline is a fictional small parcel-logistics SaaS (~20 people) used as the running example for the practice-layer design (`docs/plans/2026-07-10-guilds-skills-standards-design.md`). It exists to demo the model end to end and to test future practice-layer features against. Everything here uses **built-in kinds plus the shipped `Cycle`/`Saga`** — the design introduces no new custom kinds, and this seed is the proof. +Ravenline is a fictional small parcel-logistics SaaS (~20 people) used as the running example for the Guildhall design (`docs/plans/2026-07-10-guilds-skills-standards-design.md`). It exists to demo the model end to end and to test future Guildhall features against. Everything here uses **built-in kinds plus the shipped `Cycle`/`Saga`** — the design introduces no new custom kinds, and this seed is the proof. ## The cast @@ -15,15 +15,15 @@ Ravenline is a fictional small parcel-logistics SaaS (~20 people) used as the ru `tracking-api` is enrolled in both aspects (`siliconsaga.org/aspects` annotation) and sits at **silver** on the security standard. `carrier-gateway` is enrolled in security only and is stuck at **bronze** with the `dependency-scanning` trial failing — its remediation doc says, in full: *add the one-line include of the paved-road pipeline template.* That is the paved-road loop from design §3.4, frozen as demo data. Meanwhile the `dependency-scanning-drive` Cycle is the security gildi's time-bound push to get every service's scanning green, and the release Saga cites how the release went. -## Practice-layer files (not catalog entities — future plugin input) +## Guildhall files (not catalog entities — future plugin input) -The `practice-layer/` and `repos/` trees are **plain YAML/markdown, deliberately not ingested**. They document the exact shapes design §5 assigns to vocabularies and Git-backed standards, so future plugins have fixtures waiting: +The `guildhall/` and `repos/` trees are **plain YAML/markdown, deliberately not ingested**. They document the exact shapes design §5 assigns to vocabularies and Git-backed standards, so future plugins have fixtures waiting (paths inside them are file-relative): -- `practice-layer/skills.yaml` — the skill vocabulary + mock profile selections (in the real system, profiles live in the plugin store and decorate `User` entities). -- `practice-layer/crafts.yaml` — `release-captain` (skills + a teaching vísir) and `incident-commander` (skills only — vísar are optional). -- `practice-layer/aspects.yaml` — `security` (steward gildi + home repo + standard) and `operational-readiness` (**no steward** — an aspect can exist before a gildi forms around it). -- `practice-layer/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 a remediation ref), the paved road (`pipeline-templates/dependency-scan.yml`), a teaching vísir (`docs/`), and a parameterized operational vísir (`runbooks/`). +- `guildhall/skills.yaml` — the skill vocabulary + mock profile selections (in the real system, profiles live in the plugin store and decorate `User` entities). +- `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. ## What ingests, what waits diff --git a/examples/mock-org/practice-layer/aspects.yaml b/examples/mock-org/guildhall/aspects.yaml similarity index 75% rename from examples/mock-org/practice-layer/aspects.yaml rename to examples/mock-org/guildhall/aspects.yaml index cd07f6b..99d9782 100644 --- a/examples/mock-org/practice-layer/aspects.yaml +++ b/examples/mock-org/guildhall/aspects.yaml @@ -1,16 +1,16 @@ # Aspect vocabulary — the cross-cutting concerns (design §3.2): each holds # standards applied to enrolled entities. Vocabulary-first; NOT catalog # entities. Enrollment is the siliconsaga.org/aspects annotation on the -# enrolled entity (see ../software.yaml). +# enrolled entity (see ../software.yaml). Paths are relative to THIS file. aspects: - id: security description: Services uphold the security bar; the gildi ships the paved road that clears it. steward: group:default/security-gildi - home: ./repos/security-practice + home: ../repos/security-practice standards: - - ./repos/security-practice/standard.yaml + - ../repos/security-practice/standard.yaml - id: operational-readiness description: Releases and services are ready to run — the software twin of season-readiness. steward: null # an aspect can exist before a gildi forms around it (design §3.2) standards: - - ./practice-layer/standards/release-readiness.yaml + - ./standards/release-readiness.yaml diff --git a/examples/mock-org/practice-layer/crafts.yaml b/examples/mock-org/guildhall/crafts.yaml similarity index 86% rename from examples/mock-org/practice-layer/crafts.yaml rename to examples/mock-org/guildhall/crafts.yaml index fbb3359..a62d97c 100644 --- a/examples/mock-org/practice-layer/crafts.yaml +++ b/examples/mock-org/guildhall/crafts.yaml @@ -5,8 +5,8 @@ crafts: - id: release-captain description: Runs a release Cycle end to end — coordinates the cut, watches the rollout, calls the rollback. skills: [ci-pipelines, incident-command] - visar: - - ./repos/handbook/docs/release-captain-guide.md + visar: # paths relative to THIS file + - ../repos/handbook/docs/release-captain-guide.md - id: incident-commander description: Owns an active incident — coordinates responders, communicates status, runs the retro. skills: [incident-command, kubernetes] diff --git a/examples/mock-org/practice-layer/skills.yaml b/examples/mock-org/guildhall/skills.yaml similarity index 100% rename from examples/mock-org/practice-layer/skills.yaml rename to examples/mock-org/guildhall/skills.yaml diff --git a/examples/mock-org/practice-layer/standards/release-readiness.yaml b/examples/mock-org/guildhall/standards/release-readiness.yaml similarity index 75% rename from examples/mock-org/practice-layer/standards/release-readiness.yaml rename to examples/mock-org/guildhall/standards/release-readiness.yaml index 9b090f9..a9e39da 100644 --- a/examples/mock-org/practice-layer/standards/release-readiness.yaml +++ b/examples/mock-org/guildhall/standards/release-readiness.yaml @@ -2,6 +2,7 @@ # software twin of the community season-readiness checklist (design §3.4). # Git-backed YAML in the shape design §5 assigns; consumed by the future # scorecard plugin. Single tier: readiness is pass/fail, not a ladder. +# Paths are relative to THIS file. standard: id: release-readiness aspect: operational-readiness @@ -12,12 +13,12 @@ standard: - id: release-captain-named rule: the Cycle's craft call for release-captain is filled factSource: muster-store # Phase 4 marketplace store - remediation: ./repos/handbook/docs/release-captain-guide.md + remediation: ../../repos/handbook/docs/release-captain-guide.md - 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/runbooks/queue-backlog.md # exemplar - id: previous-cycle-saga-exists rule: the previous release Cycle has at least one Saga factSource: catalog - remediation: ./repos/handbook/docs/release-captain-guide.md + remediation: ../../repos/handbook/docs/release-captain-guide.md # step 5: nudge a skald diff --git a/examples/mock-org/org.yaml b/examples/mock-org/org.yaml index fc1a619..825f454 100644 --- a/examples/mock-org/org.yaml +++ b/examples/mock-org/org.yaml @@ -5,7 +5,7 @@ apiVersion: backstage.io/v1alpha1 kind: Group metadata: name: ravenline - description: Ravenline — parcel-logistics SaaS (mock org, practice-layer demo) + description: Ravenline — parcel-logistics SaaS (mock org, Guildhall demo) spec: type: organization children: [rl-engineering, security-gildi, release-captains-gildi] @@ -30,7 +30,7 @@ kind: Group metadata: { name: team-platform } spec: { type: team, parent: rl-engineering, children: [] } --- -# Gildi — the fellowship form of the practice layer (design §3.2/§5): plain +# 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. apiVersion: backstage.io/v1alpha1 @@ -58,7 +58,7 @@ spec: children: [] --- # People — membership carries both team and gildi affiliation via memberOf. -# Skill profiles are NOT entity fields: see practice-layer/skills.yaml. +# Skill profiles are NOT entity fields: see guildhall/skills.yaml. apiVersion: backstage.io/v1alpha1 kind: User metadata: { name: astrid, description: 'Platform engineer, security-inclined' } diff --git a/examples/mock-org/repos/handbook/docs/release-captain-guide.md b/examples/mock-org/repos/handbook/docs/release-captain-guide.md index 9147b21..2d9dc41 100644 --- a/examples/mock-org/repos/handbook/docs/release-captain-guide.md +++ b/examples/mock-org/repos/handbook/docs/release-captain-guide.md @@ -1,6 +1,6 @@ # Release captain's guide -*Teaching vísir (craft-scoped): the guide handed to whoever answers the release-captain call. Referenced by `practice-layer/crafts.yaml`.* +*Teaching vísir (craft-scoped): the guide handed to whoever answers the release-captain call. Referenced by `guildhall/crafts.yaml`.* You're captaining a release Cycle. The job is coordination, not heroics: diff --git a/examples/mock-org/repos/security-practice/docs/security-contact.md b/examples/mock-org/repos/security-practice/docs/security-contact.md new file mode 100644 index 0000000..c52c6b2 --- /dev/null +++ b/examples/mock-org/repos/security-practice/docs/security-contact.md @@ -0,0 +1,13 @@ +# Declare a security contact — how to satisfy the trial + +*Teaching vísir (static, docs-homed). Remediation target of the `security-contact-declared` trial.* + +Add the contact annotation to your component's `catalog-info.yaml`: + +```yaml +metadata: + annotations: + siliconsaga.org/security-contact: group:default/team-shipping # or a User ref +``` + +Point it at whoever should hear about findings first — usually the owning team, sometimes a named individual. The trial flips green on the next catalog refresh. If nobody obvious exists, ask in `#security-gildi`: naming a reluctant contact beats having none. diff --git a/examples/mock-org/repos/security-practice/docs/threat-modeling.md b/examples/mock-org/repos/security-practice/docs/threat-modeling.md new file mode 100644 index 0000000..6a407e2 --- /dev/null +++ b/examples/mock-org/repos/security-practice/docs/threat-modeling.md @@ -0,0 +1,10 @@ +# Threat modeling — how to satisfy the trial + +*Teaching vísir (static, docs-homed). Remediation target of the `threat-model-current` trial.* + +The gold-tier bar: a threat model on file in this practice repo (`threat-models/.md`), reviewed within the last year. + +1. Book a one-hour session with a security gildi member (`#security-gildi`) — the gildi facilitates, your team brings the system knowledge. +2. Work the four questions: what are we building, what can go wrong, what are we doing about it, did we do enough? +3. Commit the result to `threat-models/` and link it from your component's docs. +4. Reviews are yearly and lightweight — a diff of what changed, not a redo. The trial reads the file's last-reviewed date. diff --git a/examples/mock-org/repos/security-practice/runbooks/rotate-leaked-credential.md b/examples/mock-org/repos/security-practice/runbooks/rotate-leaked-credential.md index 6e9eea9..17132fc 100644 --- a/examples/mock-org/repos/security-practice/runbooks/rotate-leaked-credential.md +++ b/examples/mock-org/repos/security-practice/runbooks/rotate-leaked-credential.md @@ -8,15 +8,17 @@ command below copy-pastes exactly right for the incident at hand. --> **When:** secret scanning flags a credential in `{{service}}`'s history, or one is reported leaked. 1. Revoke the credential at its source immediately — before cleanup, before comms. -2. Issue the replacement and store it: +2. Issue the replacement and store it — via stdin, so the new secret never lands in shell history or the process list: - ``` - bao kv put secret/{{secret_path}} value= + ```bash + read -rs NEW_CREDENTIAL + printf %s "$NEW_CREDENTIAL" | bao kv put secret/{{secret_path}} value=- + unset NEW_CREDENTIAL ``` 3. Restart the consuming workload so it picks up the new value: - ``` + ```bash kubectl --context {{cluster}} -n {{namespace}} rollout restart deploy/{{service}} ``` diff --git a/examples/mock-org/repos/security-practice/standard.yaml b/examples/mock-org/repos/security-practice/standard.yaml index f52f5db..93429ad 100644 --- a/examples/mock-org/repos/security-practice/standard.yaml +++ b/examples/mock-org/repos/security-practice/standard.yaml @@ -24,14 +24,14 @@ standard: - id: no-critical-vulns-30d rule: no critical finding older than 30 days factSource: ci-pipeline-results - remediation: ./docs/dependency-scanning.md + remediation: ./docs/dependency-scanning.md # the 30-day clock is documented there - id: security-contact-declared rule: the Component declares a security contact factSource: catalog-annotations - remediation: ./docs/dependency-scanning.md + remediation: ./docs/security-contact.md - name: gold trials: - id: threat-model-current rule: a threat model is on file and reviewed within the last year factSource: practice-home-repo - remediation: ./docs/dependency-scanning.md + remediation: ./docs/threat-modeling.md diff --git a/examples/mock-org/repos/tracking-api/runbooks/queue-backlog.md b/examples/mock-org/repos/tracking-api/runbooks/queue-backlog.md index c80a45a..014bfa8 100644 --- a/examples/mock-org/repos/tracking-api/runbooks/queue-backlog.md +++ b/examples/mock-org/repos/tracking-api/runbooks/queue-backlog.md @@ -8,7 +8,7 @@ incident where these commands lived in one engineer's head. --> 1. Confirm it's consumption, not a poison message — check the consumer error rate: - ``` + ```bash kubectl --context {{cluster}} -n {{namespace}} logs deploy/tracking-consumer --since=10m ``` @@ -16,7 +16,7 @@ incident where these commands lived in one engineer's head. --> 2. Scale out the consumers: - ``` + ```bash kubectl --context {{cluster}} -n {{namespace}} scale deploy/tracking-consumer --replicas=6 ``` diff --git a/scripts/smoke-catalog.sh b/scripts/smoke-catalog.sh index c2b28a5..9ed0dec 100644 --- a/scripts/smoke-catalog.sh +++ b/scripts/smoke-catalog.sh @@ -60,8 +60,13 @@ byname() { curl -fsS --connect-timeout 3 --max-time 5 "${hdr[@]}" "http://localh # Backend readiness != catalog-ingestion readiness. Poll until the custom entities # appear (or the timeout expires) rather than sleeping once and querying once. +# 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='{}' +deadline=$((SECONDS + 300)) for _ in $(seq 1 120); do + if (( SECONDS >= deadline )); then break; fi CYCLE="$(byname cycle/default/soccer-2026-spring)" SAGA="$(byname saga/default/saga-soccer-2026-spring)" GROUP="$(byname group/default/mtl)" @@ -104,7 +109,7 @@ check_rel "Saga ownedBy skald (guest)" "$SAGA" ownedBy user:default/gues check_rel "Saga ownedBy owner (mtl-soccer)" "$SAGA" ownedBy group:default/mtl-soccer || pass=0 check_rel "Saga dependsOn Cycle (touches)" "$SAGA" dependsOn cycle:default/soccer-2026-spring || pass=0 check "Saga doc annotation preserved" "$SAGA" 'siliconsaga.org/saga-doc' || pass=0 -# Mock software org (Ravenline — practice-layer running example): the software +# Mock software org (Ravenline — Guildhall running example): the software # side of the two-family model plus a gildi-typed Group, ingesting with the # same machinery and zero new code. check "Ravenline Cycle ingested (release)" "$RLCYCLE" '"type":"release"' || pass=0 @@ -115,9 +120,9 @@ check "Ravenline Saga ingested" "$RLSAGA" '"kind":"Saga"' 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 -# Surface any catalog processing errors for the seed. -echo "--- catalog errors mentioning mtl/cycle/saga (if any) ---" -grep -iE "error|InputError|Unable to read" "$LOG" 2>/dev/null | grep -iE "mtl|cycle|saga" | tail -20 || true +# Surface any catalog processing errors for the seeds (MTL + Ravenline). +echo "--- catalog errors mentioning the seeds (if any) ---" +grep -iE "error|InputError|Unable to read" "$LOG" 2>/dev/null | grep -iE "mtl|cycle|saga|ravenline|tracking|gildi|mock-org" | tail -20 || true echo "(end errors)" # Backend teardown is handled by the EXIT trap registered above. From 1ee1d51d47b0dc445b0973f1e2165fd88fc672cf Mon Sep 17 00:00:00 2001 From: Cervator Date: Sat, 11 Jul 2026 15:58:23 -0400 Subject: [PATCH 7/8] docs: ADR 0009 (Guildhall model) + CR #5 review round 2 MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit ADR 0009 distills the durable decisions of this arc into the MADR set: the Guildhall name (practice-layer rejected for its verb reading), the craft-vs-aspect split, aspects holding standards and shipping the paved road, the no-new-kinds mapping, and the kennings display layer. The design doc stays the deep treatment — the ADR is the compact record. Review round 2 fixes (CodeRabbit): - security-contact.md no longer claims trials evaluate today — the flip-green behavior is described as shipping with the future scorecard plugin, consistent with the mock-org README's honesty line. - rotate-leaked-credential.md guards against storing a blank credential (read -rs accepts an empty line) and its header now states the render-time requirement the injection finding surfaced. - That requirement is promoted to the design doc's section 8 runbooks open question as a hard constraint: URL-sourced placeholder values must be allowlist-validated and shell-escaped before interpolation, so a crafted link can never turn a copied command into an injection. - Declined the outside-diff "siconsaga.org/stewards typo" finding: verified via git grep that both the working tree and the pushed commit read siliconsaga.org/stewards — the claim does not match the code. Also folds in a kennings note from review discussion: corporate lexicons can slot in house terms like Center of Excellence for gildi where the org already speaks them. Co-Authored-By: Claude Fable 5 --- docs/adrs/0009-guildhall-practice-model.md | 29 +++++++++++++++++++ docs/adrs/README.md | 1 + ...26-07-10-guilds-skills-standards-design.md | 4 +-- .../docs/security-contact.md | 2 +- .../runbooks/rotate-leaked-credential.md | 6 +++- 5 files changed, 38 insertions(+), 4 deletions(-) create mode 100644 docs/adrs/0009-guildhall-practice-model.md diff --git a/docs/adrs/0009-guildhall-practice-model.md b/docs/adrs/0009-guildhall-practice-model.md new file mode 100644 index 0000000..7c0191e --- /dev/null +++ b/docs/adrs/0009-guildhall-practice-model.md @@ -0,0 +1,29 @@ +# Guildhall: the practice model — aspects hold standards, guilds are people, no new kinds + +- Status: accepted +- Date: 2026-07-11 +- Deciders: Cervator, Claude (Fable 5) + +## Context and Problem Statement + +Spotify's premium **Skill Exchange** (skills on user profiles, opportunity marketplace) and **Soundcheck** (facts → checks → levels → tracks, bronze/silver/gold) ship as unconnected products, and "practice" — the concept that would unify them — reads as a verb half the time. We need one model covering skills, staffing bundles, communities of practice, maturity measurement, and procedure docs, for both the community domain and software, without inventing catalog machinery. + +## Considered Options + +- Two independent systems (skills marketplace + maturity engine), linked by convention — the Spotify shape. +- A practice-as-hub model where one "guild" concept owns people, processes, and measurement. +- The hub model **split by role**: fellowship vs. cross-cutting concern as distinct concepts. + +## Decision Outcome + +Chosen: the split hub model, named the **Guildhall** (norse kenning skin *Gildaskáli*; "practice layer" was rejected for its verb reading). Concepts: **Skill** (unowned shared vocabulary on people, have/learning axis) · **Craft** (demand-side skill bundle a muster calls for) · **Gildi** (the fellowship — purely people, craft- or aspect-aligned) · **Aspect** (the cross-cutting concern, AOP sense — it **holds the Standards** and ships both the bar and the paved road to clear it) · **Standard → Trials** (tiered checks; every trial declares a remediation **vísir**) · **Vísir** (procedure doc; teaching grade in `/docs`, operational parameterized grade in `/runbooks`). The split that carries the model: *crafts are what people do; aspects are what things must uphold.* + +Mapping introduces **no new custom kinds**: gildi = `Group` with `spec.type: gildi`; skills/crafts/aspects = vocabularies; standards = Git-backed YAML for the future scorecard plugin (Tech Insights evaluated first); vísar = annotation-referenced Git markdown; enrollment = `siliconsaga.org/aspects` annotation. A **kennings layer** maps canonical technical terms to per-instance display lexicons (norse/plain/custom — e.g. corporate "Practice Hub"), which keeps parent-facing surfaces on plain language by construction. + +### Consequences + +- Good: the Ravenline seed (`examples/mock-org/`) ingests with zero new code — the no-new-kinds claim is demonstrated, and the vocabulary/standard files are frozen fixtures for Phase 6. +- Trial evaluation, skill profiles, scorecards, and the runbooks plugin are **not built** — this ADR fixes vocabulary and shapes only. +- Open items live in the design doc §8: aspect kenning skin (*þáttr* rejected — Danish false-friend), vísir grade term split, tier ordering, runbooks-plugin parameter safety. + +See the design: [`../plans/2026-07-10-guilds-skills-standards-design.md`](../plans/2026-07-10-guilds-skills-standards-design.md), and ADRs [0007](0007-cycle-custom-kind.md)/[0008](0008-saga-git-backed-kind.md) for the kinds it builds on. diff --git a/docs/adrs/README.md b/docs/adrs/README.md index de000e1..568590b 100644 --- a/docs/adrs/README.md +++ b/docs/adrs/README.md @@ -19,3 +19,4 @@ annotation. Until then they live here as plain Markdown. | [0006](0006-bdd-from-day-one.md) | BDD from day one over TDD'd tooling | | [0007](0007-cycle-custom-kind.md) | Cycle: a custom catalog kind for bounded groupings | | [0008](0008-saga-git-backed-kind.md) | Saga: a Git-backed catalog kind for narrated effort records | +| [0009](0009-guildhall-practice-model.md) | Guildhall: the practice model — aspects hold standards, guilds are people, no new kinds | 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 66d3c68..5c605e4 100644 --- a/docs/plans/2026-07-10-guilds-skills-standards-design.md +++ b/docs/plans/2026-07-10-guilds-skills-standards-design.md @@ -85,7 +85,7 @@ Technical identifiers commit to **one canonical vocabulary** (below). The UI nev - Ships with two built-in lexicons: **norse** (Gildi, Vísir, Trial, Saga…) and **plain** (Guild, Guide/Runbook, Check, Report…), selected per instance in app-config. - A per-user lexicon preference is a **later enhancement** (Backstage user settings can hold it), not a launch requirement. - The parent-facing Ting surface pins the **plain** lexicon — satisfying the realm Tone Guide with zero special-casing. -- A corporate instance can pin its own custom lexicon (Practice, Grid, Check) over the identical model — same bones, different skin. +- A corporate instance can pin its own custom lexicon (Practice, Grid, Check) over the identical model — same bones, different skin. House terms slot in wherever the org already speaks them — e.g. "Center of Excellence" for gildi, if that term isn't already overloaded locally. ### Canonical vocabulary @@ -143,4 +143,4 @@ Follows the established discipline: no kind introduced merely to filter; nothing - **Ordered levels vs. unordered blocks** inside a standard: Soundcheck levels are strictly sequential; the day-job Blocks are thematic groupings. Decide when the scorecard plugin is built (Tech Insights' model may decide it for us). - **Where craft and aspect definitions live** long-term if matching/enrollment gets real (vocabulary → entity promotion path). - **Kennings scope**: exact config shape, and whether spec *field* names (not just kind/type display) participate in display mapping. -- **Runbooks plugin shape**: parameter syntax, URL-parameter contract, and how `/runbooks` coexists with TechDocs (separate renderer vs. TechDocs extension). +- **Runbooks plugin shape**: parameter syntax, URL-parameter contract, and how `/runbooks` coexists with TechDocs (separate renderer vs. TechDocs extension). **Parameter safety is a hard requirement** (surfaced in CR #5 review): placeholder values arrive via URL, so the renderer must allowlist-validate and shell-escape them before interpolating into commands — a crafted link must never turn a copy-pasted command into an injection. diff --git a/examples/mock-org/repos/security-practice/docs/security-contact.md b/examples/mock-org/repos/security-practice/docs/security-contact.md index c52c6b2..05cd719 100644 --- a/examples/mock-org/repos/security-practice/docs/security-contact.md +++ b/examples/mock-org/repos/security-practice/docs/security-contact.md @@ -10,4 +10,4 @@ metadata: siliconsaga.org/security-contact: group:default/team-shipping # or a User ref ``` -Point it at whoever should hear about findings first — usually the owning team, sometimes a named individual. The trial flips green on the next catalog refresh. If nobody obvious exists, ask in `#security-gildi`: naming a reluctant contact beats having none. +Point it at whoever should hear about findings first — usually the owning team, sometimes a named individual. The trial is designed to flip green on the next catalog refresh (evaluation ships with the future scorecard plugin — see the mock-org README). If nobody obvious exists, ask in `#security-gildi`: naming a reluctant contact beats having none. diff --git a/examples/mock-org/repos/security-practice/runbooks/rotate-leaked-credential.md b/examples/mock-org/repos/security-practice/runbooks/rotate-leaked-credential.md index 17132fc..e349732 100644 --- a/examples/mock-org/repos/security-practice/runbooks/rotate-leaked-credential.md +++ b/examples/mock-org/repos/security-practice/runbooks/rotate-leaked-credential.md @@ -3,7 +3,10 @@ +command below copy-pastes exactly right for the incident at hand. +Plugin requirement (design §8): placeholder values come from URLs, so the +renderer MUST allowlist-validate and shell-escape them before interpolation — +a crafted link must not be able to turn a copied command into an injection. --> **When:** secret scanning flags a credential in `{{service}}`'s history, or one is reported leaked. @@ -12,6 +15,7 @@ command below copy-pastes exactly right for the incident at hand. --> ```bash read -rs NEW_CREDENTIAL + [ -n "$NEW_CREDENTIAL" ] || { echo "empty input — aborting, nothing stored"; unset NEW_CREDENTIAL; exit 1; } printf %s "$NEW_CREDENTIAL" | bao kv put secret/{{secret_path}} value=- unset NEW_CREDENTIAL ``` From c2c592a29fc16ae4b89b7f1c4a17385f82094558 Mon Sep 17 00:00:00 2001 From: Cervator Date: Sat, 11 Jul 2026 16:59:05 -0400 Subject: [PATCH 8/8] =?UTF-8?q?docs(examples):=20harden=20rotate-credentia?= =?UTF-8?q?l=20runbook=20=E2=80=94=20verbatim=20read,=20abort=20on=20faile?= =?UTF-8?q?d=20store?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit CR #5 review round 3 (CodeRabbit, both valid): IFS= read -r -s reads the replacement credential verbatim (plain read -rs still lets IFS trim leading/trailing whitespace), and a failed bao kv put now aborts the runbook before the unset and restart steps — the dangerous state is precisely "old credential revoked, no replacement stored," so falling through to the rollout restart would be the worst move. Co-Authored-By: Claude Fable 5 --- .../security-practice/runbooks/rotate-leaked-credential.md | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/examples/mock-org/repos/security-practice/runbooks/rotate-leaked-credential.md b/examples/mock-org/repos/security-practice/runbooks/rotate-leaked-credential.md index e349732..9e52d42 100644 --- a/examples/mock-org/repos/security-practice/runbooks/rotate-leaked-credential.md +++ b/examples/mock-org/repos/security-practice/runbooks/rotate-leaked-credential.md @@ -14,9 +14,10 @@ a crafted link must not be able to turn a copied command into an injection. --> 2. Issue the replacement and store it — via stdin, so the new secret never lands in shell history or the process list: ```bash - read -rs NEW_CREDENTIAL + IFS= read -r -s NEW_CREDENTIAL [ -n "$NEW_CREDENTIAL" ] || { echo "empty input — aborting, nothing stored"; unset NEW_CREDENTIAL; exit 1; } - printf %s "$NEW_CREDENTIAL" | bao kv put secret/{{secret_path}} value=- + printf %s "$NEW_CREDENTIAL" | bao kv put secret/{{secret_path}} value=- \ + || { echo "store FAILED — stop here: the old credential is revoked and no replacement is stored"; unset NEW_CREDENTIAL; exit 1; } unset NEW_CREDENTIAL ```