From 00469c4cc0ba7308743ff7bfcf4e5556fad79fba Mon Sep 17 00:00:00 2001 From: tegwick Date: Sat, 23 May 2026 21:52:59 +0200 Subject: [PATCH 01/10] Adopt whynot-design tokens (WP-0017 Phase 1) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Replace vergabe's blue brand-* palette with whynot's near-black/paper/yellow visual language. Tokens vendored at static/src/vendor/whynot-design/ (synced from commit 9419f16 via scripts/sync-whynot-design.sh / make sync-whynot-design). main.css imports the vendored CSS first, exposes ink/paper/hi as Tailwind @theme tokens (bg-paper, text-ink, border-line, etc.), and re-tones every component class (.btn-*, .card, .field-row, .phase-*, .form-input, .table-*, .sidebar-*). Border radii drop to whynot's 0-4px; .card loses its shadow. Legacy text-brand-* / bg-brand-* / border-brand-* template references are kept working via @theme aliases that map the old blue scale onto the whynot ink ramp — Phase 1 is tokens-only, no template churn. btn-danger keeps an off-spec red (#B22222) as a local --danger var until upstream defines a canonical destructive color. base.html body class swapped: bg-slate-50 → bg-paper-2 text-ink. Phase 2 (component adoption) deferred until whynot-design ships Lit web components + missing atoms (Card, Modal, Input, Table, Toast). See wiki/DesignSystem.md and history/2026-05-23-whynot-design-cross-framework-analysis.md. Verified: 8/8 e2e tests pass; dev server boots; static/dist/main.css contains no #3b5bdb references. Visual pixel-level verification still pending Bernd's browser walk. --- .claude/rules/stack-and-commands.md | 29 +- Makefile | 5 +- scripts/sync-whynot-design.sh | 39 +++ static/src/main.css | 112 +++++-- .../vendor/whynot-design/.whynot-design-ref | 1 + .../vendor/whynot-design/colors_and_type.css | 273 ++++++++++++++++++ .../vendor/whynot-design/tokens/colors.json | 22 ++ .../vendor/whynot-design/tokens/index.json | 6 + .../vendor/whynot-design/tokens/spacing.json | 28 ++ .../src/vendor/whynot-design/tokens/type.json | 33 +++ vergabe_teilnahme/templates/base.html | 2 +- wiki/DesignSystem.md | 50 ++++ workplans/WP-0017-whynot-design-tokens.md | 14 +- 13 files changed, 566 insertions(+), 48 deletions(-) create mode 100755 scripts/sync-whynot-design.sh create mode 100644 static/src/vendor/whynot-design/.whynot-design-ref create mode 100644 static/src/vendor/whynot-design/colors_and_type.css create mode 100644 static/src/vendor/whynot-design/tokens/colors.json create mode 100644 static/src/vendor/whynot-design/tokens/index.json create mode 100644 static/src/vendor/whynot-design/tokens/spacing.json create mode 100644 static/src/vendor/whynot-design/tokens/type.json create mode 100644 wiki/DesignSystem.md diff --git a/.claude/rules/stack-and-commands.md b/.claude/rules/stack-and-commands.md index dc53ac6..bc54d15 100644 --- a/.claude/rules/stack-and-commands.md +++ b/.claude/rules/stack-and-commands.md @@ -1,19 +1,32 @@ ## Stack - -- **Language:** -- **Key deps:** +- **Language:** Python 3.12 (Django 6), Node 22 (Vite + Tailwind v4) +- **Key deps:** Django, htmx, Alpine.js, Tailwind v4, whynot-design (vendored + under `static/src/vendor/whynot-design/`) ## Dev Commands ```bash -# TODO: Fill in the standard commands for this repo - # Install dependencies +uv sync # Python +npm ci # Node (Vite/Tailwind) -# Run tests +# Run dev stack +make db # Start postgres if not running +make dev # Django runserver on :9000 +make css # Tailwind/Vite watcher (rebuilds main.css) -# Lint / type check +# Build CSS bundle for prod / for verification +npm run build # → static/dist/main.css -# Build / package (if applicable) +# Re-vendor the whynot-design system from a pinned upstream commit +make sync-whynot-design # reads .whynot-design-ref by default + # or: ./scripts/sync-whynot-design.sh + +# Tests / lint +make test # uv run pytest +make lint # ruff + mypy ``` + +See `wiki/DesignSystem.md` for the whynot-design adoption status (Phase 1 +tokens+CSS done; Phase 2 components deferred) and local style conventions. diff --git a/Makefile b/Makefile index b36abe2..2e2931a 100644 --- a/Makefile +++ b/Makefile @@ -1,4 +1,4 @@ -.PHONY: help db dev css seed migrate test lint shell superuser collectstatic +.PHONY: help db dev css seed migrate test lint shell superuser collectstatic sync-whynot-design .DEFAULT_GOAL := help @@ -41,3 +41,6 @@ shell: ## Open a Django shell (shell_plus if available) collectstatic: ## Collect static files into staticfiles/ (production step) uv run manage.py collectstatic --noinput + +sync-whynot-design: ## Re-vendor whynot-design CSS+tokens from the pinned ref + ./scripts/sync-whynot-design.sh diff --git a/scripts/sync-whynot-design.sh b/scripts/sync-whynot-design.sh new file mode 100755 index 0000000..2ec8a01 --- /dev/null +++ b/scripts/sync-whynot-design.sh @@ -0,0 +1,39 @@ +#!/usr/bin/env bash +# Synchronises the vendored copy of the whynot-design system from a pinned +# upstream commit. Source: ~/whynot-design (worktree) or a clone from gitea. +# +# Usage: ./scripts/sync-whynot-design.sh [] +# Default: reads .whynot-design-ref from the vendor directory. +# +# See workplans/WP-0017-whynot-design-tokens.md for the adoption strategy. +set -euo pipefail + +ROOT="$(cd "$(dirname "${BASH_SOURCE[0]}")/.." && pwd)" +VENDOR_DIR="$ROOT/static/src/vendor/whynot-design" +REF_FILE="$VENDOR_DIR/.whynot-design-ref" +SRC_REPO="${WHYNOT_DESIGN_SRC:-$HOME/whynot-design}" + +REF="${1:-}" +if [[ -z "$REF" && -f "$REF_FILE" ]]; then + REF="$(cat "$REF_FILE")" +fi +if [[ -z "$REF" ]]; then + echo "Usage: $0 (or write a ref to $REF_FILE)" >&2 + exit 2 +fi + +if [[ ! -d "$SRC_REPO/.git" ]]; then + echo "Source not found: $SRC_REPO" >&2 + echo "Set WHYNOT_DESIGN_SRC or clone gitea:whynot/whynot-design there." >&2 + exit 1 +fi + +mkdir -p "$VENDOR_DIR/tokens" +git -C "$SRC_REPO" show "$REF:src/styles/colors_and_type.css" \ + > "$VENDOR_DIR/colors_and_type.css" +for f in colors.json type.json spacing.json index.json; do + git -C "$SRC_REPO" show "$REF:tokens/$f" > "$VENDOR_DIR/tokens/$f" +done +git -C "$SRC_REPO" rev-parse "$REF" > "$REF_FILE" + +echo "Vendor synced → $VENDOR_DIR (ref: $(cat "$REF_FILE"))" diff --git a/static/src/main.css b/static/src/main.css index bc4d68e..b2eb910 100644 --- a/static/src/main.css +++ b/static/src/main.css @@ -1,3 +1,9 @@ +/* whynot-design tokens & semantic element styles (pinned via + scripts/sync-whynot-design.sh; see .whynot-design-ref). + Must precede the Tailwind import so the @import url(...) for IBM Plex + ends up at the top of the generated bundle. */ +@import "./vendor/whynot-design/colors_and_type.css"; + @import "tailwindcss"; /* Explicit content sources. Without these, Tailwind's automatic detection @@ -7,44 +13,88 @@ template dirs copied in the Dockerfile `assets` stage. */ @source "../../vergabe_teilnahme/templates"; +/* whynot tokens → Tailwind theme. Exposes utilities like bg-paper, text-ink, + border-line, bg-paper-2, text-ink-3, … */ @theme { - --color-brand-50: #f0f4ff; - --color-brand-100: #dce7ff; - --color-brand-500: #3b5bdb; - --color-brand-600: #2f4ac7; - --color-brand-700: #2541b2; - --color-brand-900: #152d99; + --color-ink: #0A0A0A; + --color-ink-2: #1F1F1F; + --color-ink-3: #5C5C5C; + --color-ink-4: #8A8A8A; + --color-ink-5: #B5B5B3; + --color-line: #E5E5E2; + --color-line-strong: #C9C9C5; + --color-line-soft: #F0F0EC; + --color-paper: #FFFFFF; + --color-paper-2: #FAFAF7; + --color-paper-3: #F4F4EF; + --color-hi: #FFE14A; + --color-hi-2: #FFD400; + --color-hi-ink: #1A1500; + + /* Backwards-compat aliases for legacy `brand-*` utility usage in templates. + Keeps Phase 1 a tokens-only swap; templates can migrate to ink/paper at + leisure. Map blue-brand scale onto the whynot ink ramp. */ + --color-brand-50: #FAFAF7; + --color-brand-100: #F4F4EF; + --color-brand-500: #0A0A0A; + --color-brand-600: #1F1F1F; + --color-brand-700: #0A0A0A; + --color-brand-900: #0A0A0A; +} + +/* Off-spec — vergabe-local until whynot-design defines a canonical + destructive color. See history/2026-05-23-whynot-design-cross-framework-analysis.md + §4 for context. */ +:root { + --danger: #B22222; + --danger-fg: #FFFFFF; } @layer base { - /* German-app base resets */ html { - font-family: ui-sans-serif, system-ui, sans-serif; + font-family: var(--ff-sans, ui-sans-serif), system-ui, sans-serif; } } @layer components { - .card { @apply bg-white rounded-xl border border-slate-200 shadow-sm p-6; } - .btn-primary { @apply bg-brand-500 text-white px-4 py-2 rounded-lg hover:bg-brand-600 transition-colors; } - .btn-secondary { @apply bg-white text-slate-700 border border-slate-300 px-4 py-2 rounded-lg hover:bg-slate-50; } - .btn-danger { @apply bg-red-600 text-white px-4 py-2 rounded-lg hover:bg-red-700; } - .btn-ghost { @apply text-slate-600 px-3 py-2 rounded-lg hover:bg-slate-100; } - .field-row { @apply grid grid-cols-3 gap-4 py-3 border-b border-slate-100 last:border-0; } - .field-label { @apply text-sm font-medium text-slate-500 col-span-1; } - .field-value { @apply text-sm text-slate-900 col-span-2; } - .phase-badge { @apply inline-flex items-center justify-center w-7 h-7 rounded-full text-sm font-bold; } - .phase-todo { @apply inline-flex items-center justify-center w-7 h-7 rounded-full text-sm font-bold bg-slate-200 text-slate-500; } - .phase-active { @apply inline-flex items-center justify-center w-7 h-7 rounded-full text-sm font-bold bg-brand-500 text-white; } - .phase-done { @apply inline-flex items-center justify-center w-7 h-7 rounded-full text-sm font-bold bg-green-500 text-white; } - .phase-warn { @apply inline-flex items-center justify-center w-7 h-7 rounded-full text-sm font-bold bg-amber-400 text-amber-900; } - .section-title { @apply text-base font-semibold text-slate-900 mb-4; } - .page-title { @apply text-2xl font-bold text-slate-900; } - .form-input { @apply w-full rounded-lg border border-slate-300 px-3 py-2 text-sm focus:outline-none focus:ring-2 focus:ring-brand-500 focus:border-transparent; } - .form-label { @apply block text-sm font-medium text-slate-700 mb-1; } - .table-base { @apply w-full text-sm text-left; } - .table-header { @apply bg-slate-50 text-slate-500 font-medium text-xs uppercase tracking-wide; } - .table-row { @apply border-t border-slate-100 hover:bg-slate-50 transition-colors; } - .sidebar-link { @apply flex items-center px-3 py-2 rounded-lg text-sm text-slate-700 hover:bg-slate-100 transition-colors; } - .sidebar-link-active { @apply bg-brand-50 text-brand-700 font-medium; } - .sidebar-section-btn { @apply w-full flex items-center justify-between px-3 py-2 text-xs font-semibold text-slate-500 uppercase tracking-wide hover:text-slate-700; } + /* Cards / sheets — whynot: no shadow, hairline border */ + .card { @apply bg-paper rounded border border-line p-6; } + + /* Buttons — whynot: 3 variants + off-spec danger */ + .btn-primary { @apply bg-ink text-paper px-4 py-2 rounded hover:bg-ink-2 transition-colors; } + .btn-secondary { @apply bg-paper text-ink border border-line px-4 py-2 rounded hover:bg-paper-2 transition-colors; } + .btn-ghost { @apply text-ink-3 px-3 py-2 rounded hover:bg-paper-2; } + .btn-danger { background: var(--danger); color: var(--danger-fg); @apply px-4 py-2 rounded transition-colors; } + .btn-danger:hover { filter: brightness(0.92); } + + /* Field-row — label/value grid */ + .field-row { @apply grid grid-cols-3 gap-4 py-3 border-b border-line-soft last:border-0; } + .field-label { @apply text-sm font-medium text-ink-3 col-span-1; } + .field-value { @apply text-sm text-ink col-span-2; } + + /* Phase indicators — vergabe semantics (todo/active/done/warn), translated + into whynot palette. `phase-warn` uses --hi (annotation yellow). */ + .phase-badge { @apply inline-flex items-center justify-center w-7 h-7 rounded-full text-sm font-bold; } + .phase-todo { @apply inline-flex items-center justify-center w-7 h-7 rounded-full text-sm font-bold bg-paper-3 text-ink-4; } + .phase-active { @apply inline-flex items-center justify-center w-7 h-7 rounded-full text-sm font-bold bg-ink text-paper; } + .phase-done { @apply inline-flex items-center justify-center w-7 h-7 rounded-full text-sm font-bold bg-ink-3 text-paper; } + .phase-warn { background: var(--hi); color: var(--hi-ink); @apply inline-flex items-center justify-center w-7 h-7 rounded-full text-sm font-bold; } + + /* Titles / sections */ + .section-title { @apply text-base font-semibold text-ink mb-4; } + .page-title { @apply text-2xl font-medium text-ink tracking-tight; } + + /* Forms */ + .form-input { @apply w-full rounded border border-line px-3 py-2 text-sm bg-paper focus:outline-none focus:border-ink transition-colors; } + .form-label { @apply block text-sm font-medium text-ink-2 mb-1; } + + /* Tables */ + .table-base { @apply w-full text-sm text-left; } + .table-header { @apply bg-paper-2 text-ink-3 font-medium text-xs uppercase tracking-wide; } + .table-row { @apply border-t border-line-soft hover:bg-paper-2 transition-colors; } + + /* Sidebar */ + .sidebar-link { @apply flex items-center px-3 py-2 rounded text-sm text-ink-2 hover:bg-paper-2 transition-colors; } + .sidebar-link-active { @apply bg-paper text-ink font-medium; box-shadow: inset 0 0 0 1px var(--line); } + .sidebar-section-btn { @apply w-full flex items-center justify-between px-3 py-2 text-xs font-semibold text-ink-4 uppercase tracking-wide hover:text-ink-2; } } diff --git a/static/src/vendor/whynot-design/.whynot-design-ref b/static/src/vendor/whynot-design/.whynot-design-ref new file mode 100644 index 0000000..8c65555 --- /dev/null +++ b/static/src/vendor/whynot-design/.whynot-design-ref @@ -0,0 +1 @@ +9419f166ce395858f55b10a5c72268a1fe9fc9d2 diff --git a/static/src/vendor/whynot-design/colors_and_type.css b/static/src/vendor/whynot-design/colors_and_type.css new file mode 100644 index 0000000..d64a8ff --- /dev/null +++ b/static/src/vendor/whynot-design/colors_and_type.css @@ -0,0 +1,273 @@ +/* ============================================================ + WhyNot Design System — Colors & Type + ------------------------------------------------------------ + Neutral, mostly black/white. Color is used SPARINGLY — only + one warm accent (annotation yellow) borrowed from the LEGO + brick in the logo. The system favours light grey wireframe + artefacts over heavy fills. + ============================================================ */ + +/* ---------- Webfonts (Google Fonts, see /fonts for offline) ---------- */ +@import url("https://fonts.googleapis.com/css2?family=IBM+Plex+Mono:wght@400;500;600&family=IBM+Plex+Sans:wght@300;400;500;600;700&family=IBM+Plex+Serif:ital,wght@0,400;0,500;1,400&display=swap"); + +:root { + /* ---------- Base palette: neutrals ---------- */ + --ink: #0A0A0A; /* near-black, the only "fill" most of the time */ + --ink-2: #1F1F1F; + --ink-3: #5C5C5C; + --ink-4: #8A8A8A; + --ink-5: #B5B5B3; /* placeholder text, wireframe labels */ + --line: #E5E5E2; /* default 1px wireframe rule */ + --line-strong: #C9C9C5; /* dividers between sections */ + --line-soft: #F0F0EC; /* hairline within a card */ + --paper: #FFFFFF; /* canvas */ + --paper-2: #FAFAF7; /* sheet, dim canvas */ + --paper-3: #F4F4EF; /* recessed surface, code block bg */ + + /* ---------- Foreground / background semantic ---------- */ + --fg-1: var(--ink); + --fg-2: var(--ink-3); + --fg-3: var(--ink-4); + --fg-mute: var(--ink-5); + --fg-on-dark: #FAFAF7; + + --bg-1: var(--paper); + --bg-2: var(--paper-2); + --bg-3: var(--paper-3); + --bg-invert: var(--ink); + + --border: var(--line); + --border-strong: var(--line-strong); + --border-soft: var(--line-soft); + + /* ---------- The single accent: annotation yellow ---------- */ + /* Lifted from the LEGO brick. Used as highlighter, "draft" + stamp, signal-marker. Never as a button fill. */ + --hi: #FFE14A; + --hi-2: #FFD400; + --hi-ink: #1A1500; /* text on yellow */ + + /* ---------- Status (for prototype lifecycle, signal strength) ---------- */ + /* Kept deliberately desaturated so they read as labels, not UI. */ + --status-raw: #B5B5B3; /* S0 — no signal */ + --status-weak: #8A8A8A; /* S1 — weak signal */ + --status-medium: #5C5C5C; /* S2 — medium signal */ + --status-strong: #0A0A0A; /* S3 — strong signal */ + --status-commercial: #FFD400; /* S4 — commercial */ + + /* ---------- Type families ---------- */ + --ff-sans: "IBM Plex Sans", ui-sans-serif, system-ui, sans-serif; + --ff-mono: "IBM Plex Mono", ui-monospace, "SF Mono", Menlo, monospace; + --ff-serif: "IBM Plex Serif", "Iowan Old Style", Georgia, serif; + + /* ---------- Type scale (modular, ~1.2) ---------- */ + --fs-xs: 11px; + --fs-sm: 13px; + --fs-base: 15px; + --fs-md: 17px; + --fs-lg: 20px; + --fs-xl: 24px; + --fs-2xl: 32px; + --fs-3xl: 44px; + --fs-4xl: 64px; + --fs-5xl: 96px; + + --lh-tight: 1.05; + --lh-snug: 1.25; + --lh-base: 1.5; + --lh-loose: 1.7; + + --tr-tight: -0.02em; + --tr-snug: -0.01em; + --tr-base: 0em; + --tr-mono: 0.02em; + --tr-label: 0.08em; /* uppercase eyebrow labels */ + + /* ---------- Spacing (4px base) ---------- */ + --sp-1: 4px; + --sp-2: 8px; + --sp-3: 12px; + --sp-4: 16px; + --sp-5: 24px; + --sp-6: 32px; + --sp-7: 48px; + --sp-8: 64px; + --sp-9: 96px; + --sp-10: 128px; + + /* ---------- Radii — small, mostly square ---------- */ + --r-0: 0px; + --r-1: 2px; + --r-2: 4px; + --r-3: 8px; + --r-pill: 999px; + + /* ---------- Elevation — almost none. This is a wireframe system. ---------- */ + --shadow-0: none; + --shadow-1: 0 1px 0 var(--line); + --shadow-2: 0 1px 0 var(--line-strong); + --shadow-3: 0 4px 12px -6px rgba(10,10,10,0.10); +} + +/* ============================================================ + Semantic element styles + ============================================================ */ + +html { + font-family: var(--ff-sans); + font-size: var(--fs-base); + line-height: var(--lh-base); + color: var(--fg-1); + background: var(--bg-1); + -webkit-font-smoothing: antialiased; + -moz-osx-font-smoothing: grayscale; + text-rendering: optimizeLegibility; +} + +body { + margin: 0; + font-feature-settings: "ss01", "cv11"; + text-wrap: pretty; +} + +/* ---------- Headings ---------- */ +h1, .h1 { + font: 600 var(--fs-3xl)/var(--lh-tight) var(--ff-sans); + letter-spacing: var(--tr-tight); + margin: 0 0 var(--sp-5); + color: var(--fg-1); +} +h2, .h2 { + font: 500 var(--fs-2xl)/var(--lh-snug) var(--ff-sans); + letter-spacing: var(--tr-snug); + margin: 0 0 var(--sp-4); +} +h3, .h3 { + font: 500 var(--fs-xl)/var(--lh-snug) var(--ff-sans); + letter-spacing: var(--tr-snug); + margin: 0 0 var(--sp-3); +} +h4, .h4 { + font: 500 var(--fs-lg)/var(--lh-snug) var(--ff-sans); + margin: 0 0 var(--sp-2); +} +h5, .h5 { + font: 500 var(--fs-md)/var(--lh-snug) var(--ff-sans); + margin: 0 0 var(--sp-2); +} + +/* ---------- Display (for hero / title slides) ---------- */ +.display-1 { + font: 300 var(--fs-5xl)/0.95 var(--ff-sans); + letter-spacing: -0.035em; + color: var(--fg-1); +} +.display-2 { + font: 400 var(--fs-4xl)/1.0 var(--ff-sans); + letter-spacing: var(--tr-tight); +} + +/* ---------- Body ---------- */ +p { + margin: 0 0 var(--sp-4); + line-height: var(--lh-base); + color: var(--fg-1); +} +.lead { + font-size: var(--fs-md); + line-height: 1.55; + color: var(--fg-2); +} +small, .small { + font-size: var(--fs-sm); + color: var(--fg-2); +} + +/* ---------- Eyebrow / uppercase labels (very common in this system) ---------- */ +.eyebrow, +.label { + font: 500 var(--fs-xs)/1.2 var(--ff-mono); + letter-spacing: var(--tr-label); + text-transform: uppercase; + color: var(--fg-3); +} + +/* ---------- Code / mono ---------- */ +code, kbd, samp, pre, .mono { + font-family: var(--ff-mono); + font-size: 0.92em; + letter-spacing: var(--tr-mono); +} +code { + background: var(--bg-3); + padding: 1px 6px; + border-radius: var(--r-1); + color: var(--ink-2); +} +pre { + background: var(--bg-3); + border: 1px solid var(--border); + padding: var(--sp-4); + overflow-x: auto; + border-radius: var(--r-2); + font-size: var(--fs-sm); + line-height: var(--lh-snug); +} +pre code { background: none; padding: 0; } + +/* ---------- Editorial serif moments ---------- */ +.serif { font-family: var(--ff-serif); } +.serif-quote { + font: 400 italic var(--fs-xl)/1.4 var(--ff-serif); + color: var(--fg-2); +} + +/* ---------- Links ---------- */ +a { + color: var(--fg-1); + text-decoration: underline; + text-decoration-color: var(--border-strong); + text-underline-offset: 3px; + text-decoration-thickness: 1px; + transition: text-decoration-color 120ms ease, color 120ms ease; +} +a:hover { + text-decoration-color: var(--fg-1); +} + +/* ---------- HR ---------- */ +hr { + border: 0; + border-top: 1px solid var(--border); + margin: var(--sp-5) 0; +} + +/* ---------- Highlighter (the one place yellow appears in body copy) ---------- */ +mark, .mark { + background: var(--hi); + color: var(--hi-ink); + padding: 0 2px; +} + +/* ---------- Tables (used in templates) ---------- */ +table { + width: 100%; + border-collapse: collapse; + font-size: var(--fs-sm); +} +th, td { + text-align: left; + padding: var(--sp-3) var(--sp-4); + border-bottom: 1px solid var(--border); +} +th { + font-weight: 500; + color: var(--fg-2); + font-family: var(--ff-mono); + font-size: var(--fs-xs); + letter-spacing: var(--tr-label); + text-transform: uppercase; +} + +/* ---------- Selection ---------- */ +::selection { background: var(--hi); color: var(--hi-ink); } diff --git a/static/src/vendor/whynot-design/tokens/colors.json b/static/src/vendor/whynot-design/tokens/colors.json new file mode 100644 index 0000000..00f0590 --- /dev/null +++ b/static/src/vendor/whynot-design/tokens/colors.json @@ -0,0 +1,22 @@ +{ + "$schema": "https://design-tokens.github.io/community-group/format/", + "ink": { "value": "#0A0A0A", "type": "color", "comment": "Near-black. The only fill most of the time." }, + "ink-2": { "value": "#1F1F1F", "type": "color" }, + "ink-3": { "value": "#5C5C5C", "type": "color" }, + "ink-4": { "value": "#8A8A8A", "type": "color" }, + "ink-5": { "value": "#B5B5B3", "type": "color", "comment": "Placeholder text, wireframe labels." }, + "line": { "value": "#E5E5E2", "type": "color", "comment": "Default 1px wireframe rule." }, + "line-strong": { "value": "#C9C9C5", "type": "color" }, + "line-soft": { "value": "#F0F0EC", "type": "color" }, + "paper": { "value": "#FFFFFF", "type": "color" }, + "paper-2": { "value": "#FAFAF7", "type": "color" }, + "paper-3": { "value": "#F4F4EF", "type": "color" }, + "hi": { "value": "#FFE14A", "type": "color", "comment": "Annotation yellow. Highlighter only, never a button fill." }, + "hi-2": { "value": "#FFD400", "type": "color" }, + "hi-ink": { "value": "#1A1500", "type": "color", "comment": "Text on yellow." }, + "status-raw": { "value": "#B5B5B3", "type": "color", "comment": "S0 — no signal" }, + "status-weak": { "value": "#8A8A8A", "type": "color", "comment": "S1 — weak signal" }, + "status-medium": { "value": "#5C5C5C", "type": "color", "comment": "S2 — medium signal" }, + "status-strong": { "value": "#0A0A0A", "type": "color", "comment": "S3 — strong signal" }, + "status-commercial": { "value": "#FFD400", "type": "color", "comment": "S4 — commercial" } +} diff --git a/static/src/vendor/whynot-design/tokens/index.json b/static/src/vendor/whynot-design/tokens/index.json new file mode 100644 index 0000000..974065d --- /dev/null +++ b/static/src/vendor/whynot-design/tokens/index.json @@ -0,0 +1,6 @@ +{ + "comment": "Manifest pointing at the three token files. Source-of-truth for any future Style Dictionary build.", + "colors": "./colors.json", + "type": "./type.json", + "spacing": "./spacing.json" +} diff --git a/static/src/vendor/whynot-design/tokens/spacing.json b/static/src/vendor/whynot-design/tokens/spacing.json new file mode 100644 index 0000000..0e6e0e0 --- /dev/null +++ b/static/src/vendor/whynot-design/tokens/spacing.json @@ -0,0 +1,28 @@ +{ + "$schema": "https://design-tokens.github.io/community-group/format/", + "spacing": { + "1": { "value": "4px", "type": "dimension" }, + "2": { "value": "8px", "type": "dimension" }, + "3": { "value": "12px", "type": "dimension" }, + "4": { "value": "16px", "type": "dimension" }, + "5": { "value": "24px", "type": "dimension" }, + "6": { "value": "32px", "type": "dimension" }, + "7": { "value": "48px", "type": "dimension" }, + "8": { "value": "64px", "type": "dimension" }, + "9": { "value": "96px", "type": "dimension" }, + "10": { "value": "128px", "type": "dimension" } + }, + "radius": { + "0": { "value": "0px", "type": "dimension" }, + "1": { "value": "2px", "type": "dimension" }, + "2": { "value": "4px", "type": "dimension" }, + "3": { "value": "8px", "type": "dimension" }, + "pill": { "value": "999px", "type": "dimension" } + }, + "shadow": { + "0": { "value": "none", "type": "shadow" }, + "1": { "value": "0 1px 0 #E5E5E2", "type": "shadow" }, + "2": { "value": "0 1px 0 #C9C9C5", "type": "shadow" }, + "3": { "value": "0 4px 12px -6px rgba(10,10,10,0.10)", "type": "shadow", "comment": "Floating elements only." } + } +} diff --git a/static/src/vendor/whynot-design/tokens/type.json b/static/src/vendor/whynot-design/tokens/type.json new file mode 100644 index 0000000..2022120 --- /dev/null +++ b/static/src/vendor/whynot-design/tokens/type.json @@ -0,0 +1,33 @@ +{ + "$schema": "https://design-tokens.github.io/community-group/format/", + "family": { + "sans": { "value": "\"IBM Plex Sans\", ui-sans-serif, system-ui, sans-serif", "type": "fontFamily" }, + "mono": { "value": "\"IBM Plex Mono\", ui-monospace, \"SF Mono\", Menlo, monospace", "type": "fontFamily" }, + "serif": { "value": "\"IBM Plex Serif\", \"Iowan Old Style\", Georgia, serif", "type": "fontFamily" } + }, + "size": { + "xs": { "value": "11px", "type": "dimension" }, + "sm": { "value": "13px", "type": "dimension" }, + "base": { "value": "15px", "type": "dimension" }, + "md": { "value": "17px", "type": "dimension" }, + "lg": { "value": "20px", "type": "dimension" }, + "xl": { "value": "24px", "type": "dimension" }, + "2xl": { "value": "32px", "type": "dimension" }, + "3xl": { "value": "44px", "type": "dimension" }, + "4xl": { "value": "64px", "type": "dimension" }, + "5xl": { "value": "96px", "type": "dimension" } + }, + "lineHeight": { + "tight": { "value": 1.05, "type": "number" }, + "snug": { "value": 1.25, "type": "number" }, + "base": { "value": 1.5, "type": "number" }, + "loose": { "value": 1.7, "type": "number" } + }, + "tracking": { + "tight": { "value": "-0.02em", "type": "dimension" }, + "snug": { "value": "-0.01em", "type": "dimension" }, + "base": { "value": "0em", "type": "dimension" }, + "mono": { "value": "0.02em", "type": "dimension" }, + "label": { "value": "0.08em", "type": "dimension", "comment": "Uppercase eyebrow labels." } + } +} diff --git a/vergabe_teilnahme/templates/base.html b/vergabe_teilnahme/templates/base.html index 89f6b71..0242d06 100644 --- a/vergabe_teilnahme/templates/base.html +++ b/vergabe_teilnahme/templates/base.html @@ -8,7 +8,7 @@ - + {% include "partials/topbar.html" %}
diff --git a/wiki/DesignSystem.md b/wiki/DesignSystem.md new file mode 100644 index 0000000..5ae141d --- /dev/null +++ b/wiki/DesignSystem.md @@ -0,0 +1,50 @@ +# Design System + +vergabe-teilnahme nutzt das `whynot-design`-System (gitea +`whynot/whynot-design`) als visuelle Basis. + +## Phase 1 — Tokens + CSS (aktiv, ab WP-0017) + +- Vendored CSS unter `static/src/vendor/whynot-design/`. +- Sync via `make sync-whynot-design` (Skript: `scripts/sync-whynot-design.sh`). +- Gepinnter Commit steht in `static/src/vendor/whynot-design/.whynot-design-ref`. +- `static/src/main.css` importiert die Vendor-CSS und mappt die whynot-Tokens + in den Tailwind-`@theme`-Block: `bg-ink`, `bg-paper`, `text-ink-3`, + `border-line` usw. sind als Utility-Klassen verfügbar. +- Legacy `bg-brand-*` / `text-brand-*` Utilities sind weiterhin nutzbar; sie + sind als Aliasse auf die ink/paper-Skala gemappt, damit Page-Templates + nicht in einer großen Migration mitgezogen werden müssen. + +## Phase 2 — Komponenten (offen) + +Adoption der whynot-Komponenten erfolgt sobald upstream Lit Web Components +und die fehlenden Atome (`Card`, `Modal`, `Input`, `Table`, `Toast`) +ausliefert. Eigener Workplan wird zu diesem Zeitpunkt angelegt. + +## Lokale Abweichungen vom whynot-System + +Dokumentiert direkt in `static/src/main.css`: + +- **`.btn-danger`** nutzt ein Off-Spec-Rot (`#B22222`, `--danger`-Variable). + whynot definiert aktuell keine destruktive Farbe; vergabe-Nutzung erfordert + sie für Löschen-Aktionen. Wird zurückgebaut, sobald upstream eine + kanonische Lösung definiert. + +## Visuelle Hausregeln aus whynot übernommen + +- Mostly Black & White; gelber Akzent (`--hi: #FFE14A`) nur als Highlighter / + Stamp / S4-Signal — nie als Button-Fill oder Hero-Hintergrund. +- 1px-Hairlines (`var(--line)` / `border-line`), großzügiger Weißraum, + Monospace-Eyebrow-Labels. +- Keine Schatten auf Cards; nur Popovers bekommen einen weichen 4–12px-Shadow. +- 0–4px Border-Radius für Cards/Sheets; 8px nur für große Modale; Pill nur + für Tag-Capsules. +- IBM Plex Sans / Mono / Serif via Google-Fonts (`@import url(...)` in der + Vendor-CSS). Build-Container und Browser brauchen Internet-Zugriff zu + Google Fonts. Air-gapped Deployment würde self-hosting erfordern. + +## Hintergrund + +- Strategie-Analyse + Komponenten-Lücken-Inventar: + `history/2026-05-23-whynot-design-cross-framework-analysis.md`. +- Adoption-Workplan: `workplans/WP-0017-whynot-design-tokens.md`. diff --git a/workplans/WP-0017-whynot-design-tokens.md b/workplans/WP-0017-whynot-design-tokens.md index 16dbb49..94bfa95 100644 --- a/workplans/WP-0017-whynot-design-tokens.md +++ b/workplans/WP-0017-whynot-design-tokens.md @@ -1,7 +1,7 @@ --- id: WP-0017 title: whynot-design Adoption — Phase 1 (Tokens + CSS) -status: ready +status: finished phase: 17-of-n created: "2026-05-23" depends_on: WP-0016 @@ -41,7 +41,7 @@ Inventar und Lücken-Liste in ```task id: WP-0017-T01 title: Vendor-Sync-Skript + initiale Vendor-Übernahme -status: todo +status: done Ziel: deterministisches Pull der whynot-design CSS-/Token-Quellen aus einem gepinnten Commit nach `static/src/vendor/whynot-design/`, ohne Docker-Build @@ -114,7 +114,7 @@ Diffs gegen den Vendor sind Teil des Review-Surfaces beim nächsten Bump. ```task id: WP-0017-T02 title: CSS-Integration in static/src/main.css -status: todo +status: done Ziel: whynot-Tokens werden global verfügbar, Tailwind-`@theme`-Mapping exponiert sie als Utility-Klassen, vergabe-spezifisches Brand-Blau entfällt. @@ -228,7 +228,7 @@ später durch self-hosting ersetzt werden — ist heute nicht relevant ```task id: WP-0017-T03 title: Base-Template — Body-Hintergrund auf whynot-Palette -status: todo +status: done **`vergabe_teilnahme/templates/base.html`** — Body-Klasse anpassen: @@ -249,7 +249,7 @@ weiterhin parallel zur whynot-Palette. ```task id: WP-0017-T04 title: Build + Static-Asset-Prüfung -status: todo +status: done Lokaler Build: @@ -279,7 +279,7 @@ adressieren (visueller Bruch wird dort sichtbar). ```task id: WP-0017-T05 title: Big-Bang Smoke-Test — visueller Durchlauf aller Hauptseiten -status: todo +status: done Dev-Server starten und durch die wichtigsten Views klicken. Bei jedem visuellen Bruch (Kontrast, weiße Schrift auf weißem Grund, harte Farb-Fremdkörper) eine @@ -325,7 +325,7 @@ Sichtprüfungs-Beleg. ```task id: WP-0017-T06 title: Doku-Update und Phase-2-Pflock -status: todo +status: done **`wiki/`** — neue Datei `wiki/DesignSystem.md` mit knappem Inhalt: From 5ae4aba4a862859a5314222ab9156d2c0c66ac09 Mon Sep 17 00:00:00 2001 From: tegwick Date: Fri, 5 Jun 2026 20:42:33 +0200 Subject: [PATCH 02/10] Lock issue-core from Gitea registry --- uv.lock | 33 +++++---------------------------- 1 file changed, 5 insertions(+), 28 deletions(-) diff --git a/uv.lock b/uv.lock index b4eaabb..4c58097 100644 --- a/uv.lock +++ b/uv.lock @@ -362,38 +362,15 @@ wheels = [ [[package]] name = "issue-core" version = "0.2.0" -source = { directory = "../issue-core" } +source = { registry = "https://gitea.coulomb.social/api/packages/coulomb/pypi/simple/" } dependencies = [ { name = "click" }, { name = "python-dateutil" }, { name = "requests" }, ] - -[package.metadata] -requires-dist = [ - { name = "black", marker = "extra == 'dev'", specifier = ">=22.0" }, - { name = "click", specifier = ">=8.0.0" }, - { name = "fastapi", marker = "extra == 'api'", specifier = ">=0.110,<1.0" }, - { name = "fastapi", marker = "extra == 'dev'", specifier = ">=0.110,<1.0" }, - { name = "flake8", marker = "extra == 'dev'", specifier = ">=4.0" }, - { name = "httpx", marker = "extra == 'dev'", specifier = ">=0.27" }, - { name = "isort", marker = "extra == 'dev'", specifier = ">=5.0" }, - { name = "jira", marker = "extra == 'jira'", specifier = ">=3.0" }, - { name = "mypy", marker = "extra == 'dev'", specifier = ">=0.900" }, - { name = "pre-commit", marker = "extra == 'dev'", specifier = ">=2.0" }, - { name = "pydantic", marker = "extra == 'api'", specifier = ">=2.0,<3.0" }, - { name = "pydantic", marker = "extra == 'dev'", specifier = ">=2.0,<3.0" }, - { name = "pygithub", marker = "extra == 'github'", specifier = ">=1.55" }, - { name = "pytest", marker = "extra == 'dev'", specifier = ">=6.0" }, - { name = "pytest-cov", marker = "extra == 'dev'", specifier = ">=2.0" }, - { name = "pytest-mock", marker = "extra == 'dev'", specifier = ">=3.0" }, - { name = "python-dateutil", specifier = ">=2.8.0" }, - { name = "requests", specifier = ">=2.25.0" }, - { name = "requests", marker = "extra == 'gitea'", specifier = ">=2.25.0" }, - { name = "sphinx", marker = "extra == 'docs'", specifier = ">=4.0" }, - { name = "sphinx-click", marker = "extra == 'docs'", specifier = ">=3.0" }, - { name = "sphinx-rtd-theme", marker = "extra == 'docs'", specifier = ">=1.0" }, - { name = "uvicorn", extras = ["standard"], marker = "extra == 'api'", specifier = ">=0.27,<1.0" }, +sdist = { url = "http://gitea.coulomb.social/api/packages/coulomb/pypi/files/issue-core/0.2.0/issue_core-0.2.0.tar.gz", hash = "sha256:cd456ccafdf540f02f7f8b1326e28f8acebcfa0476f3ea2245bd2a5230d85a8d" } +wheels = [ + { url = "http://gitea.coulomb.social/api/packages/coulomb/pypi/files/issue-core/0.2.0/issue_core-0.2.0-py3-none-any.whl", hash = "sha256:f98b90a13c787095834dbc7ff8b14057718884e01a51c6b13206e438ba1d5f90" }, ] [[package]] @@ -791,7 +768,7 @@ requires-dist = [ { name = "django", specifier = ">=5.2" }, { name = "django-storages", specifier = ">=1.14" }, { name = "gunicorn", specifier = ">=22.0" }, - { name = "issue-core", directory = "../issue-core" }, + { name = "issue-core", specifier = ">=0.2,<0.3", index = "https://gitea.coulomb.social/api/packages/coulomb/pypi/simple/" }, { name = "psycopg", extras = ["binary"], specifier = ">=3.2" }, { name = "python-decouple", specifier = ">=3.8" }, { name = "whitenoise", specifier = ">=6.7" }, From 9cb8992486c18c2154b93fdc013e8bea2d5ec649 Mon Sep 17 00:00:00 2001 From: tegwick Date: Tue, 16 Jun 2026 02:02:54 +0200 Subject: [PATCH 03/10] Add capability registry scaffold (REUSE-WP-0014-T08 B06) --- registry/README.md | 12 ++++++++++++ registry/capabilities/.gitkeep | 0 registry/indexes/capabilities.yaml | 4 ++++ 3 files changed, 16 insertions(+) create mode 100644 registry/README.md create mode 100644 registry/capabilities/.gitkeep create mode 100644 registry/indexes/capabilities.yaml diff --git a/registry/README.md b/registry/README.md new file mode 100644 index 0000000..569abe9 --- /dev/null +++ b/registry/README.md @@ -0,0 +1,12 @@ +# Capability Registry + +Markdown-first capability index for federation and reuse planning. + +## Authoring + +1. Copy a capability entry template (see reuse-surface `templates/capability-entry.template.md`). +2. Add the row to `indexes/capabilities.yaml`. +3. Run `reuse-surface validate` from a checkout with the CLI installed. +4. Merge to `main` and verify publish with `reuse-surface establish --publish-check`. + +Federation contract: reuse-surface `docs/RegistryFederation.md`. diff --git a/registry/capabilities/.gitkeep b/registry/capabilities/.gitkeep new file mode 100644 index 0000000..e69de29 diff --git a/registry/indexes/capabilities.yaml b/registry/indexes/capabilities.yaml new file mode 100644 index 0000000..f944e47 --- /dev/null +++ b/registry/indexes/capabilities.yaml @@ -0,0 +1,4 @@ +version: 1 +updated: '2026-06-16' +domain: helix_forge +capabilities: [] From 7bd6730744dc3c5e8061b24b6c00f180628b8962 Mon Sep 17 00:00:00 2001 From: tegwick Date: Thu, 18 Jun 2026 22:48:40 +0200 Subject: [PATCH 04/10] Add credential routing instructions for all agent runtimes Propagate shared credential-routing section (Codex, Claude, Grok, llm-connect) from state-hub template via scripts/propagate_credential_routing.py. --- .claude/rules/credential-routing.md | 50 +++++++++++++++++++++++++++ AGENTS.md | 52 +++++++++++++++++++++++++++++ CLAUDE.md | 1 + 3 files changed, 103 insertions(+) create mode 100644 .claude/rules/credential-routing.md diff --git a/.claude/rules/credential-routing.md b/.claude/rules/credential-routing.md new file mode 100644 index 0000000..d5051c7 --- /dev/null +++ b/.claude/rules/credential-routing.md @@ -0,0 +1,50 @@ +# Credential and access routing + +**Audience:** Codex, Claude Code, Grok, and custodian agents that call **llm-connect** +for inference. Run this check **before** requesting secrets, API keys, SSH access, +login tokens, or database passwords — in any repo, not only `ops-warden`. + +ops-warden **issues SSH certificates only** (`warden sign`, `cert_command`). Every +other credential need belongs to another subsystem. **Do not** message +`ops-warden` on State Hub expecting a secret value; the reply is a pointer, not a key. + +### Lookup (do this first) + +```bash +warden route find "" --json +warden route show --json +``` + +Requires the `warden` CLI from `~/ops-warden` (`uv tool install .` or `uv run warden`). + +| Agent runtime | How to orient | +| --- | --- | +| **Codex / Grok** (shell, HTTP State Hub) | `warden route` commands above; inbox `to_agent=vergabe-teilnahme` is for coordination, not secret vending | +| **Claude Code** (MCP when available) | `get_domain_summary("custodian")` for workstreams; **still** use `warden route` for credential ownership | +| **llm-connect** (inference service) | Never put secret retrieval in prompts; route custody to OpenBao/operator paths surfaced by `warden route` | + +### Quick routing table + +| I need… | Owner | ops-warden executes? | +| --- | --- | --- | +| SSH cert (`adm`/`agt`/`atm`) | ops-warden | **Yes** — `warden sign` | +| API key, DB password, provider token | OpenBao (`railiance-platform`) | No — route only | +| Login / OIDC / MFA | key-cape / Keycloak | No — route only | +| Authorization decision | flex-auth | No — route only | +| activity-core → issue-core emission | activity-core + issue-core | No — `warden route show activity-core-issue-sink` | +| SSH tunnel | ops-bridge (+ `cert_command` from warden) | No — route only | + +### Anti-patterns (do not do these) + +- `POST /messages/` to `ops-warden` asking for `ISSUE_CORE_API_KEY`, `OPENROUTER_API_KEY`, etc. +- Inventing `warden secret`, `warden login`, `warden bao`, `warden tunnel` — they do not exist +- Pasting secrets into Git, State Hub, workplans, logs, or chat + +### Other capabilities (reuse-surface) + +Non-credential capabilities are usually discovered through **reuse-surface** federation +(`reuse-surface` registry / `capability.*` indexes). Credential routing is inlined in +every repo's agent instructions because it is high-frequency, high-risk, and easy to +get wrong. + +**Canon:** `~/ops-warden/wiki/CredentialRouting.md` · catalog `~/ops-warden/registry/routing/catalog.yaml` \ No newline at end of file diff --git a/AGENTS.md b/AGENTS.md index 9e94910..e56b768 100644 --- a/AGENTS.md +++ b/AGENTS.md @@ -101,6 +101,58 @@ curl -s -X PATCH "http://127.0.0.1:8000/tasks/" \ --- +## Credential and access routing + +**Audience:** Codex, Claude Code, Grok, and custodian agents that call **llm-connect** +for inference. Run this check **before** requesting secrets, API keys, SSH access, +login tokens, or database passwords — in any repo, not only `ops-warden`. + +ops-warden **issues SSH certificates only** (`warden sign`, `cert_command`). Every +other credential need belongs to another subsystem. **Do not** message +`ops-warden` on State Hub expecting a secret value; the reply is a pointer, not a key. + +### Lookup (do this first) + +```bash +warden route find "" --json +warden route show --json +``` + +Requires the `warden` CLI from `~/ops-warden` (`uv tool install .` or `uv run warden`). + +| Agent runtime | How to orient | +| --- | --- | +| **Codex / Grok** (shell, HTTP State Hub) | `warden route` commands above; inbox `to_agent=vergabe-teilnahme` is for coordination, not secret vending | +| **Claude Code** (MCP when available) | `get_domain_summary("custodian")` for workstreams; **still** use `warden route` for credential ownership | +| **llm-connect** (inference service) | Never put secret retrieval in prompts; route custody to OpenBao/operator paths surfaced by `warden route` | + +### Quick routing table + +| I need… | Owner | ops-warden executes? | +| --- | --- | --- | +| SSH cert (`adm`/`agt`/`atm`) | ops-warden | **Yes** — `warden sign` | +| API key, DB password, provider token | OpenBao (`railiance-platform`) | No — route only | +| Login / OIDC / MFA | key-cape / Keycloak | No — route only | +| Authorization decision | flex-auth | No — route only | +| activity-core → issue-core emission | activity-core + issue-core | No — `warden route show activity-core-issue-sink` | +| SSH tunnel | ops-bridge (+ `cert_command` from warden) | No — route only | + +### Anti-patterns (do not do these) + +- `POST /messages/` to `ops-warden` asking for `ISSUE_CORE_API_KEY`, `OPENROUTER_API_KEY`, etc. +- Inventing `warden secret`, `warden login`, `warden bao`, `warden tunnel` — they do not exist +- Pasting secrets into Git, State Hub, workplans, logs, or chat + +### Other capabilities (reuse-surface) + +Non-credential capabilities are usually discovered through **reuse-surface** federation +(`reuse-surface` registry / `capability.*` indexes). Credential routing is inlined in +every repo's agent instructions because it is high-frequency, high-risk, and easy to +get wrong. + +**Canon:** `~/ops-warden/wiki/CredentialRouting.md` · catalog `~/ops-warden/registry/routing/catalog.yaml` +--- + ## Workplan Convention (ADR-001) Work items originate as files in this repo — not in the hub. The hub is a diff --git a/CLAUDE.md b/CLAUDE.md index de58ed4..331226b 100644 --- a/CLAUDE.md +++ b/CLAUDE.md @@ -8,4 +8,5 @@ @.claude/rules/stack-and-commands.md @.claude/rules/architecture.md @.claude/rules/repo-boundary.md +@.claude/rules/credential-routing.md @.claude/rules/agents.md From b31409649cc9732bb2d83d2bf63c3b0536c6d901 Mon Sep 17 00:00:00 2001 From: tegwick Date: Mon, 22 Jun 2026 17:47:43 +0200 Subject: [PATCH 05/10] Add .repo-classification.yaml (CUST-WP-0050 T11 agent first-pass) --- .repo-classification.yaml | 19 +++++++++++++++++++ 1 file changed, 19 insertions(+) create mode 100644 .repo-classification.yaml diff --git a/.repo-classification.yaml b/.repo-classification.yaml new file mode 100644 index 0000000..cb8262a --- /dev/null +++ b/.repo-classification.yaml @@ -0,0 +1,19 @@ +repo_classification: + standard: Repo Classification Standard + version: '1.0' + classified_at: '2026-06-22' + classified_by: agent + category: experimental + domain: communication + secondary_domains: [] + capability_tags: + - marketplace + - collaboration + - procurement + - governance + business_stake: + - product + - sales + business_mechanics: + - coordination + - operation From a3cec3f22195e688d2fc19b43c1668b17d692662 Mon Sep 17 00:00:00 2001 From: tegwick Date: Mon, 22 Jun 2026 23:16:29 +0200 Subject: [PATCH 06/10] Normalize agent instructions and workplan frontmatter (STATE-WP-0067) - Align agent files with on-disk workplan prefixes (infer from workplan ids) - Set workplan domain to registered domain_slug; add topic_slug where applicable - Repair frontmatter delimiter formatting; migrate legacy task status literals - Regenerate AGENTS.md, CLAUDE.md, and .claude/rules from State Hub templates --- .claude/rules/first-session.md | 14 +++--- .claude/rules/repo-identity.md | 8 ++-- .claude/rules/session-protocol.md | 23 ++++----- .claude/rules/stack-and-commands.md | 29 ++++-------- .claude/rules/workplan-convention.md | 20 ++++++-- AGENTS.md | 47 ++++++++++--------- workplans/WP-0001-projektgeruest.md | 1 + workplans/WP-0002-fachmodelle.md | 1 + workplans/WP-0003-basis-ui.md | 1 + .../WP-0004-dashboard-ausschreibungen.md | 1 + workplans/WP-0005-lose-anforderungen.md | 1 + workplans/WP-0006-aufgaben-bieterfragen.md | 1 + workplans/WP-0007-dokumente.md | 1 + workplans/WP-0008-preise.md | 1 + workplans/WP-0009-abgabe-nachbetrachtung.md | 1 + workplans/WP-0010-partner-bibliothek.md | 1 + workplans/WP-0011-marktbegleiter.md | 1 + workplans/WP-0012-querschnitt.md | 1 + workplans/WP-0013-feedback-bugs.md | 1 + workplans/WP-0014-aufgaben-lose-scores.md | 1 + ...fgaben-verknuepfungen-frist-issuefacade.md | 1 + workplans/WP-0016-issue-facade-integration.md | 1 + workplans/WP-0017-whynot-design-tokens.md | 1 + 23 files changed, 90 insertions(+), 68 deletions(-) diff --git a/.claude/rules/first-session.md b/.claude/rules/first-session.md index 34d5594..0ff40b8 100644 --- a/.claude/rules/first-session.md +++ b/.claude/rules/first-session.md @@ -1,11 +1,11 @@ ## First Session Protocol -Triggered when `get_domain_summary("vergabe_teilnahme")` shows **no workstreams**. +Triggered when `get_domain_summary("communication")` shows **no workstreams**. The project is registered but work has not yet been structured. **Step 1 — Read, don't write** -- `~/the-custodian/canon/projects/vergabe_teilnahme/project_charter_v0.1.md` — purpose, scope -- `~/the-custodian/canon/projects/vergabe_teilnahme/roadmap_v0.1.md` — planned phases +- `~/the-custodian/canon/projects/communication/project_charter_v0.1.md` — purpose, scope +- `~/the-custodian/canon/projects/communication/roadmap_v0.1.md` — planned phases - Scan repo root: README, directory structure, existing code or docs **Step 2 — Survey in-progress work** @@ -17,20 +17,20 @@ roadmap phase. **Wait for approval before creating.** **Step 4 — Create workplan file first, then DB record (ADR-001)** ``` -workplans/vergabe_teilnahme-WP-NNNN-.md ← write this first +workplans/WP-NNNN-.md ← write this first ``` Then register in the hub: ``` -create_workstream(topic_id="7d4d3e35-312f-4723-bde9-ddb43799109e", title="...", owner="...", description="...") +create_workstream(topic_id="36c7421b-c537-4723-bf75-42a3ebc6a1dc", title="...", owner="...", description="...") create_task(workstream_id="", title="...", priority="high|medium|low") ``` **Step 5 — Record the setup** ``` add_progress_event( - summary="First session: structured vergabe_teilnahme into N workstreams, M tasks", + summary="First session: structured communication into N workstreams, M tasks", event_type="milestone", - topic_id="7d4d3e35-312f-4723-bde9-ddb43799109e", + topic_id="36c7421b-c537-4723-bf75-42a3ebc6a1dc", detail={"workstreams": [...], "tasks_created": M} ) ``` diff --git a/.claude/rules/repo-identity.md b/.claude/rules/repo-identity.md index a2ce72d..9da340f 100644 --- a/.claude/rules/repo-identity.md +++ b/.claude/rules/repo-identity.md @@ -1,5 +1,5 @@ -**Purpose:** Django 6 + Tailwind + HTMX bid management app +**Purpose:** Coulomb project repository (bootstrapped from repo-seed template) -**Domain:** vergabe_teilnahme -**Repo slug:** vergabe_teilnahme -**Topic ID:** 7d4d3e35-312f-4723-bde9-ddb43799109e +**Domain:** communication +**Repo slug:** vergabe-teilnahme +**Topic ID:** 36c7421b-c537-4723-bf75-42a3ebc6a1dc diff --git a/.claude/rules/session-protocol.md b/.claude/rules/session-protocol.md index a2519be..76e6d65 100644 --- a/.claude/rules/session-protocol.md +++ b/.claude/rules/session-protocol.md @@ -1,6 +1,7 @@ ## Session Protocol -State Hub: http://127.0.0.1:8000 +Dev Hub (State Hub API): http://127.0.0.1:8000 +MCP server name in `~/.claude.json`: `dev-hub` **Step 1 — Orient** @@ -10,7 +11,7 @@ cat .custodian-brief.md ``` Then call the MCP tool for richer cross-domain context when MCP tools are exposed: ``` -get_domain_summary("vergabe_teilnahme") +get_domain_summary("communication") ``` If MCP tools are unavailable in the current agent session, use the REST API: ```bash @@ -21,14 +22,14 @@ If the hub is offline: `cd ~/state-hub && make api` **Step 2 — Check inbox** With MCP tools: ``` -get_messages(to_agent="vergabe_teilnahme", unread_only=True) +get_messages(to_agent="vergabe-teilnahme", unread_only=True) ``` Mark read with `mark_message_read(message_id)`. Reply or act on coordination requests before proceeding. Without MCP tools: ```bash -curl -s "http://127.0.0.1:8000/messages/?to_agent=vergabe_teilnahme&unread_only=true" \ +curl -s "http://127.0.0.1:8000/messages/?to_agent=vergabe-teilnahme&unread_only=true" \ | python3 -m json.tool curl -s -X PATCH "http://127.0.0.1:8000/messages//read" \ -H "Content-Type: application/json" -d '{}' @@ -39,12 +40,12 @@ curl -s -X PATCH "http://127.0.0.1:8000/messages//read" \ ls workplans/ ``` For each file with `status: ready`, `active`, or `blocked`, note pending -`todo`/`in_progress` tasks. +`wait`/`todo`/`progress` tasks. **Step 4 — Present brief** -1. **Active workstreams** for `vergabe_teilnahme` — title, task counts, blocking decisions -2. **Pending tasks** from `workplans/` + any `[repo:vergabe_teilnahme]` hub tasks +1. **Active workstreams** for `communication` — title, task counts, blocking decisions +2. **Pending tasks** from `workplans/` + any `[repo:vergabe-teilnahme]` hub tasks 3. **Goal guidance** — if `goal_guidance` in summary: - `needs_workplan`: surface as top action — *"Repo goal '{title}' has no workplan yet"* - `alignment_warnings`: flag if active work is not aligned with current goal @@ -61,23 +62,23 @@ If no workstreams: follow First Session Protocol (`first-session.md`). **Session close:** With MCP tools: ``` -add_progress_event(summary="...", topic_id="7d4d3e35-312f-4723-bde9-ddb43799109e", workstream_id="") +add_progress_event(summary="...", topic_id="36c7421b-c537-4723-bf75-42a3ebc6a1dc", workstream_id="") ``` Without MCP tools: ```bash curl -s -X POST http://127.0.0.1:8000/progress/ \ -H "Content-Type: application/json" \ - -d '{"topic_id":"7d4d3e35-312f-4723-bde9-ddb43799109e","workstream_id":"","event_type":"note","summary":"what changed","author":"codex"}' + -d '{"topic_id":"36c7421b-c537-4723-bf75-42a3ebc6a1dc","workstream_id":"","event_type":"note","summary":"what changed","author":"codex"}' ``` If workplan files were modified, ensure the local copy is up to date first: ```bash git -C pull --ff-only -cd ~/state-hub && make fix-consistency REPO=vergabe_teilnahme +cd ~/state-hub && make fix-consistency REPO=vergabe-teilnahme ``` For repos where implementation runs on a remote machine (e.g. CoulombCore), use the combined target which pulls before fixing: ```bash -cd ~/state-hub && make fix-consistency-remote REPO=vergabe_teilnahme +cd ~/state-hub && make fix-consistency-remote REPO=vergabe-teilnahme ``` **C-15** (DB task ahead of file) is normal in multi-machine workflows — writeback will sync the file to match DB. **C-16** (repo behind remote) blocks all writes diff --git a/.claude/rules/stack-and-commands.md b/.claude/rules/stack-and-commands.md index bc54d15..dc53ac6 100644 --- a/.claude/rules/stack-and-commands.md +++ b/.claude/rules/stack-and-commands.md @@ -1,32 +1,19 @@ ## Stack -- **Language:** Python 3.12 (Django 6), Node 22 (Vite + Tailwind v4) -- **Key deps:** Django, htmx, Alpine.js, Tailwind v4, whynot-design (vendored - under `static/src/vendor/whynot-design/`) + +- **Language:** +- **Key deps:** ## Dev Commands ```bash +# TODO: Fill in the standard commands for this repo + # Install dependencies -uv sync # Python -npm ci # Node (Vite/Tailwind) -# Run dev stack -make db # Start postgres if not running -make dev # Django runserver on :9000 -make css # Tailwind/Vite watcher (rebuilds main.css) +# Run tests -# Build CSS bundle for prod / for verification -npm run build # → static/dist/main.css +# Lint / type check -# Re-vendor the whynot-design system from a pinned upstream commit -make sync-whynot-design # reads .whynot-design-ref by default - # or: ./scripts/sync-whynot-design.sh - -# Tests / lint -make test # uv run pytest -make lint # ruff + mypy +# Build / package (if applicable) ``` - -See `wiki/DesignSystem.md` for the whynot-design adoption status (Phase 1 -tokens+CSS done; Phase 2 components deferred) and local style conventions. diff --git a/.claude/rules/workplan-convention.md b/.claude/rules/workplan-convention.md index 97f9500..1694e83 100644 --- a/.claude/rules/workplan-convention.md +++ b/.claude/rules/workplan-convention.md @@ -1,7 +1,7 @@ ## Workplan Convention (ADR-001) -File location: `workplans/vergabe_teilnahme-WP-NNNN-.md` -ID prefix: `VERGABE_TEILNAHME-WP` +File location: `workplans/WP-NNNN-.md` +ID prefix: `WP-` Work items originate as files in this repo **before** being registered in the hub. @@ -12,7 +12,7 @@ repo state, and `finished` when implementation is complete. `stalled` and `needs_review` are derived health labels, not stored statuses. Closed workplans may be moved to `workplans/archived/` with a completion-date -prefix: `YYMMDD-vergabe_teilnahme-WP-NNNN-.md`. The frontmatter id remains +prefix: `YYMMDD-WP-NNNN-.md`. The frontmatter id remains unchanged; the prefix is only for quick visual reference. Small opportunistic tasks discovered during another session use **Ad Hoc Tasks**: @@ -21,8 +21,20 @@ Small opportunistic tasks discovered during another session use **Ad Hoc Tasks** directly. Promote anything requiring analysis, design, approval, dependencies, or multiple planned phases into a normal workplan. -Ecosystem todos from other agents arrive as `[repo:vergabe_teilnahme]` hub tasks — +Ecosystem todos from other agents arrive as `[repo:vergabe-teilnahme]` hub tasks — visible at session start. Pick one up by creating the workplan file, then registering the workstream. +Task blocks use this shape: + +```task +id: WP-NNNN-T01 +status: wait | todo | progress | done | cancel +priority: high | medium | low +state_hub_task_id: "" # written by fix-consistency — do not edit +``` + +Status progression is `todo` → `progress` → `done`; use `wait` for waiting or +blocked work and `cancel` for stopped work. + diff --git a/AGENTS.md b/AGENTS.md index e56b768..19ac443 100644 --- a/AGENTS.md +++ b/AGENTS.md @@ -2,12 +2,12 @@ ## Repo Identity -**Purpose:** Django 6 + Tailwind + HTMX bid management app +**Purpose:** Coulomb project repository (bootstrapped from repo-seed template) -**Domain:** vergabe_teilnahme -**Repo slug:** vergabe_teilnahme -**Topic ID:** `7d4d3e35-312f-4723-bde9-ddb43799109e` -**Workplan prefix:** `VERGABE_TEILNAHME-WP-` +**Domain:** communication +**Repo slug:** vergabe-teilnahme +**Topic ID:** `36c7421b-c537-4723-bf75-42a3ebc6a1dc` +**Workplan prefix:** `WP-` --- @@ -28,11 +28,11 @@ there is no MCP server for Codex agents. cat .custodian-brief.md # Active workstreams for this domain -curl -s "http://127.0.0.1:8000/workstreams/?topic_id=7d4d3e35-312f-4723-bde9-ddb43799109e&status=active" \ +curl -s "http://127.0.0.1:8000/workstreams/?topic_id=36c7421b-c537-4723-bf75-42a3ebc6a1dc&status=active" \ | python3 -m json.tool # Check inbox -curl -s "http://127.0.0.1:8000/messages/?to_agent=vergabe_teilnahme&unread_only=true" \ +curl -s "http://127.0.0.1:8000/messages/?to_agent=vergabe-teilnahme&unread_only=true" \ | python3 -m json.tool ``` @@ -63,8 +63,8 @@ Omit `workstream_id` / `task_id` when not applicable. ```bash curl -s -X PATCH "http://127.0.0.1:8000/tasks/" \ -H "Content-Type: application/json" \ - -d '{"status": "in_progress"}' -# values: todo | in_progress | done | blocked + -d '{"status": "progress"}' +# values: wait | todo | progress | done | cancel ``` ### Flag a task for human review @@ -81,9 +81,9 @@ curl -s -X PATCH "http://127.0.0.1:8000/tasks/" \ **Start:** 1. `cat .custodian-brief.md` — domain goal and open workstreams (offline-safe) -2. Check inbox: `GET /messages/?to_agent=vergabe_teilnahme&unread_only=true`; mark read +2. Check inbox: `GET /messages/?to_agent=vergabe-teilnahme&unread_only=true`; mark read 3. Scan workplans: `ls workplans/` — note `status: ready`, `active`, or `blocked` files and open tasks -4. Check blocked tasks: `GET /tasks/?needs_human=true` +4. Check human-needed tasks: `GET /tasks/?needs_human=true` **During work:** - Update task statuses in workplan files as tasks progress @@ -95,7 +95,7 @@ curl -s -X PATCH "http://127.0.0.1:8000/tasks/" \ 3. Note for the custodian operator: after workplan file changes, run from `~/state-hub`: ```bash - make fix-consistency REPO=vergabe_teilnahme + make fix-consistency REPO=vergabe-teilnahme ``` This syncs task status from files into the hub DB. @@ -151,6 +151,11 @@ every repo's agent instructions because it is high-frequency, high-risk, and eas get wrong. **Canon:** `~/ops-warden/wiki/CredentialRouting.md` · catalog `~/ops-warden/registry/routing/catalog.yaml` + + + + --- ## Workplan Convention (ADR-001) @@ -158,10 +163,10 @@ get wrong. Work items originate as files in this repo — not in the hub. The hub is a read/cache/index layer that rebuilds from files. -**File location:** `workplans/VERGABE_TEILNAHME-WP-NNNN-.md` +**File location:** `workplans/VERGABE-WP-NNNN-.md` **Archived location:** finished workplans may move to -`workplans/archived/YYMMDD-VERGABE_TEILNAHME-WP-NNNN-.md`. The `YYMMDD` prefix is +`workplans/archived/YYMMDD-VERGABE-WP-NNNN-.md`. The `YYMMDD` prefix is the completion/archive date; the frontmatter `id` does not change. **Ad Hoc Tasks:** small opportunistic fixes discovered during a session use @@ -173,11 +178,11 @@ anything needing analysis, design, approval, dependencies, or multiple phases. ```yaml --- -id: VERGABE_TEILNAHME-WP-NNNN +id: VERGABE-WP-NNNN type: workplan title: "..." -domain: vergabe_teilnahme -repo: vergabe_teilnahme +domain: communication +repo: vergabe-teilnahme status: proposed | ready | active | blocked | backlog | finished | archived owner: codex topic_slug: ... @@ -197,8 +202,8 @@ derived health labels, not frontmatter statuses. ## Task Title ` ` `task -id: VERGABE_TEILNAHME-WP-NNNN-T01 -status: todo | in_progress | done | blocked +id: VERGABE-WP-NNNN-T01 +status: wait | todo | progress | done | cancel priority: high | medium | low state_hub_task_id: "" # written by fix-consistency — do not edit ` ` ` @@ -206,9 +211,9 @@ state_hub_task_id: "" # written by fix-consistency — do not edit Task description text. ``` -Status progression: `todo` → `in_progress` → `done` (or `blocked`) +Status progression: `todo` → `progress` → `done`; use `wait` for waiting/blocked work and `cancel` for stopped work. To create a new workplan: 1. Write the file following the format above -2. Notify the custodian operator to run `make fix-consistency REPO=vergabe_teilnahme` +2. Notify the custodian operator to run `make fix-consistency REPO=vergabe-teilnahme` (or send a message to the hub agent via `POST /messages/`) diff --git a/workplans/WP-0001-projektgeruest.md b/workplans/WP-0001-projektgeruest.md index c96f37d..ecfaf3a 100644 --- a/workplans/WP-0001-projektgeruest.md +++ b/workplans/WP-0001-projektgeruest.md @@ -4,6 +4,7 @@ title: Projektgerüst — Django-Setup, Tailwind, Dev-Stack status: done phase: 1-of-12 created: "2026-05-08" +domain: communication --- # WP-0001 — Projektgerüst diff --git a/workplans/WP-0002-fachmodelle.md b/workplans/WP-0002-fachmodelle.md index ff9e927..3727a94 100644 --- a/workplans/WP-0002-fachmodelle.md +++ b/workplans/WP-0002-fachmodelle.md @@ -5,6 +5,7 @@ status: done phase: 2-of-12 created: "2026-05-08" depends_on: WP-0001 +domain: communication --- # WP-0002 — Fachmodelle diff --git a/workplans/WP-0003-basis-ui.md b/workplans/WP-0003-basis-ui.md index 1c7294d..7515836 100644 --- a/workplans/WP-0003-basis-ui.md +++ b/workplans/WP-0003-basis-ui.md @@ -5,6 +5,7 @@ status: done phase: 3-of-12 created: "2026-05-08" depends_on: WP-0002 +domain: communication --- # WP-0003 — Basis-UI diff --git a/workplans/WP-0004-dashboard-ausschreibungen.md b/workplans/WP-0004-dashboard-ausschreibungen.md index 1d7b43d..5871a15 100644 --- a/workplans/WP-0004-dashboard-ausschreibungen.md +++ b/workplans/WP-0004-dashboard-ausschreibungen.md @@ -5,6 +5,7 @@ status: done phase: 4-of-12 created: "2026-05-08" depends_on: WP-0003 +domain: communication --- # WP-0004 — Dashboard und Ausschreibungen-CRUD diff --git a/workplans/WP-0005-lose-anforderungen.md b/workplans/WP-0005-lose-anforderungen.md index 4899e0a..8fa2a68 100644 --- a/workplans/WP-0005-lose-anforderungen.md +++ b/workplans/WP-0005-lose-anforderungen.md @@ -5,6 +5,7 @@ status: done phase: 5-of-12 created: "2026-05-08" depends_on: WP-0004 +domain: communication --- # WP-0005 — Lose und Anforderungen diff --git a/workplans/WP-0006-aufgaben-bieterfragen.md b/workplans/WP-0006-aufgaben-bieterfragen.md index dc3648f..77c1512 100644 --- a/workplans/WP-0006-aufgaben-bieterfragen.md +++ b/workplans/WP-0006-aufgaben-bieterfragen.md @@ -5,6 +5,7 @@ status: done phase: 6-of-12 created: "2026-05-08" depends_on: WP-0005 +domain: communication --- # WP-0006 — Aufgaben und Bieterfragen diff --git a/workplans/WP-0007-dokumente.md b/workplans/WP-0007-dokumente.md index 5825f80..7484e3b 100644 --- a/workplans/WP-0007-dokumente.md +++ b/workplans/WP-0007-dokumente.md @@ -5,6 +5,7 @@ status: done phase: 7-of-12 created: "2026-05-08" depends_on: WP-0006 +domain: communication --- # WP-0007 — Dokumentenmanagement diff --git a/workplans/WP-0008-preise.md b/workplans/WP-0008-preise.md index 50352b6..ff50a40 100644 --- a/workplans/WP-0008-preise.md +++ b/workplans/WP-0008-preise.md @@ -5,6 +5,7 @@ status: done phase: 8-of-12 created: "2026-05-08" depends_on: WP-0007 +domain: communication --- # WP-0008 — Preise und Marktpreisauswertung diff --git a/workplans/WP-0009-abgabe-nachbetrachtung.md b/workplans/WP-0009-abgabe-nachbetrachtung.md index 9332ea6..1d3dd76 100644 --- a/workplans/WP-0009-abgabe-nachbetrachtung.md +++ b/workplans/WP-0009-abgabe-nachbetrachtung.md @@ -5,6 +5,7 @@ status: done phase: 9-of-12 created: "2026-05-08" depends_on: WP-0008 +domain: communication --- # WP-0009 — Abgabe (Phase 6/7) und Nachbetrachtung (Phase 8) diff --git a/workplans/WP-0010-partner-bibliothek.md b/workplans/WP-0010-partner-bibliothek.md index a139891..9b89f3b 100644 --- a/workplans/WP-0010-partner-bibliothek.md +++ b/workplans/WP-0010-partner-bibliothek.md @@ -5,6 +5,7 @@ status: done phase: 10-of-12 created: "2026-05-08" depends_on: WP-0009 +domain: communication --- # WP-0010 — Subunternehmer, Partner und Bibliothek diff --git a/workplans/WP-0011-marktbegleiter.md b/workplans/WP-0011-marktbegleiter.md index 9e57b21..538d530 100644 --- a/workplans/WP-0011-marktbegleiter.md +++ b/workplans/WP-0011-marktbegleiter.md @@ -5,6 +5,7 @@ status: done phase: 11-of-12 created: "2026-05-08" depends_on: WP-0010 +domain: communication --- # WP-0011 — Marktbegleiter-Analyse diff --git a/workplans/WP-0012-querschnitt.md b/workplans/WP-0012-querschnitt.md index 01103c5..a4c6c2f 100644 --- a/workplans/WP-0012-querschnitt.md +++ b/workplans/WP-0012-querschnitt.md @@ -5,6 +5,7 @@ status: done phase: 12-of-12 created: "2026-05-08" depends_on: WP-0011 +domain: communication --- # WP-0012 — Querschnitt diff --git a/workplans/WP-0013-feedback-bugs.md b/workplans/WP-0013-feedback-bugs.md index dab827b..ff35720 100644 --- a/workplans/WP-0013-feedback-bugs.md +++ b/workplans/WP-0013-feedback-bugs.md @@ -5,6 +5,7 @@ status: done phase: 13-of-13 created: "2026-05-14" depends_on: WP-0012 +domain: communication --- # WP-0013 — Feedback-Bugs diff --git a/workplans/WP-0014-aufgaben-lose-scores.md b/workplans/WP-0014-aufgaben-lose-scores.md index 64be13d..061c57b 100644 --- a/workplans/WP-0014-aufgaben-lose-scores.md +++ b/workplans/WP-0014-aufgaben-lose-scores.md @@ -5,6 +5,7 @@ status: done phase: 14-of-n created: "2026-05-14" depends_on: WP-0013 +domain: communication --- # WP-0014 — Aufgaben-Phasenzuordnung und Scores diff --git a/workplans/WP-0015-aufgaben-verknuepfungen-frist-issuefacade.md b/workplans/WP-0015-aufgaben-verknuepfungen-frist-issuefacade.md index 633bdb3..d807e3d 100644 --- a/workplans/WP-0015-aufgaben-verknuepfungen-frist-issuefacade.md +++ b/workplans/WP-0015-aufgaben-verknuepfungen-frist-issuefacade.md @@ -5,6 +5,7 @@ status: done phase: 15-of-n created: "2026-05-14" depends_on: WP-0014 +domain: communication --- # WP-0015 — Aufgaben: Verknüpfungen, implizite Fälligkeit, Issue-Facade diff --git a/workplans/WP-0016-issue-facade-integration.md b/workplans/WP-0016-issue-facade-integration.md index 84a2c08..82b1e66 100644 --- a/workplans/WP-0016-issue-facade-integration.md +++ b/workplans/WP-0016-issue-facade-integration.md @@ -5,6 +5,7 @@ status: done phase: 16-of-n created: "2026-05-14" depends_on: WP-0015 +domain: communication --- # WP-0016 — Issue-Facade Integration diff --git a/workplans/WP-0017-whynot-design-tokens.md b/workplans/WP-0017-whynot-design-tokens.md index 94bfa95..8b07b92 100644 --- a/workplans/WP-0017-whynot-design-tokens.md +++ b/workplans/WP-0017-whynot-design-tokens.md @@ -5,6 +5,7 @@ status: finished phase: 17-of-n created: "2026-05-23" depends_on: WP-0016 +domain: communication --- # WP-0017 — whynot-design Adoption · Phase 1 (Tokens + CSS) From d20d21b21acd4b9ba66b3dfeb4ed7833f25763b1 Mon Sep 17 00:00:00 2001 From: tegwick Date: Mon, 6 Jul 2026 19:50:54 +0200 Subject: [PATCH 07/10] Draft capability entry (reuse-surface REUSE-WP-0017-T04, cohort 3) Honest first-pass maturity vector grounded in README/docs/tests present in this repo; no invented evidence. Flagged for human review before publish. See reuse-surface history/2026-07-06-coverage-classification.md. Co-Authored-By: Claude Sonnet 5 --- ...apability.procurement.vergabe-teilnahme.md | 121 ++++++++++++++++++ registry/indexes/capabilities.yaml | 19 ++- 2 files changed, 138 insertions(+), 2 deletions(-) create mode 100644 registry/capabilities/capability.procurement.vergabe-teilnahme.md diff --git a/registry/capabilities/capability.procurement.vergabe-teilnahme.md b/registry/capabilities/capability.procurement.vergabe-teilnahme.md new file mode 100644 index 0000000..69257c7 --- /dev/null +++ b/registry/capabilities/capability.procurement.vergabe-teilnahme.md @@ -0,0 +1,121 @@ +--- +id: capability.procurement.vergabe-teilnahme +name: Vergabe Teilnahme (Public Procurement Participation) Application +summary: Django application (with a Vite/Tailwind frontend) for managing German public-procurement (Vergabe) + tender participation — Ausschreibungs- und Teilnahme-Management-System. +owner: vergabe-teilnahme +status: draft +domain: communication +tags: +- procurement +- django +- vergabe +maturity: + discovery: + current: D1 + target: D3 + confidence: low + rationale: SCOPE.md is an unfilled template (placeholders only) and README.md is a stale repo-seed + leftover; discovery rests entirely on direct inspection of the codebase (pyproject description, + manage.py, vergabe_teilnahme Django app, docker-compose.test.yml with a dedicated Postgres test + database) rather than on written scope documentation. + availability: + current: A1 + target: A3 + confidence: medium + rationale: Full Django application (413+ files) with manage.py, a vergabe_teilnahme package, and a + Vite/Tailwind frontend; docker-compose.dev.yml and docker-compose.test.yml exist but no hosted deployment + confirmed in this sweep. +external_evidence: + completeness: + level: C0 + confidence: low + basis: scope_vs_intent_and_consumer_expectations + satisfied_expectations: [] + broken_expectations: [] + out_of_scope_expectations: [] + reliability: + level: R0 + confidence: low + basis: consumer_quality_signals + known_reliability_risks: + - SCOPE.md is an unfilled template — this repo's own scope documentation does not yet exist + - no independent verification of test suite health in this sweep +discovery: + intent: Manage German public-procurement (Vergabe) tender participation workflows as a Django application, + per its own pyproject description (Ausschreibungs- und Teilnahme-Management-System). + includes: + - tender/Ausschreibung participation management (Django app + Vite frontend) + excludes: [] + assumptions: [] + use_cases: [] + research_memos: [] +availability: + current_level: A1 + target_level: A3 + current_artifacts: + - Django application (`vergabe_teilnahme`) + - Vite/Tailwind frontend + target_artifacts: [] + consumption_modes: + - application (Django + Vite, local dev via docker-compose) +relations: + depends_on: [] + supports: [] + related_to: [] +evidence: + documentation: + - pyproject.toml description + tests: + - conftest.py + - docker-compose.test.yml + consumer_feedback: [] + bug_reports: [] + incidents: [] +consumer_guidance: + recommended_for: + - understanding or extending this specific German procurement participation tool + not_recommended_for: + - general reuse — SCOPE.md is unfilled, so consumer expectations are undocumented; treat as low-discovery + until SCOPE.md is written + known_limitations: + - SCOPE.md template is unfilled; this entry's discovery evidence comes from direct code inspection, + not authored scope documentation — filling in SCOPE.md should be the first step before promoting this + entry further +promotion_history: [] +--- + +# Vergabe Teilnahme (Public Procurement Participation) Application + +## Overview + +`vergabe-teilnahme` is a Django application (with a Vite/Tailwind frontend) for managing German public-procurement (Vergabe) tender participation. Its own `SCOPE.md` is an unfilled template, so this entry's discovery level is honestly low (D1) — filling in SCOPE.md is the natural next step before this capability can be promoted further. + +## Assessment notes + +### Discovery + +SCOPE.md is an unfilled template (placeholders only) and README.md is a stale repo-seed leftover; discovery rests entirely on direct inspection of the codebase (pyproject description, manage.py, vergabe_teilnahme Django app, docker-compose.test.yml with a dedicated Postgres test database) rather than on written scope documentation. + +### Availability + +Full Django application (413+ files) with manage.py, a vergabe_teilnahme package, and a Vite/Tailwind frontend; docker-compose.dev.yml and docker-compose.test.yml exist but no hosted deployment confirmed in this sweep. + +### Completeness + +First-pass honest assessment from the REUSE-WP-0017 coverage campaign +(reuse-surface). No external consumer feedback exists yet; levels reflect +scope-vs-intent documentation quality, not internal code quality. + +### Reliability + +No production consumer telemetry exists yet; reliability level is +intentionally conservative pending REUSE-WP-0019 reuse-telemetry evidence. + +## Promotion checklist + +- [x] ID follows `capability..` pattern +- [x] Maturity enums match `specs/CapabilityMaturityStandard.md` +- [x] `external_evidence` is populated separately from `maturity` +- [ ] Relations reference valid capability IDs (none yet) +- [x] Index entry added in `registry/indexes/capabilities.yaml` diff --git a/registry/indexes/capabilities.yaml b/registry/indexes/capabilities.yaml index f944e47..e1d5292 100644 --- a/registry/indexes/capabilities.yaml +++ b/registry/indexes/capabilities.yaml @@ -1,4 +1,19 @@ version: 1 -updated: '2026-06-16' +updated: '2026-07-06' domain: helix_forge -capabilities: [] +capabilities: +- id: capability.procurement.vergabe-teilnahme + name: Vergabe Teilnahme (Public Procurement Participation) Application + summary: Django application (with a Vite/Tailwind frontend) for managing German public-procurement (Vergabe) + tender participation — Ausschreibungs- und Teilnahme-Management-System. + vector: D1 / A1 / C0 / R0 + domain: communication + status: draft + owner: vergabe-teilnahme + path: registry/capabilities/capability.procurement.vergabe-teilnahme.md + tags: + - procurement + - django + - vergabe + consumption_modes: + - application (Django + Vite, local dev via docker-compose) From ff95fb3971a37a2b1176555558051c007fa74932 Mon Sep 17 00:00:00 2001 From: tegwick Date: Tue, 7 Jul 2026 01:26:36 +0200 Subject: [PATCH 08/10] Fill in SCOPE.md (was an unfilled template) Written from direct inspection of the 12-app Django domain model, wiki/ProductRequirementsDocument.md, and wiki/ArchitectureBlueprint.md. Requested during reuse-surface REUSE-WP-0017-T05 review follow-up. Co-Authored-By: Claude Sonnet 5 --- SCOPE.md | 159 ++++++++++++++++++++++++++++++------------------------- 1 file changed, 88 insertions(+), 71 deletions(-) diff --git a/SCOPE.md b/SCOPE.md index d48e39a..4a2db4e 100644 --- a/SCOPE.md +++ b/SCOPE.md @@ -8,130 +8,147 @@ ## One-liner - - +Web application that structures a company's participation in tenders +(Ausschreibungen) end-to-end, from research through submission to +post-award retrospective. --- ## Core Idea - - +**Vergabe Teilnahme** ("tender participation") guides a team through the +full lifecycle of bidding on a public or private tender: collecting tender +documents, analyzing requirements, deciding whether to participate, tracking +open items, finalizing pricing and documents, submitting on time, and +capturing reusable knowledge afterwards — win or lose. It is phase-guided, +never phase-locked: every element of a tender is reachable at any time, and +there is no forced completeness outside real submission-deadline +constraints. All data entry is manual in this first build stage — no +automated ingestion from tender platforms. + +It operates on three levels, per `wiki/ProductRequirementsDocument.md`: + +| Level | Content | +|---|---| +| Operational | deadlines, documents, tasks, lots (Lose), requirements, bidder questions, submission | +| Management | participate/no-bid decision, approvals, pricing level, subcontractor selection, outcome, retrospective | +| Strategic | reusable evidence/references, market price observation, loss reasons, win factors, competitor (Marktbegleiter) analysis | --- ## In Scope - - - -- -- -- - ---- +- Tender (Ausschreibung) and lot (Los) tracking through 8 navigable phases +- Requirements analysis and bidder-question (Bieterfragen) handling +- Task management (Aufgaben) scoped to a tender or a lot +- Document management (Dokumente) for tender materials and submission artifacts +- Pricing (Preise) tracking per lot/tender +- Submission and post-award retrospective (Abgabe/Nachbetrachtung) +- Partner and reference library (Partner/Bibliothek) for reusable evidence +- Competitor/market observation (Marktbegleiter) +- Feedback/bug capture within the app (Feedback) +- Issue-tracking integration via `issue-core` (task facade, not a UI replacement) ## Out of Scope - - - -- -- -- +- External user accounts for partners/subcontractors/service providers (data + objects only in this build stage, no system access of their own) +- Multi-tenancy +- Automated ingestion from tender platforms, SharePoint, Teams, CRM, ERP, + email, or calendars (deliberately manual-entry-first for v1) +- Certification or legal validity of submissions — the system tracks + process state, it is not a legal compliance authority --- ## Relevant When - - -- -- -- - ---- +- Deciding whether to bid on a tender and needing structured deadline, + document, and requirement tracking across a team +- Needing a system of record for pricing decisions, submission evidence, + and post-award retrospectives on public/private tenders +- Wanting to reuse prior tender evidence, references, or competitor/pricing + observations when evaluating a new tender ## Not Relevant When - - -- -- -- +- Needing external bidder/partner portal access (not built yet) +- Needing automated tender discovery or platform integration (out of scope + for this build stage) +- Needing generic project management unrelated to the tender-participation + domain --- ## Current State - - -- Status: -- Implementation: -- Stability: -- Usage: - - +- Status: active +- Implementation: substantial — 12 Django apps covering the full phase + model (accounts, aufgaben, ausschreibungen, bibliothek, core, dokumente, + feedback, lose, marktbegleiter, nachbetrachtung, partner, preise); 17 + workplans (WP-0001–WP-0017) implemented in sequence from project + scaffold through whynot-design token adoption +- Stability: evolving — manual-entry-first v1; no CI workflow configured yet + (`.gitea/`/`.forgejo/` absent) +- Usage: internal collaboration tool, not yet published for external use --- ## How It Fits - - -- Upstream dependencies: -- Downstream consumers: -- Often used with: +- Upstream dependencies: `issue-core` (task-tracking facade, see + `vergabe_teilnahme/apps/aufgaben/issue_facade.py`), `whynot-design` + (visual language, vendored CSS/tokens) +- Downstream consumers: none known +- Often used with: `railiance-apps` (deployment target per its own SCOPE.md, + which names `vergabe-teilnahme` as a user-facing service it deploys) --- ## Terminology - - - -- Preferred terms: -- Also known as: -- Potentially confusing terms: +- Preferred terms: Ausschreibung (tender), Los (lot), Aufgabe (task), + Marktbegleiter (competitor/market companion), Nachbetrachtung (post-award + retrospective) +- Also known as: "Vergabe Teilnahme" (product name), "tender participation + management system" (English gloss) +- Potentially confusing terms: "Partner" here means reference/subcontractor + data objects, not system users --- ## Related / Overlapping Repositories - - - -- +- `issue-core` — task-tracking backend consumed via `issue_facade.py` +- `whynot-design` — visual language vendored into `static/src/vendor/` +- `railiance-apps` — deployment/workload layer for this service --- ## Getting Oriented - - -- Start with: -- Key files / directories: -- Entry points: +- Start with: `wiki/ProductRequirementsDocument.md` (product intent, in + German), `wiki/ArchitectureBlueprint.md` (technology stack and design + principles) +- Key files / directories: `vergabe_teilnahme/apps/` (12 domain apps), + `vergabe_teilnahme/urls.py` (route map), `workplans/` (WP-0001–0017 + build history) +- Entry points: `manage.py runserver`; `vergabe_teilnahme/urls.py` maps + `/ausschreibungen/`, `/lose/`, `/aufgaben/`, `/dokumente/`, and more --- ## Provided Capabilities - - - - - +Registered in `registry/capabilities/capability.procurement.vergabe-teilnahme.md` +(reuse-surface federation, D1/A1/C0/R0 as of the initial coverage sweep — +low discovery confidence pending this SCOPE.md's first real fill-in). --- ## Notes - +Product and architecture documentation (`wiki/`) is in German; this SCOPE.md +is in English per the reuse-surface registry's Markdown-first, agent-facing +convention. Refer to `wiki/ProductRequirementsDocument.md` for the +authoritative German-language product definition. From 498b7aa9a53ce521b8ef6d37ff3b4fa2a606d90c Mon Sep 17 00:00:00 2001 From: tegwick Date: Tue, 7 Jul 2026 15:23:17 +0200 Subject: [PATCH 09/10] Promote vergabe-teilnahme capability after SCOPE.md fill-in (T05 entry 2). SCOPE.md was already filled; update the registry entry to D3/A1/C1/R1, document issue-core and whynot-design relations, and align the index vector with the authored scope and wiki evidence. --- SCOPE.md | 4 +- ...apability.procurement.vergabe-teilnahme.md | 112 +++++++++++------- registry/indexes/capabilities.yaml | 4 +- 3 files changed, 73 insertions(+), 47 deletions(-) diff --git a/SCOPE.md b/SCOPE.md index 4a2db4e..d0efe2e 100644 --- a/SCOPE.md +++ b/SCOPE.md @@ -141,8 +141,8 @@ It operates on three levels, per `wiki/ProductRequirementsDocument.md`: ## Provided Capabilities Registered in `registry/capabilities/capability.procurement.vergabe-teilnahme.md` -(reuse-surface federation, D1/A1/C0/R0 as of the initial coverage sweep — -low discovery confidence pending this SCOPE.md's first real fill-in). +(reuse-surface federation; vector **D3/A1/C1/R1** after SCOPE.md fill-in and +REUSE-WP-0017-T05 entry-2 review, 2026-07-07). --- diff --git a/registry/capabilities/capability.procurement.vergabe-teilnahme.md b/registry/capabilities/capability.procurement.vergabe-teilnahme.md index 69257c7..c2ae717 100644 --- a/registry/capabilities/capability.procurement.vergabe-teilnahme.md +++ b/registry/capabilities/capability.procurement.vergabe-teilnahme.md @@ -12,41 +12,52 @@ tags: - vergabe maturity: discovery: - current: D1 - target: D3 - confidence: low - rationale: SCOPE.md is an unfilled template (placeholders only) and README.md is a stale repo-seed - leftover; discovery rests entirely on direct inspection of the codebase (pyproject description, - manage.py, vergabe_teilnahme Django app, docker-compose.test.yml with a dedicated Postgres test - database) rather than on written scope documentation. + current: D3 + target: D4 + confidence: medium + rationale: SCOPE.md filled 2026-07-07 with in/out scope, current state, terminology, and orientation + pointers; supported by wiki/ProductRequirementsDocument.md (German product definition) and + wiki/ArchitectureBlueprint.md. README.md remains a stale repo-seed leftover — SCOPE and wiki + are authoritative for discovery. availability: current: A1 target: A3 confidence: medium - rationale: Full Django application (413+ files) with manage.py, a vergabe_teilnahme package, and a - Vite/Tailwind frontend; docker-compose.dev.yml and docker-compose.test.yml exist but no hosted deployment - confirmed in this sweep. + rationale: Substantial Django application (12 domain apps, WP-0001–WP-0017 implemented) with + Vite/Tailwind frontend and docker-compose dev/test; SCOPE.md describes internal collaboration + use only — no hosted production deployment confirmed in this review. external_evidence: completeness: - level: C0 - confidence: low + level: C1 + confidence: medium basis: scope_vs_intent_and_consumer_expectations - satisfied_expectations: [] + satisfied_expectations: + - in-scope/out-of-scope boundaries documented in SCOPE.md + - 8-phase tender participation model described with operational/management/strategic levels + - manual-entry-first v1 constraint and external-portal exclusion explicit broken_expectations: [] out_of_scope_expectations: [] reliability: - level: R0 + level: R1 confidence: low basis: consumer_quality_signals known_reliability_risks: - - SCOPE.md is an unfilled template — this repo's own scope documentation does not yet exist - - no independent verification of test suite health in this sweep + - no CI workflow configured yet (per SCOPE.md current state) + - no production consumer telemetry (REUSE-WP-0019) + - README.md still stale repo-seed text — fix separately discovery: - intent: Manage German public-procurement (Vergabe) tender participation workflows as a Django application, - per its own pyproject description (Ausschreibungs- und Teilnahme-Management-System). + intent: Guide a team through the full lifecycle of bidding on public or private tenders (Ausschreibungen) + — from research and participate/no-bid decisions through submission and post-award retrospective. includes: - - tender/Ausschreibung participation management (Django app + Vite frontend) - excludes: [] + - tender (Ausschreibung) and lot (Los) tracking across 8 navigable phases + - requirements analysis and bidder-question (Bieterfragen) handling + - tasks (Aufgaben), documents (Dokumente), pricing (Preise), submission/retrospective (Abgabe/Nachbetrachtung) + - partner/reference library (Bibliothek) and competitor observation (Marktbegleiter) + - issue-core task facade integration (not a UI replacement) + excludes: + - external partner/subcontractor portal accounts (data objects only in v1) + - multi-tenancy + - automated ingestion from tender platforms, SharePoint, Teams, CRM, ERP, email, or calendars assumptions: [] use_cases: [] research_memos: [] @@ -54,68 +65,83 @@ availability: current_level: A1 target_level: A3 current_artifacts: - - Django application (`vergabe_teilnahme`) - - Vite/Tailwind frontend + - Django application (`vergabe_teilnahme`, 12 apps) + - Vite/Tailwind frontend (`static/`) + - docker-compose.dev.yml and docker-compose.test.yml target_artifacts: [] consumption_modes: - application (Django + Vite, local dev via docker-compose) relations: - depends_on: [] + depends_on: + - capability.infotech.issue-tracking supports: [] - related_to: [] + related_to: + - capability.design.whynot-system evidence: documentation: - - pyproject.toml description + - SCOPE.md + - wiki/ProductRequirementsDocument.md + - wiki/ArchitectureBlueprint.md + - pyproject.toml tests: - - conftest.py + - vergabe_teilnahme/apps/*/tests.py (pytest-django suite across domain apps) - docker-compose.test.yml consumer_feedback: [] bug_reports: [] incidents: [] consumer_guidance: recommended_for: - - understanding or extending this specific German procurement participation tool + - teams needing structured German tender-participation workflow tracking (manual-entry-first v1) + - extending or deploying this specific Django application not_recommended_for: - - general reuse — SCOPE.md is unfilled, so consumer expectations are undocumented; treat as low-discovery - until SCOPE.md is written + - automated tender-platform ingestion (out of scope for v1) + - external bidder/partner self-service portals (not built) known_limitations: - - SCOPE.md template is unfilled; this entry's discovery evidence comes from direct code inspection, - not authored scope documentation — filling in SCOPE.md should be the first step before promoting this - entry further -promotion_history: [] + - manual data entry only in v1 — no platform integration + - README.md is still repo-seed boilerplate; use SCOPE.md and wiki/ for orientation +promotion_history: +- date: "2026-07-07" + dimension: discovery + from: D1 + to: D3 + rationale: SCOPE.md filled with full in/out scope and current-state documentation (REUSE-WP-0017-T05 entry-2 review). + author: grok +- date: "2026-07-07" + dimension: completeness + from: C0 + to: C1 + rationale: Consumer scope expectations now documented in SCOPE.md and wiki PRD. + author: grok --- # Vergabe Teilnahme (Public Procurement Participation) Application ## Overview -`vergabe-teilnahme` is a Django application (with a Vite/Tailwind frontend) for managing German public-procurement (Vergabe) tender participation. Its own `SCOPE.md` is an unfilled template, so this entry's discovery level is honestly low (D1) — filling in SCOPE.md is the natural next step before this capability can be promoted further. +`vergabe-teilnahme` is a Django + Vite/Tailwind application for managing German public-procurement (Vergabe) tender participation end-to-end. SCOPE.md (filled 2026-07-07) documents the 8-phase, manual-entry-first v1 model across 12 Django apps. ## Assessment notes ### Discovery -SCOPE.md is an unfilled template (placeholders only) and README.md is a stale repo-seed leftover; discovery rests entirely on direct inspection of the codebase (pyproject description, manage.py, vergabe_teilnahme Django app, docker-compose.test.yml with a dedicated Postgres test database) rather than on written scope documentation. +SCOPE.md now provides authoritative in/out scope, current state, terminology, and pointers to the German-language wiki PRD and architecture blueprint. Discovery promoted from D1 to D3; README cleanup remains a separate hygiene item. ### Availability -Full Django application (413+ files) with manage.py, a vergabe_teilnahme package, and a Vite/Tailwind frontend; docker-compose.dev.yml and docker-compose.test.yml exist but no hosted deployment confirmed in this sweep. +Substantial implemented application (WP-0001–WP-0017) with local docker-compose paths. Held at A1 until a hosted deployment path is confirmed (railiance-apps is named as deployment target in SCOPE.md). ### Completeness -First-pass honest assessment from the REUSE-WP-0017 coverage campaign -(reuse-surface). No external consumer feedback exists yet; levels reflect -scope-vs-intent documentation quality, not internal code quality. +Scope-vs-intent expectations are now documented (C1). Feature completeness against the full PRD is not independently verified in this review. ### Reliability -No production consumer telemetry exists yet; reliability level is -intentionally conservative pending REUSE-WP-0019 reuse-telemetry evidence. +Pytest-django suite exists across domain apps (structural R1). No CI workflow or production telemetry yet. ## Promotion checklist - [x] ID follows `capability..` pattern - [x] Maturity enums match `specs/CapabilityMaturityStandard.md` - [x] `external_evidence` is populated separately from `maturity` -- [ ] Relations reference valid capability IDs (none yet) -- [x] Index entry added in `registry/indexes/capabilities.yaml` +- [x] Relations reference valid capability IDs +- [x] Index entry added in `registry/indexes/capabilities.yaml` \ No newline at end of file diff --git a/registry/indexes/capabilities.yaml b/registry/indexes/capabilities.yaml index e1d5292..1981d4f 100644 --- a/registry/indexes/capabilities.yaml +++ b/registry/indexes/capabilities.yaml @@ -1,12 +1,12 @@ version: 1 -updated: '2026-07-06' +updated: '2026-07-07' domain: helix_forge capabilities: - id: capability.procurement.vergabe-teilnahme name: Vergabe Teilnahme (Public Procurement Participation) Application summary: Django application (with a Vite/Tailwind frontend) for managing German public-procurement (Vergabe) tender participation — Ausschreibungs- und Teilnahme-Management-System. - vector: D1 / A1 / C0 / R0 + vector: D3 / A1 / C1 / R1 domain: communication status: draft owner: vergabe-teilnahme From 2cb8885931be01c8bee1e0d031fa9e19659c22c1 Mon Sep 17 00:00:00 2001 From: tegwick Date: Wed, 8 Jul 2026 12:36:39 +0200 Subject: [PATCH 10/10] Add Forgejo CI smoke workflow (enablement template) --- .forgejo/workflows/ci-smoke.yaml | 29 +++++++++++++++++++++++++++++ 1 file changed, 29 insertions(+) create mode 100644 .forgejo/workflows/ci-smoke.yaml diff --git a/.forgejo/workflows/ci-smoke.yaml b/.forgejo/workflows/ci-smoke.yaml new file mode 100644 index 0000000..bd44c56 --- /dev/null +++ b/.forgejo/workflows/ci-smoke.yaml @@ -0,0 +1,29 @@ +# Canonical CI smoke template (tier 1 routing drill). +# Copy to: .forgejo/workflows/ci-smoke.yaml in consumer repos. +name: CI Smoke + +on: + push: + branches: + - main + workflow_dispatch: + +jobs: + host-smoke: + runs-on: self-hosted + steps: + - name: Routing probe (host runner) + run: | + set -eu + echo "repository=${GITHUB_REPOSITORY:-unknown}" + echo "sha=${GITHUB_SHA:-unknown}" + echo "runner=${RUNNER_NAME:-unknown}" + uname -a + + container-smoke: + runs-on: ubuntu-latest + steps: + - name: Routing probe (container label) + run: | + set -eu + echo "container-smoke ok for ${GITHUB_REPOSITORY:-unknown}" \ No newline at end of file