diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml
index fa48408..3e7dc30 100644
--- a/.github/workflows/ci.yml
+++ b/.github/workflows/ci.yml
@@ -16,8 +16,10 @@ name: CI
on:
push:
branches: [master, main]
+ # Every pull request, whatever it targets. A base-branch filter here would
+ # skip each layer of a stacked PR except the bottom one, which is exactly the
+ # work that most needs checking before it reaches master.
pull_request:
- branches: [master, main]
# Least privilege: jobs only read the repo. Override per-job if more is needed.
permissions:
diff --git a/.github/workflows/pages.yml b/.github/workflows/pages.yml
index 7009ed2..faa5c70 100644
--- a/.github/workflows/pages.yml
+++ b/.github/workflows/pages.yml
@@ -43,7 +43,7 @@ jobs:
run: npm run build
# Static Pages has no gateway/nginx to rewrite the fragment asset prefix,
- # and /__wf/* is outside the project-site mount. Point the marketplace
+ # and /__wf/* is outside the project-site mount. Point the knowledge base
# stylesheet at its real served path (/knowledge-base/style.css → dist/style.css).
- name: Rewrite fragment asset paths for static hosting
run: find dist -name '*.html' -exec sed -i 's#/__wf/knowledge-base/#/knowledge-base/#g' {} +
diff --git a/.github/workflows/pr-requirements.yml b/.github/workflows/pr-requirements.yml
index 1dec647..4767bef 100644
--- a/.github/workflows/pr-requirements.yml
+++ b/.github/workflows/pr-requirements.yml
@@ -5,9 +5,10 @@
name: PR Requirements
on:
+ # No base-branch filter: a stacked PR targets the layer below it, and each
+ # layer needs the same hygiene checks as the one that reaches master.
pull_request:
types: [opened, synchronize, reopened, edited, labeled, unlabeled]
- branches: [master]
# Least privilege: read PR metadata only.
permissions:
@@ -19,6 +20,25 @@ jobs:
name: PR Requirements
runs-on: ubuntu-latest
steps:
+ # A stacked PR targets the layer below it rather than master, so a fixed
+ # allow-list of `master` fails every layer but the bottom one. Allow the
+ # base branch as well when it is itself a convention-named branch — that
+ # still rejects a PR aimed at some unrelated branch, which is what the
+ # check is for, while letting a stack be reviewed layer by layer.
+ - name: Resolve allowed target branches
+ id: targets
+ env:
+ KB_BASE_REF: ${{ github.event.pull_request.base.ref }}
+ KB_BRANCH_PATTERN: '^(feat|feature|fix|bugfix|hotfix|release|support|chore|docs|ci|test)/[a-zA-Z0-9._/-]+$'
+ run: |
+ set -euo pipefail
+ if printf '%s' "$KB_BASE_REF" | grep -Eq "$KB_BRANCH_PATTERN"; then
+ echo "Stacked PR: also allowing the layer below ($KB_BASE_REF)."
+ echo "list=master,$KB_BASE_REF" >> "$GITHUB_OUTPUT"
+ else
+ echo "list=master" >> "$GITHUB_OUTPUT"
+ fi
+
- name: Check PR requirements
uses: AbsaOSS/check-pr-requirements@adb22f6d88c93fd801e787a63d948d6fbbdd4af3 # v0.2.0
with:
@@ -48,4 +68,4 @@ jobs:
# segments in dependabot branches (e.g. dependabot/npm_and_yarn/…).
branch-pattern: "^(feat|feature|fix|bugfix|hotfix|release|support|chore|docs|ci|test|dependabot)/[a-zA-Z0-9._/-]+$"
max-files-changed: "50"
- allowed-target-branches: "master"
+ allowed-target-branches: ${{ steps.targets.outputs.list }}
diff --git a/.github/workflows/validate-doc-app.yml b/.github/workflows/validate-doc-app.yml
index 4c424ef..ecca0a1 100644
--- a/.github/workflows/validate-doc-app.yml
+++ b/.github/workflows/validate-doc-app.yml
@@ -1,6 +1,6 @@
# Reusable workflow — validate a doc app against the knowledge-base contract.
#
-# Called by doc-app repos in their own CI to verify the app meets the marketplace
+# Called by doc-app repos in their own CI to verify the app meets the knowledge base
# contract before raising a PR or publishing a release.
#
# Usage in a doc repo (.github/workflows/validate.yml):
@@ -28,7 +28,7 @@ permissions:
jobs:
validate:
- name: Validate marketplace contract
+ name: Validate knowledge base contract
runs-on: ubuntu-latest
steps:
- name: Checkout
@@ -106,15 +106,15 @@ jobs:
echo "✓ dist/${ENTRY} found"
# ── Validate headless HTML structure ───────────────────────────────────
- - name: Check data-mp-headless attribute
+ - name: Check data-kb-headless attribute
run: |
ENTRY=$(node -e "const m=require('./marketplace.json'); console.log(m.entryPoint || 'index.html')")
- if ! grep -q 'data-mp-headless="true"' "dist/${ENTRY}"; then
- echo "::error file=dist/${ENTRY}::Missing data-mp-headless=\"true\" on element."
- echo "Add data-mp-headless=\"true\" to the tag when building with --headless."
+ if ! grep -q 'data-kb-headless="true"' "dist/${ENTRY}"; then
+ echo "::error file=dist/${ENTRY}::Missing data-kb-headless=\"true\" on element."
+ echo "Add data-kb-headless=\"true\" to the tag when building with --headless."
exit 1
fi
- echo "✓ data-mp-headless=\"true\" found"
+ echo "✓ data-kb-headless=\"true\" found"
- name: Check no fixed site header in headless output
run: |
diff --git a/AGENTS.md b/AGENTS.md
index 110739b..6c5f3d8 100644
--- a/AGENTS.md
+++ b/AGENTS.md
@@ -121,13 +121,13 @@ add a registry entry that requires network or a sibling checkout without it.
### Two build modes, one document
Every page renders through `src/layouts/Base.astro`. Headless (web-fragment) and
-standalone differ only by `data-mp-headless` and the shadow-DOM compat styles —
+standalone differ only by `data-kb-headless` and the shadow-DOM compat styles —
not by a different layout. Changes that add a mode-specific code path need a
strong reason.
### Light only
-The marketplace has no dark mode: no theme toggle, no persisted theme, no `dark`
+The knowledge base has no dark mode: no theme toggle, no persisted theme, no `dark`
class, no dark palette. A sub-app's own theme bootstrap is removed twice:
`scripts/hoist-inline-scripts.js` deletes it while it is still inline, and
`src/utils/transform.js` strips any that survives, along with a `dark` body
diff --git a/CLAUDE.md b/CLAUDE.md
index fc8b5de..5bdcc77 100644
--- a/CLAUDE.md
+++ b/CLAUDE.md
@@ -72,7 +72,7 @@ Orchestrator: `scripts/build-vite.js`. Flags: `--local`, `--headless`.
- `src/pages/index.astro` — Landing catalog page
- `src/utils/apps.js` — `getAppPages()` enumerates sub-app HTML (manifest-driven or filesystem crawl)
- `src/utils/transform.js` — `transformSubAppHtml()`: URL rewriting, document splitting (head/body/title/body-class), headless transforms
-- `src/layouts/Base.astro` — The one document shell: head, marketplace CSS (which carries the self-hosted Inter faces), ``, shadow-DOM compat styles
+- `src/layouts/Base.astro` — The one document shell: head, knowledge base CSS (which carries the self-hosted Inter faces), ``, shadow-DOM compat styles
- `src/components/Masthead.astro` — Persistent Knowledge base header + Library/current-app sub-nav (all pages, both modes)
- `src/components/AppCard.astro`, `src/components/AppIcon.astro` — Catalog card and its icon
- `src/templates/shadow-compat.js` — Shadow-DOM design-token styles, injected into the body by the layout
@@ -90,21 +90,21 @@ An `apps.json` entry is one of:
- **default (packaged)** — a repo publishes a headless static site as `dist.tar.gz` plus `marketplace.json`. Every HTML file becomes a route.
- **`type: "iframe"`** — no artifact; a single route renders a full-viewport `