yadflow 2.5.0 → 2.7.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/CHANGELOG.md +8 -2
- package/README.md +65 -22
- package/bin/yad.mjs +27 -1
- package/cli/docs.mjs +298 -0
- package/cli/doctor.mjs +1 -0
- package/cli/manifest.mjs +23 -2
- package/cli/ship.mjs +37 -0
- package/docs/index.html +44 -13
- package/package.json +2 -2
- package/skills/sdlc/config.yaml +26 -2
- package/skills/sdlc/install.sh +1 -1
- package/skills/sdlc/module-help.csv +11 -4
- package/skills/yad-checks/references/check-gates.md +58 -2
- package/skills/yad-checks/templates/checks/commit-message.sh +82 -0
- package/skills/yad-checks/templates/github/yad-checks.yml +27 -0
- package/skills/yad-checks/templates/github/yad-hub-checks.yml +36 -0
- package/skills/yad-checks/templates/gitlab/yad-checks.gitlab-ci.yml +20 -0
- package/skills/yad-checks/templates/gitlab/yad-hub-checks.gitlab-ci.yml +39 -0
- package/skills/yad-commit/SKILL.md +66 -0
- package/skills/yad-connect-docs/SKILL.md +132 -0
- package/skills/yad-connect-docs/references/docs-registry.md +74 -0
- package/skills/yad-docs/SKILL.md +159 -0
- package/skills/yad-docs/references/data-mapping.md +75 -0
- package/skills/yad-docs/references/theme-map.md +69 -0
- package/skills/yad-docs/templates/app/README.md +31 -0
- package/skills/yad-docs/templates/app/eslint.config.js +23 -0
- package/skills/yad-docs/templates/app/index.html +17 -0
- package/skills/yad-docs/templates/app/package-lock.json +4030 -0
- package/skills/yad-docs/templates/app/package.json +35 -0
- package/skills/yad-docs/templates/app/public/favicon.svg +28 -0
- package/skills/yad-docs/templates/app/public/logo.svg +39 -0
- package/skills/yad-docs/templates/app/public/vite.svg +1 -0
- package/skills/yad-docs/templates/app/src/App.tsx +98 -0
- package/skills/yad-docs/templates/app/src/components/Auth/LoginPage.tsx +101 -0
- package/skills/yad-docs/templates/app/src/components/Canvas/AnimatedMessage.tsx +101 -0
- package/skills/yad-docs/templates/app/src/components/Canvas/ConnectionLine.tsx +90 -0
- package/skills/yad-docs/templates/app/src/components/Canvas/FlowCanvas.tsx +216 -0
- package/skills/yad-docs/templates/app/src/components/Canvas/SystemComponent.tsx +153 -0
- package/skills/yad-docs/templates/app/src/components/Controls/PlaybackBar.tsx +284 -0
- package/skills/yad-docs/templates/app/src/components/Controls/StepDetail.tsx +167 -0
- package/skills/yad-docs/templates/app/src/components/DetailPanel/HandlerLogicSnippet.tsx +41 -0
- package/skills/yad-docs/templates/app/src/components/DetailPanel/RequestPayloadPreview.tsx +46 -0
- package/skills/yad-docs/templates/app/src/components/DetailPanel/RightPanel.tsx +88 -0
- package/skills/yad-docs/templates/app/src/components/DetailPanel/StatusCard.tsx +76 -0
- package/skills/yad-docs/templates/app/src/components/DetailPanel/TriggerEventCard.tsx +45 -0
- package/skills/yad-docs/templates/app/src/components/DocLayout/DocPageShell.tsx +80 -0
- package/skills/yad-docs/templates/app/src/components/DocLayout/DocSectionCard.tsx +55 -0
- package/skills/yad-docs/templates/app/src/components/DocLayout/DocTableOfContents.tsx +79 -0
- package/skills/yad-docs/templates/app/src/components/DocLayout/RoleCard.tsx +67 -0
- package/skills/yad-docs/templates/app/src/components/DocSections/ApiReferenceSection.tsx +108 -0
- package/skills/yad-docs/templates/app/src/components/DocSections/CancelabilitySection.tsx +73 -0
- package/skills/yad-docs/templates/app/src/components/DocSections/CriticalRunbookSection.tsx +177 -0
- package/skills/yad-docs/templates/app/src/components/DocSections/DataMigrationSection.tsx +102 -0
- package/skills/yad-docs/templates/app/src/components/DocSections/DbSchemaSection.tsx +98 -0
- package/skills/yad-docs/templates/app/src/components/DocSections/DeploymentGuideSection.tsx +104 -0
- package/skills/yad-docs/templates/app/src/components/DocSections/DriverIntegrationSection.tsx +127 -0
- package/skills/yad-docs/templates/app/src/components/DocSections/ExecutiveSummarySection.tsx +69 -0
- package/skills/yad-docs/templates/app/src/components/DocSections/FlowOverviewSection.tsx +73 -0
- package/skills/yad-docs/templates/app/src/components/DocSections/FlowPathsChecklistSection.tsx +96 -0
- package/skills/yad-docs/templates/app/src/components/DocSections/MiddlewareChainSection.tsx +107 -0
- package/skills/yad-docs/templates/app/src/components/DocSections/MonitoringAlertingSection.tsx +106 -0
- package/skills/yad-docs/templates/app/src/components/DocSections/NotificationLocalizationSection.tsx +102 -0
- package/skills/yad-docs/templates/app/src/components/DocSections/PMRoadmapSection.tsx +133 -0
- package/skills/yad-docs/templates/app/src/components/DocSections/PerformanceTestingSection.tsx +91 -0
- package/skills/yad-docs/templates/app/src/components/DocSections/RiderIntegrationSection.tsx +99 -0
- package/skills/yad-docs/templates/app/src/components/DocSections/SecuritySection.tsx +74 -0
- package/skills/yad-docs/templates/app/src/components/DocSections/StatusMachineSection.tsx +90 -0
- package/skills/yad-docs/templates/app/src/components/DocSections/TestPlanSection.tsx +163 -0
- package/skills/yad-docs/templates/app/src/components/Logs/SystemLogsTerminal.tsx +126 -0
- package/skills/yad-docs/templates/app/src/components/Navigation/TopNavBar.tsx +90 -0
- package/skills/yad-docs/templates/app/src/components/Reference/BullMQJobsList.tsx +60 -0
- package/skills/yad-docs/templates/app/src/components/Reference/DecisionTreeView.tsx +49 -0
- package/skills/yad-docs/templates/app/src/components/Reference/DeeplinkActionsChips.tsx +69 -0
- package/skills/yad-docs/templates/app/src/components/Reference/DriverUIStatesTable.tsx +61 -0
- package/skills/yad-docs/templates/app/src/components/Reference/FeatureFlagMatrix.tsx +73 -0
- package/skills/yad-docs/templates/app/src/components/Reference/RiderUIStatesTable.tsx +61 -0
- package/skills/yad-docs/templates/app/src/components/Reference/RulesLegendPanel.tsx +217 -0
- package/skills/yad-docs/templates/app/src/components/Reference/StakeholderToggle.tsx +41 -0
- package/skills/yad-docs/templates/app/src/components/Reference/TroubleshootingSection.tsx +93 -0
- package/skills/yad-docs/templates/app/src/components/Sidebar/PathSelector.tsx +148 -0
- package/skills/yad-docs/templates/app/src/components/Sidebar/SidebarFooter.tsx +40 -0
- package/skills/yad-docs/templates/app/src/components/Sidebar/StepList.tsx +234 -0
- package/skills/yad-docs/templates/app/src/components/shared/Badge.tsx +28 -0
- package/skills/yad-docs/templates/app/src/components/shared/CommandPalette.tsx +213 -0
- package/skills/yad-docs/templates/app/src/components/shared/Icon.tsx +21 -0
- package/skills/yad-docs/templates/app/src/components/shared/Tooltip.tsx +42 -0
- package/skills/yad-docs/templates/app/src/data/components.ts +74 -0
- package/skills/yad-docs/templates/app/src/data/docSections.ts +231 -0
- package/skills/yad-docs/templates/app/src/data/paths.ts +2319 -0
- package/skills/yad-docs/templates/app/src/data/referenceData.ts +392 -0
- package/skills/yad-docs/templates/app/src/data/roles.ts +145 -0
- package/skills/yad-docs/templates/app/src/data/types.ts +79 -0
- package/skills/yad-docs/templates/app/src/hooks/useAnimationQueue.ts +41 -0
- package/skills/yad-docs/templates/app/src/hooks/usePlayback.ts +100 -0
- package/skills/yad-docs/templates/app/src/hooks/useStakeholderFilter.ts +10 -0
- package/skills/yad-docs/templates/app/src/index.css +121 -0
- package/skills/yad-docs/templates/app/src/main.tsx +13 -0
- package/skills/yad-docs/templates/app/src/pages/RoleSelectPage.tsx +34 -0
- package/skills/yad-docs/templates/app/src/pages/StakeholderDocPage.tsx +98 -0
- package/skills/yad-docs/templates/app/src/pages/SubPathDetailPage.tsx +282 -0
- package/skills/yad-docs/templates/app/src/store/useAuthStore.ts +42 -0
- package/skills/yad-docs/templates/app/src/store/useFlowStore.ts +197 -0
- package/skills/yad-docs/templates/app/src/utils/iconMap.ts +46 -0
- package/skills/yad-docs/templates/app/tsconfig.app.json +28 -0
- package/skills/yad-docs/templates/app/tsconfig.json +7 -0
- package/skills/yad-docs/templates/app/tsconfig.node.json +26 -0
- package/skills/yad-docs/templates/app/vite.config.ts +10 -0
- package/skills/yad-docs-overview/SKILL.md +129 -0
- package/skills/yad-docs-overview/references/pipeline-model.md +102 -0
- package/skills/yad-docs-sync/SKILL.md +99 -0
- package/skills/yad-docs-sync/references/staleness.md +81 -0
- package/skills/yad-engineer-review/SKILL.md +86 -0
- package/skills/{yad-ship → yad-engineer-review}/references/ship-and-record.md +2 -2
- package/skills/{yad-ship → yad-engineer-review}/templates/.coderabbit.yaml +1 -1
- package/skills/yad-epic/references/state-schema.md +1 -1
- package/skills/yad-implement/SKILL.md +1 -1
- package/skills/yad-implement/references/implement-conventions.md +1 -1
- package/skills/yad-open-pr/SKILL.md +72 -0
- package/skills/yad-pr-template/templates/checks/pr-template.sh +62 -0
- package/skills/yad-pr-template/templates/checks/pr-title.sh +51 -0
- package/skills/yad-run/SKILL.md +2 -2
- package/skills/yad-run/references/run-loop.md +4 -4
- package/skills/yad-ship/SKILL.md +44 -66
- package/skills/yad-spec/SKILL.md +1 -1
|
@@ -0,0 +1,99 @@
|
|
|
1
|
+
---
|
|
2
|
+
name: yad-docs-sync
|
|
3
|
+
description: 'The maintenance/CI reconciler for the generated docs sites — mirroring the `yad check` / `yad gate ci` drift pattern. Recomputes each site''s freshness hashes (per-epic: the artifact hash + repo HEADs; overview: config.yaml + module-help.csv + the overview diagram + skill count) and compares them to each docs-build.json baseline: a site is stale when any hash differs or its shell template is out of date. `--check` (default, read-only) reports which sites are stale and WHY; `--refresh` regenerates + redeploys each stale site; `--wire` commits the CI workflow that runs the check on push and rebuilds on staleness. Refresh is always a human/CI decision, never silent; docs are never a gate. Use when the user says "sync the docs", "check docs staleness", "refresh stale docs sites", or "wire the docs CI".'
|
|
4
|
+
---
|
|
5
|
+
|
|
6
|
+
# SDLC — Sync the Docs Sites (the staleness reconciler)
|
|
7
|
+
|
|
8
|
+
**Goal:** Keep the generated docs sites in step with the artifacts they render — the per-epic sites
|
|
9
|
+
(`epics/EP-<slug>/docs-site/`) and the project overview (`docs/sdlc-site/`). It mirrors the `yad check`
|
|
10
|
+
/ `yad gate ci` reconcile pattern: it does **not** re-author content; it **detects drift** between each
|
|
11
|
+
site's `docs-build.json` baseline and the current inputs, and reports / refreshes / wires CI accordingly.
|
|
12
|
+
|
|
13
|
+
Docs are an output enrichment, so this skill is **never a gate** — it never touches `state.json`,
|
|
14
|
+
approvals, or the contract lock. Refreshing a stale site is always a **human or CI decision**, never
|
|
15
|
+
silent (the same discipline as `yad repo refresh`).
|
|
16
|
+
|
|
17
|
+
## Conventions
|
|
18
|
+
|
|
19
|
+
- `{project-root}` resolves from the project working directory (the **product hub**).
|
|
20
|
+
- Per-epic baseline: `epics/EP-<slug>/.sdlc/docs-build.json` (written by `yad-docs`). Overview baseline:
|
|
21
|
+
`docs/sdlc-site/.docs-build.json` (written by `yad-docs-overview`).
|
|
22
|
+
- The hashing + build + deploy is the **`yad docs sync` CLI**'s job; the regeneration of a stale site is
|
|
23
|
+
delegated back to `yad-docs` / `yad-docs-overview` (the AI generation step). This skill orchestrates
|
|
24
|
+
the reconcile.
|
|
25
|
+
- The docs target is `.sdlc/docs.json` (`yad-connect-docs`).
|
|
26
|
+
- Speak in the configured `communication_language`; write documents in `document_output_language`.
|
|
27
|
+
|
|
28
|
+
## Inputs
|
|
29
|
+
|
|
30
|
+
- `action` — `check` (default, read-only) | `refresh` | `wire`.
|
|
31
|
+
- `epic` — optional. Default: **sweep all epics** under `epics/` **plus the overview**. Given an
|
|
32
|
+
`EP-<slug>`, scope to that one site.
|
|
33
|
+
|
|
34
|
+
## On Activation
|
|
35
|
+
|
|
36
|
+
### Step 1 — Compute the current freshness hashes per target
|
|
37
|
+
For each target in scope, recompute its hash inputs (exact inputs in `references/staleness.md`):
|
|
38
|
+
|
|
39
|
+
- **Per-epic** (`epics/EP-<slug>/`): the `artifactHash` (sha256 of `epic.md` + `architecture.md` +
|
|
40
|
+
`contract.md` CONTRACT-SURFACE + `ui-design.md` + each story) **and** `repoHeads` (current
|
|
41
|
+
`git -C <path> rev-parse HEAD` for each repo in `epic.repos`).
|
|
42
|
+
- **Overview** (`docs/sdlc-site/`): sha256 of `skills/sdlc/config.yaml` + `skills/sdlc/module-help.csv`
|
|
43
|
+
+ `docs/diagrams/sdlc-overview.mmd` + the current `skillCount` (number of `yad-*` skills).
|
|
44
|
+
|
|
45
|
+
This is the same drift computation `yad check` runs for repos; reuse the repos.json HEAD-sha rule.
|
|
46
|
+
|
|
47
|
+
### Step 2 — Compare to each build manifest
|
|
48
|
+
Read each `docs-build.json` and compare. A site is **stale** when **any** of:
|
|
49
|
+
- its `artifactHash` differs (a rendered artifact moved), or
|
|
50
|
+
- any `repoHeads[<repo>]` differs from the repo's current HEAD (the code the components cite advanced —
|
|
51
|
+
the same head-sha staleness as `repos.json`), or
|
|
52
|
+
- for the overview, `config.yaml` / `module-help.csv` / the `.mmd` / `skillCount` moved, or
|
|
53
|
+
- its `templateVersion` < the current shell template version (the shell was upgraded).
|
|
54
|
+
|
|
55
|
+
A missing `docs-build.json` (a site never generated) counts as **stale → needs generate**.
|
|
56
|
+
|
|
57
|
+
### Step 3 — Act on `action`
|
|
58
|
+
- **`check`** (default, **read-only**) — print which sites are stale and **WHY**, in `yad check` drift
|
|
59
|
+
style: *which artifact moved* (name it), *which repo HEAD advanced* (`<repo>: <old>→<new>`), *config /
|
|
60
|
+
manifest / diagram / skill-count changed*, or *shell upgraded* (`templateVersion`). Writes nothing.
|
|
61
|
+
- **`refresh`** — for each stale site, re-run the generator (`yad-docs` for an epic site, `yad-docs-overview`
|
|
62
|
+
for the overview) to regenerate `src/data/*.ts` + theme + manifest, then redeploy via `yad docs deploy`
|
|
63
|
+
(degrading to build-only when no platform CLI). Report every site refreshed. **Never silent** — refresh
|
|
64
|
+
is a deliberate human/CI act, surfaced exactly like `yad repo refresh`.
|
|
65
|
+
- **`wire`** — commit the CI workflow (Step 4) that automates the check + rebuild.
|
|
66
|
+
|
|
67
|
+
### Step 4 — `wire`: the CI auto-rebuild workflow
|
|
68
|
+
Commit the platform-matched workflow (GitHub `.github/workflows/yad-docs.yml`, or a GitLab `pages` job at
|
|
69
|
+
`.gitlab/ci/yad-docs.yml` that must be `include:`d from the root `.gitlab-ci.yml` —
|
|
70
|
+
`include: { local: .gitlab/ci/yad-docs.yml }`, the same fragment+include shape as the `yad-checks` gates):
|
|
71
|
+
- on push, run **`yad docs sync --check`**; on detected staleness, **rebuild + deploy** the affected
|
|
72
|
+
site(s);
|
|
73
|
+
- carry **`[skip ci]`** on any commit the workflow itself makes (the regenerated source / manifest) and
|
|
74
|
+
a **concurrency group** (one docs deploy at a time) — both to **prevent deploy loops** (a rebuild must
|
|
75
|
+
not retrigger the workflow). See `references/staleness.md`.
|
|
76
|
+
|
|
77
|
+
### Step 5 — Report
|
|
78
|
+
Report per target: **fresh** or **stale (why)**; for `refresh`, what was regenerated + the deploy URL or
|
|
79
|
+
"build-only"; for `wire`, the workflow path committed. Never advance any epic; docs are not a gate.
|
|
80
|
+
|
|
81
|
+
## Hard rules
|
|
82
|
+
|
|
83
|
+
- **Refresh is never silent.** A stale site is *reported*; regenerating + redeploying is a human or CI
|
|
84
|
+
decision (the `yad repo refresh` discipline). `check` is strictly read-only.
|
|
85
|
+
- **Docs are never a gate.** This skill never touches `state.json`, `approvals.json`, or
|
|
86
|
+
`contract-lock.json`. Staleness blocks nothing in the SDLC; it only flags out-of-date docs.
|
|
87
|
+
- **HEAD-sha staleness, reused.** Repo drift uses the exact `repos.json` `syncedHead`-vs-current-HEAD
|
|
88
|
+
rule. The overview uses config + manifest + diagram + skill-count.
|
|
89
|
+
- **Loop-prevention is mandatory in CI.** The wired workflow must carry `[skip ci]` on its own commits
|
|
90
|
+
and a concurrency group so a deploy never retriggers a deploy.
|
|
91
|
+
- **Reconcile, don't re-author.** This skill detects drift and delegates regeneration to `yad-docs` /
|
|
92
|
+
`yad-docs-overview`; it does not generate `src/data/*.ts` itself.
|
|
93
|
+
|
|
94
|
+
## Reference
|
|
95
|
+
- The manifest schema (per-epic + overview), the exact hash inputs, the head-sha staleness rule, and the
|
|
96
|
+
CI loop-prevention note: `references/staleness.md`.
|
|
97
|
+
- The generators this delegates to: `../yad-docs/SKILL.md`, `../yad-docs-overview/SKILL.md`.
|
|
98
|
+
- The docs target it deploys to: `../yad-connect-docs/SKILL.md`.
|
|
99
|
+
- The drift / refresh discipline this mirrors: `../yad-connect-repos/SKILL.md` (HEAD-sha staleness).
|
|
@@ -0,0 +1,81 @@
|
|
|
1
|
+
# Docs staleness — manifests, hash inputs, and the CI loop note
|
|
2
|
+
|
|
3
|
+
`yad-docs-sync` reconciles each generated site against a **build manifest** (`docs-build.json`) written
|
|
4
|
+
when the site was last generated. A site is **stale** when the manifest's recorded hashes no longer match
|
|
5
|
+
the current inputs, or its shell template is out of date. This mirrors the `repos.json`
|
|
6
|
+
`syncedHead`-vs-current-HEAD drift rule used across the SDLC.
|
|
7
|
+
|
|
8
|
+
## Build manifest schema
|
|
9
|
+
|
|
10
|
+
### Per-epic — `epics/EP-<slug>/.sdlc/docs-build.json` (written by `yad-docs`)
|
|
11
|
+
|
|
12
|
+
```json
|
|
13
|
+
{
|
|
14
|
+
"builtAt": "<YYYY-MM-DD>",
|
|
15
|
+
"theme": "design.json | DESIGN.md | default",
|
|
16
|
+
"artifactHash": "<sha256 of epic.md + architecture.md + contract.md CONTRACT-SURFACE + ui-design.md + each story>",
|
|
17
|
+
"repoHeads": { "<repo>": "<HEAD sha>" },
|
|
18
|
+
"deployUrl": "<url or null>",
|
|
19
|
+
"templateVersion": "<shell template version>"
|
|
20
|
+
}
|
|
21
|
+
```
|
|
22
|
+
|
|
23
|
+
### Overview — `docs/sdlc-site/.docs-build.json` (written by `yad-docs-overview`)
|
|
24
|
+
|
|
25
|
+
```json
|
|
26
|
+
{
|
|
27
|
+
"builtAt": "<YYYY-MM-DD>",
|
|
28
|
+
"theme": "yadflow-brand",
|
|
29
|
+
"artifactHash": "<sha256 of config.yaml + module-help.csv + docs/diagrams/sdlc-overview.mmd>",
|
|
30
|
+
"skillCount": <number of yad-* skills>,
|
|
31
|
+
"deployUrl": "<url or null>",
|
|
32
|
+
"templateVersion": "<shell template version>"
|
|
33
|
+
}
|
|
34
|
+
```
|
|
35
|
+
|
|
36
|
+
## Exact hash inputs
|
|
37
|
+
|
|
38
|
+
| Target | `artifactHash` inputs | head inputs |
|
|
39
|
+
|--------|-----------------------|-------------|
|
|
40
|
+
| **per-epic** | `epic.md` + `architecture.md` + `contract.md` **CONTRACT-SURFACE only** + `ui-design.md` + **each** `stories/*.md` (concatenated in stable story-id order, hashed sha256) | `repoHeads`: `git -C <path> rev-parse HEAD` for each repo in `epic.repos` |
|
|
41
|
+
| **overview** | `skills/sdlc/config.yaml` + `skills/sdlc/module-help.csv` + `docs/diagrams/sdlc-overview.mmd`, concatenated in that order, hashed sha256 (`skillCount` is an informational manifest field, not a hash input — `module-help.csv` already moves when the skill set does) | — (no repos) |
|
|
42
|
+
|
|
43
|
+
Because `yad-docs` generates `src/data/*.ts` **deterministically** (stable-ID sort, fixed key order, no
|
|
44
|
+
embedded timestamps), an unchanged input set re-hashes identically — so a hash move means a *real*
|
|
45
|
+
content move, not a regeneration artifact. The contract uses the **CONTRACT-SURFACE block only** so
|
|
46
|
+
non-surface edits to `contract.md` don't churn the docs.
|
|
47
|
+
|
|
48
|
+
## Staleness rule
|
|
49
|
+
|
|
50
|
+
A site is **stale** when ANY holds:
|
|
51
|
+
|
|
52
|
+
1. recomputed `artifactHash` ≠ manifest `artifactHash` — a rendered artifact moved (name it in the report);
|
|
53
|
+
2. for any repo, current HEAD ≠ manifest `repoHeads[<repo>]` — the cited code advanced (`<repo>:
|
|
54
|
+
<old>→<new>`). **Identical to the `repos.json` `syncedHead` staleness rule** — and, as there, a stale
|
|
55
|
+
repo is *flagged*, never auto-refreshed: the `code-context` itself is refreshed by a human via
|
|
56
|
+
`yad repo refresh`, and the docs are regenerated only on an explicit `refresh`/CI decision;
|
|
57
|
+
3. (overview) `config.yaml` / `module-help.csv` / the `.mmd` moved — the pipeline changed (this is what
|
|
58
|
+
enforces "the overview regenerates whenever the workflow definition or skill set changes"); or the
|
|
59
|
+
`templateVersion` (the yad CLI version) advanced — the doc shell upgraded;
|
|
60
|
+
4. manifest `templateVersion` < the current shell template version — the `templates/app/` shell was
|
|
61
|
+
upgraded, so every site should re-copy it;
|
|
62
|
+
5. the `docs-build.json` is **missing** — the site was never generated (treat as stale → generate).
|
|
63
|
+
|
|
64
|
+
`check` reports which of these tripped and why; `refresh` regenerates + redeploys; neither blocks any
|
|
65
|
+
SDLC step (docs are never a gate).
|
|
66
|
+
|
|
67
|
+
## CI loop-prevention note
|
|
68
|
+
|
|
69
|
+
The `wire` workflow (`.github/workflows/yad-docs.yml`, or the GitLab `pages` job at
|
|
70
|
+
`.gitlab/ci/yad-docs.yml` included from the root `.gitlab-ci.yml`) runs
|
|
71
|
+
`yad docs sync --check` on push and rebuilds + deploys on staleness. Because the rebuild **commits** the
|
|
72
|
+
regenerated `src/data/*.ts` + refreshed `docs-build.json`, that commit would re-trigger the same workflow
|
|
73
|
+
— a deploy loop. Two guards, both mandatory:
|
|
74
|
+
|
|
75
|
+
- **`[skip ci]`** in the message of any commit the workflow itself makes (the regenerated source +
|
|
76
|
+
manifest), so the workflow does not re-fire on its own output;
|
|
77
|
+
- a **concurrency group** (e.g. `concurrency: { group: yad-docs-deploy, cancel-in-progress: true }`) so
|
|
78
|
+
at most one docs build/deploy runs at a time, and a queued one is superseded rather than stacking.
|
|
79
|
+
|
|
80
|
+
Together these make the CI rebuild idempotent: a push that moves an artifact deploys exactly one fresh
|
|
81
|
+
site, and the resulting bot commit does not start another round.
|
|
@@ -0,0 +1,86 @@
|
|
|
1
|
+
---
|
|
2
|
+
name: yad-engineer-review
|
|
3
|
+
description: 'Build-half Step E of the gated SDLC — AI review, engineer review, then merge. Wire an advisory AI first-pass (CodeRabbit) on the PR/MR; record the human engineer review with the same human_approve discipline as the front gates (owner + 1 reviewer, escalating to domain owners on high risk / contract / auth / payments — the Step D routing); and on merge, record the ship in the epic build-log and update the story state so the epic → story → task → PR chain is traceable. Never auto-advances — the human owns the merge. Use when the user says "record the engineer review", "merge this task", or "wire the AI review". (To commit + open the PR/MR, use yad-ship.)'
|
|
4
|
+
---
|
|
5
|
+
|
|
6
|
+
# SDLC — Engineer Review & Merge (build-half Step E)
|
|
7
|
+
|
|
8
|
+
**Goal:** Take a task PR/MR that has passed the **check gates** (Step C) through two sets of eyes and
|
|
9
|
+
out to production: an **AI first-pass** (advisory) and a **human engineer review** (the authority),
|
|
10
|
+
then **ship** — merge, record the ship, and update the story state. This is the last build-half step
|
|
11
|
+
(build plan §E). It is a **human gate**, the same `human_approve` discipline as the front states:
|
|
12
|
+
**nothing auto-advances**; the engineer owns the merge.
|
|
13
|
+
|
|
14
|
+
## Conventions
|
|
15
|
+
|
|
16
|
+
- `{project-root}` resolves from the project working directory — the **product** repo (the source of
|
|
17
|
+
truth: it holds the story and the build ledger).
|
|
18
|
+
- Code repos are separate git repos under `{project-root}/demo-repos/<repo>/`.
|
|
19
|
+
- The build ledger is `{project-root}/epics/<epic>/.sdlc/build-log.json` (append-only).
|
|
20
|
+
- The engineer-review rule reuses `yad-review-gate`: base = at least one `owner` AND one distinct
|
|
21
|
+
`reviewer`; **escalated** (the PR's Impact & Risk is `high`, or it touches contract/auth/payments) =
|
|
22
|
+
base PLUS one `domain-owner` per touched domain — the same routing `yad-pr-template`'s
|
|
23
|
+
`risk-route.sh` prints.
|
|
24
|
+
- AI review wiring: `templates/.coderabbit.yaml` → `<repo>/.coderabbit.yaml`.
|
|
25
|
+
|
|
26
|
+
## Inputs
|
|
27
|
+
|
|
28
|
+
- `epic` / `story` / `task` / `repo` — the PR under review (the task branch `feat/<story>-<task>-…`).
|
|
29
|
+
- `action` — `ai-review` | `approve` | `ship` (default `ai-review`).
|
|
30
|
+
- For `approve`: the reviewer `name` and `role` (`owner` | `reviewer` | `domain-owner`), and for a
|
|
31
|
+
domain owner the `domain`.
|
|
32
|
+
|
|
33
|
+
## On Activation
|
|
34
|
+
|
|
35
|
+
### Step 1 — `ai-review` (advisory first pass)
|
|
36
|
+
Ensure the AI reviewer is wired: copy `templates/.coderabbit.yaml` to `<repo>/.coderabbit.yaml` (commit
|
|
37
|
+
on the default branch if missing). CodeRabbit reviews each PR automatically and posts comments — it is
|
|
38
|
+
a **second set of eyes, never the authority**: it cannot approve or merge. Where CodeRabbit can't run
|
|
39
|
+
(no remote), run an equivalent AI first-pass by hand and capture its notes. Record that the AI review
|
|
40
|
+
ran; surface its findings to the engineer. Do **not** treat AI approval as a gate.
|
|
41
|
+
|
|
42
|
+
### Step 2 — `approve` (the engineer review — the human gate)
|
|
43
|
+
A human engineer reads the diff **against the spec** (`specs/<story>/`) and the acceptance criteria,
|
|
44
|
+
and records an approval. Determine the rule from the PR's Impact & Risk block (run
|
|
45
|
+
`../yad-pr-template/templates/checks/risk-route.sh` on the PR body): base, or escalated to a
|
|
46
|
+
domain-owner per touched domain. Record each approval; re-evaluate whether the rule is satisfied.
|
|
47
|
+
Recording an approval does **not** ship — shipping is a separate, explicit step. Front-half discipline:
|
|
48
|
+
the gate talks only through files; refuse to treat AI review as a human approval.
|
|
49
|
+
|
|
50
|
+
### Step 3 — `ship` (merge + record + update state)
|
|
51
|
+
Ship **iff ALL hold**: the check gates pass (Step C), the AI review has run (advisory), and the
|
|
52
|
+
engineer-review rule is satisfied (Step 2). Then:
|
|
53
|
+
- **Merge** the task branch into the repo's default branch (the human performs/authorises the merge).
|
|
54
|
+
- **Record the ship** — append to `epics/<epic>/.sdlc/build-log.json`:
|
|
55
|
+
```json
|
|
56
|
+
{ "story": "<story>", "task": "<task>", "repo": "<repo>", "branch": "feat/<story>-<task>-…",
|
|
57
|
+
"pr": "<url|#>", "mergeCommit": "<sha>", "gates": ["spec-link","contract-check","build-test-lint"],
|
|
58
|
+
"ai_review": "coderabbit (advisory)", "engineer_review": [{"approver":"<name>","role":"<role>","domain":"<opt>"}],
|
|
59
|
+
"risk": "<low|medium|high>", "shippedAt": "<YYYY-MM-DD>" }
|
|
60
|
+
```
|
|
61
|
+
- **Update the story state** — when **every** task in `specs/<story>/tasks.md` has a ship record, set
|
|
62
|
+
the story frontmatter `status: shipped`; otherwise `status: in-build`. The chain
|
|
63
|
+
**epic → story → task → PR → mergeCommit** is now traceable end to end.
|
|
64
|
+
- **Finalize the trust verdict (Phase 4).** If this story has a `build-state/<story>.json` (it ran
|
|
65
|
+
through `yad-run`), the engineer **confirms or overrides** the provisional trust verdict that the
|
|
66
|
+
orchestrator derived for this run, and the final verdict is written to
|
|
67
|
+
`epics/<epic>/.sdlc/trust-log.json`. The human has the last word on the trust signal: a diff merged
|
|
68
|
+
as authored is `approved-unchanged`; one the engineer edited before merge is `approved-with-edits`;
|
|
69
|
+
a rejected one is `rejected`. This is the evidence that later earns a step its `machine_advance`
|
|
70
|
+
(it never weakens the merge gate — the engineer still owns the merge).
|
|
71
|
+
|
|
72
|
+
### Step 4 — Stop
|
|
73
|
+
Report what shipped and the story's state. Do not advance anything else; the front-half `state.json`
|
|
74
|
+
stays as it was (`ready-for-build`). The build half is recorded in `build-log.json` + the story status.
|
|
75
|
+
|
|
76
|
+
## Hard rules (build plan §E, Cross-cutting)
|
|
77
|
+
|
|
78
|
+
- **AI review is advisory, never the authority.** Only a human engineer approval counts toward the gate.
|
|
79
|
+
- **High risk routes to domain owners** — the same escalation as `yad-review-gate` / `risk-route.sh`.
|
|
80
|
+
- **Ship only after gates + engineer review.** No gate skipped; the human owns the merge.
|
|
81
|
+
- **Nothing auto-advances.** Step E records human decisions in files; it never machine-advances.
|
|
82
|
+
|
|
83
|
+
## Reference
|
|
84
|
+
- The build ledger + story-state rules: `references/ship-and-record.md`.
|
|
85
|
+
- The escalation reused: `../yad-review-gate/SKILL.md`; the routing helper: `../yad-pr-template/`.
|
|
86
|
+
- The gates that must pass first: `../yad-checks/references/check-gates.md`.
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
# Ship — the build ledger and the story state
|
|
2
2
|
|
|
3
|
-
Step E (`yad-
|
|
3
|
+
Step E (`yad-engineer-review`) closes the build half: AI review (advisory) → engineer review (the human gate) →
|
|
4
4
|
ship. Shipping records the merge and updates the story state so the whole chain is traceable.
|
|
5
5
|
|
|
6
6
|
## Two sets of eyes
|
|
@@ -64,4 +64,4 @@ trailer → story → epic).
|
|
|
64
64
|
2. The **AI review** has run (advisory; findings surfaced to the engineer).
|
|
65
65
|
3. The **engineer review** rule is satisfied (base or escalated per the Impact & Risk block).
|
|
66
66
|
|
|
67
|
-
Only then does the human merge and `yad-
|
|
67
|
+
Only then does the human merge and `yad-engineer-review` record it. Nothing auto-advances.
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
# CodeRabbit — AI first-pass review (Phase 3 build plan §E).
|
|
2
2
|
# Advisory only: a second set of eyes that COMMENTS on every PR. It never approves or merges — the
|
|
3
|
-
# human engineer review (yad-review-gate discipline) owns that decision. See skills/yad-
|
|
3
|
+
# human engineer review (yad-review-gate discipline) owns that decision. See skills/yad-engineer-review.
|
|
4
4
|
language: en
|
|
5
5
|
reviews:
|
|
6
6
|
request_changes_workflow: false # never block the merge — the engineer review is the gate
|
|
@@ -216,7 +216,7 @@ base** that decides when a step is safe to automate (build plan Step A). One ent
|
|
|
216
216
|
|------|---------|-------------------------------|
|
|
217
217
|
| `spec` | `human_edited_spec` | the human who accepts `specs/<story>/` (`yad-spec` Step 8) |
|
|
218
218
|
| `tasks` | `task_rescoped` | first consume by `yad-implement` (Step 8) |
|
|
219
|
-
| `implement` | `human_edited_diff`, `scope_overrun`, `contract_touch` | engineer review at `yad-
|
|
219
|
+
| `implement` | `human_edited_diff`, `scope_overrun`, `contract_touch` | engineer review at `yad-engineer-review` |
|
|
220
220
|
| `checks` | `checks` (`pass`\|`fail`) | the gate run itself (objective) |
|
|
221
221
|
|
|
222
222
|
**Deriving the provisional verdict** (build plan Step A; extended for `spec`/`tasks` in Phase 4b — the
|
|
@@ -124,7 +124,7 @@ finalize a `tasks` trust entry, anchored to what the human/dev actually did with
|
|
|
124
124
|
Append the entry to `epics/<epic>/.sdlc/trust-log.json` (schema:
|
|
125
125
|
`../yad-epic/references/state-schema.md`). `tasks` stays `human_approve` until its slice clears
|
|
126
126
|
the threshold — this only *gathers* evidence. (The `implement` step's own verdict is finalized later,
|
|
127
|
-
at the engineer review in `yad-
|
|
127
|
+
at the engineer review in `yad-engineer-review`: merged as authored → `approved-unchanged`; edited first →
|
|
128
128
|
`approved-with-edits`; scope/contract/checks halt → `rejected`.)
|
|
129
129
|
|
|
130
130
|
## Hard rules (build plan §B, Cross-cutting)
|
|
@@ -59,7 +59,7 @@ Co-Authored-By: CodeRabbit <noreply@coderabbit.ai>
|
|
|
59
59
|
|
|
60
60
|
- Choose the entry whose `id` matches the tool that actually helped author the diff; add more than one
|
|
61
61
|
line if several did. CodeRabbit is a co-author only when it **contributed code**, not when it merely
|
|
62
|
-
reviewed (that is `ai_review` in `yad-
|
|
62
|
+
reviewed (that is `ai_review` in `yad-engineer-review`).
|
|
63
63
|
- For a fully human-authored commit, pick `id: none` — i.e. **omit** the trailer. `ai_coauthor.required`
|
|
64
64
|
is `false`, so a missing trailer is valid and no gate fails on it.
|
|
65
65
|
- `yad-implement` installs the `.gitmessage` template (`templates/.gitmessage`) and sets
|
|
@@ -0,0 +1,72 @@
|
|
|
1
|
+
---
|
|
2
|
+
name: yad-open-pr
|
|
3
|
+
description: 'Build-half helper of the gated SDLC. Open a code-repo task PR/MR from the committed platform template — detect GitHub/GitLab, push the current task branch, and create the PR/MR with the template body prefilled (Summary / Story-task / Impact & Risk) and the title defaulting to the commit subject. Auto-assigns from the hub roster: assignee = the committer, reviewers = the repo''s reviewers + domain-owners. High risk / contract surface routes to domain owners (risk-route.sh). Drives the `yad open-pr` CLI; never merges. Use when the user says "open the PR", "open the MR", or "raise the merge request".'
|
|
4
|
+
---
|
|
5
|
+
|
|
6
|
+
# SDLC — Open Task PR/MR (build-half helper)
|
|
7
|
+
|
|
8
|
+
**Goal:** Open the PR/MR for the current task branch from the repo's committed PR/MR template
|
|
9
|
+
(installed by `yad-pr-template`, Step D), with the body prefilled and the right reviewers requested.
|
|
10
|
+
This is the standalone open-PR step; it **never merges** — the engineer review (`yad-engineer-review`,
|
|
11
|
+
Step E) owns the merge. Distinct from `yad gate open`, which opens a front-half artifact-review PR on
|
|
12
|
+
the product hub.
|
|
13
|
+
|
|
14
|
+
## Conventions
|
|
15
|
+
|
|
16
|
+
- Run **inside the code repo** under `{project-root}/demo-repos/<repo>/` (or pass `--repo <name>` to
|
|
17
|
+
resolve it from `.sdlc/repos.json`). The branch must be the task branch, not the default branch.
|
|
18
|
+
- **Platform** is detected from the `origin` remote (or the registry / `--platform`).
|
|
19
|
+
- **Title** — defaults to the last commit subject (one atomic task = one branch = one PR/MR), so it
|
|
20
|
+
follows the same Conventional-Commits style and passes the `pr-title` gate. Override with `--title`.
|
|
21
|
+
- **Body** — the committed template (`.github/pull_request_template.md` /
|
|
22
|
+
`.gitlab/merge_request_templates/Default.md`) with `Task:`, `Risk level:`, `Contract surface
|
|
23
|
+
touched:`, and `Domains` prefilled; the rest is left for the author. This satisfies the `pr-template`
|
|
24
|
+
gate.
|
|
25
|
+
- **Auto-assign** — from the hub roster scoped to this repo: assignee = the committer (resolved from
|
|
26
|
+
the local git identity), reviewers = the repo's `reviewer`/`domain-owner` logins minus the committer.
|
|
27
|
+
Degrades cleanly when there is no roster.
|
|
28
|
+
- **Routing** — `low`/`medium` → base rule (owner + 1 reviewer); `high` (or a touched
|
|
29
|
+
contract/auth/payments surface) → plus one domain-owner per touched domain. `bash
|
|
30
|
+
checks/risk-route.sh <body>` prints the required reviewers.
|
|
31
|
+
|
|
32
|
+
## Inputs
|
|
33
|
+
|
|
34
|
+
- `repo` — target a registered repo by name (optional; else the current dir).
|
|
35
|
+
- `risk` — `low|medium|high` (default `low`); prefilled into the body.
|
|
36
|
+
- `contractChange` — flag; marks the contract surface touched and triggers escalation.
|
|
37
|
+
- `base` / `platform` / `title` — optional overrides.
|
|
38
|
+
|
|
39
|
+
## On Activation
|
|
40
|
+
|
|
41
|
+
### Step 1 — Confirm the branch and template
|
|
42
|
+
Confirm you are on the task branch (not the default branch) and that the PR/MR template is committed
|
|
43
|
+
(if not, run `yad-pr-template` first). The branch's commits should already carry the `Task:` trailer.
|
|
44
|
+
|
|
45
|
+
### Step 2 — Open the PR/MR
|
|
46
|
+
Run from the repo root:
|
|
47
|
+
```
|
|
48
|
+
yad open-pr [--repo <name>] [--risk <level>] [--contract-change] [--title "<subject>"]
|
|
49
|
+
```
|
|
50
|
+
The CLI pushes the branch (sets upstream, the user's own auth), fills the template, and creates the
|
|
51
|
+
PR/MR with the auto-assigned assignee + reviewers.
|
|
52
|
+
|
|
53
|
+
### Step 3 — Route the review (if escalated)
|
|
54
|
+
On `high` risk or a contract touch, run `bash checks/risk-route.sh <pr-body>` to print the required
|
|
55
|
+
domain-owner reviewers — the same escalation `yad-engineer-review` enforces.
|
|
56
|
+
|
|
57
|
+
### Step 4 — Stop (no merge)
|
|
58
|
+
Report the PR/MR URL and the requested reviewers. The PR now runs the check gates (Step C); the human
|
|
59
|
+
engineer review and merge happen in `yad-engineer-review` (Step E).
|
|
60
|
+
|
|
61
|
+
## Hard rules
|
|
62
|
+
|
|
63
|
+
- **One task = one branch = one PR/MR.** Never open a PR from the default branch.
|
|
64
|
+
- **Title follows the commit subject** — Conventional-Commits style, so the `pr-title` gate passes.
|
|
65
|
+
- **High risk routes to domain owners** — the same escalation as the gate; never a separate rule.
|
|
66
|
+
- **Opening a PR never merges.** The human owns the merge in Step E.
|
|
67
|
+
|
|
68
|
+
## Reference
|
|
69
|
+
- The PR/MR template + the Impact & Risk block + routing: `../yad-pr-template/references/risk-routing.md`.
|
|
70
|
+
- The gates the PR must pass: `../yad-checks/references/check-gates.md` (incl. `pr-title`, `pr-template`).
|
|
71
|
+
- Commit first: `../yad-commit/SKILL.md`; commit + open in one step: `../yad-ship/SKILL.md`.
|
|
72
|
+
- The engineer review + merge that follow: `../yad-engineer-review/SKILL.md`.
|
|
@@ -0,0 +1,62 @@
|
|
|
1
|
+
#!/usr/bin/env bash
|
|
2
|
+
# pr-template gate.
|
|
3
|
+
# The PR/MR BODY must actually USE the committed template — i.e. carry its required sections so the
|
|
4
|
+
# review (and risk-route.sh) has the inputs it needs. This catches an empty / free-form description
|
|
5
|
+
# that bypassed the template.
|
|
6
|
+
# --profile code (default) — the code-repo task template (yad-pr-template templates/<platform>/):
|
|
7
|
+
# requires `## Summary`, `## Impact & Risk`, `## Checklist`, and a filled `Risk level:` (low|medium|high).
|
|
8
|
+
# --profile hub — the front-half artifact-review template (templates/hub/<platform>/):
|
|
9
|
+
# requires `## Artifact under review`, `## Impact & Risk (front-half)`, `## Checklist`, and a `Risk tags:` line.
|
|
10
|
+
# The body is passed as a FILE path (single positional arg); CI writes the event body to a temp file
|
|
11
|
+
# (GitHub: github.event.pull_request.body; GitLab: $CI_MERGE_REQUEST_DESCRIPTION).
|
|
12
|
+
set -euo pipefail
|
|
13
|
+
|
|
14
|
+
PROFILE=code
|
|
15
|
+
ARGS=()
|
|
16
|
+
while [ $# -gt 0 ]; do
|
|
17
|
+
case "$1" in
|
|
18
|
+
--profile) PROFILE="${2:-code}"; shift 2 ;;
|
|
19
|
+
--profile=*) PROFILE="${1#*=}"; shift ;;
|
|
20
|
+
*) ARGS+=("$1"); shift ;;
|
|
21
|
+
esac
|
|
22
|
+
done
|
|
23
|
+
case "$PROFILE" in code|hub) ;; *) echo "FAIL [pr-template]: unknown --profile '$PROFILE' (code|hub)."; exit 1 ;; esac
|
|
24
|
+
|
|
25
|
+
BODY="${ARGS[0]:-}"
|
|
26
|
+
if [ -z "$BODY" ] || [ ! -f "$BODY" ]; then
|
|
27
|
+
echo "FAIL [pr-template]: body file not found — pass the PR/MR description as a file path."
|
|
28
|
+
exit 1
|
|
29
|
+
fi
|
|
30
|
+
|
|
31
|
+
rc=0
|
|
32
|
+
require_heading() {
|
|
33
|
+
if ! grep -qiE "^[[:space:]]*$1[[:space:]]*$" "$BODY"; then
|
|
34
|
+
echo "FAIL [pr-template]: missing section '${2}' — the PR/MR body does not use the template."
|
|
35
|
+
rc=1
|
|
36
|
+
fi
|
|
37
|
+
}
|
|
38
|
+
|
|
39
|
+
if [ "$PROFILE" = hub ]; then
|
|
40
|
+
require_heading '## Artifact under review' '## Artifact under review'
|
|
41
|
+
require_heading '## Impact & Risk \(front-half\)' '## Impact & Risk (front-half)'
|
|
42
|
+
require_heading '## Checklist' '## Checklist'
|
|
43
|
+
if ! grep -qiE '(\*\*)?Risk tags:' "$BODY"; then
|
|
44
|
+
echo "FAIL [pr-template]: missing 'Risk tags:' line (front-half Impact & Risk)."
|
|
45
|
+
rc=1
|
|
46
|
+
fi
|
|
47
|
+
else
|
|
48
|
+
require_heading '## Summary' '## Summary'
|
|
49
|
+
require_heading '## Impact & Risk' '## Impact & Risk'
|
|
50
|
+
require_heading '## Checklist' '## Checklist'
|
|
51
|
+
# Risk level must be present AND filled with a real value (not the <placeholder>).
|
|
52
|
+
rl="$(grep -iE '(\*\*)?Risk level:' "$BODY" | head -1 \
|
|
53
|
+
| sed -E 's/<!--.*$//; s/^[^:]*://; s/[*`]//g; s/^[[:space:]]*//; s/[[:space:]]*$//' || true)"
|
|
54
|
+
rl="$(printf '%s' "$rl" | tr 'A-Z' 'a-z' | grep -oE 'low|medium|high' | head -1 || true)"
|
|
55
|
+
if [ -z "$rl" ]; then
|
|
56
|
+
echo "FAIL [pr-template]: 'Risk level:' missing or not set to low|medium|high."
|
|
57
|
+
rc=1
|
|
58
|
+
fi
|
|
59
|
+
fi
|
|
60
|
+
|
|
61
|
+
[ "$rc" = 0 ] && echo "PASS [pr-template]: body uses the ${PROFILE} template (required sections present)."
|
|
62
|
+
exit "$rc"
|
|
@@ -0,0 +1,51 @@
|
|
|
1
|
+
#!/usr/bin/env bash
|
|
2
|
+
# pr-title gate.
|
|
3
|
+
# The PR/MR TITLE must follow the convention for its repo kind:
|
|
4
|
+
# --profile code (default) — a Conventional-Commits subject "<type>: <description>", no trailing
|
|
5
|
+
# period (config.yaml build.pr_title_style: same_as_commit_subject; one task = one PR, the title is
|
|
6
|
+
# the squash-merge subject). Keep <type> in sync with cli/manifest.mjs COMMIT_TYPES.
|
|
7
|
+
# --profile hub — a front-half artifact-review title "review: <artifact> (EP-<slug>)", the shape
|
|
8
|
+
# `yad gate open` creates (cli/gate.mjs).
|
|
9
|
+
# The title is passed as the (single) positional arg; CI injects it from the event payload
|
|
10
|
+
# (GitHub: github.event.pull_request.title; GitLab: $CI_MERGE_REQUEST_TITLE).
|
|
11
|
+
set -euo pipefail
|
|
12
|
+
|
|
13
|
+
PROFILE=code
|
|
14
|
+
ARGS=()
|
|
15
|
+
while [ $# -gt 0 ]; do
|
|
16
|
+
case "$1" in
|
|
17
|
+
--profile) PROFILE="${2:-code}"; shift 2 ;;
|
|
18
|
+
--profile=*) PROFILE="${1#*=}"; shift ;;
|
|
19
|
+
*) ARGS+=("$1"); shift ;;
|
|
20
|
+
esac
|
|
21
|
+
done
|
|
22
|
+
case "$PROFILE" in code|hub) ;; *) echo "FAIL [pr-title]: unknown --profile '$PROFILE' (code|hub)."; exit 1 ;; esac
|
|
23
|
+
|
|
24
|
+
TITLE="${ARGS[0]:-}"
|
|
25
|
+
if [ -z "$TITLE" ]; then
|
|
26
|
+
echo "FAIL [pr-title]: empty title — pass the PR/MR title as the argument."
|
|
27
|
+
exit 1
|
|
28
|
+
fi
|
|
29
|
+
|
|
30
|
+
TYPES='feat|fix|docs|refactor|test|perf|build|ci|chore|revert'
|
|
31
|
+
|
|
32
|
+
if [ "$PROFILE" = hub ]; then
|
|
33
|
+
# review: <artifact> (EP-<slug>)
|
|
34
|
+
if printf '%s' "$TITLE" | grep -qE '^review: .+ \(EP-[a-z0-9-]+\)$'; then
|
|
35
|
+
echo "PASS [pr-title]: '${TITLE}' (profile: hub)"
|
|
36
|
+
exit 0
|
|
37
|
+
fi
|
|
38
|
+
echo "FAIL [pr-title]: '${TITLE}' is not a hub review title 'review: <artifact> (EP-<slug>)'."
|
|
39
|
+
exit 1
|
|
40
|
+
fi
|
|
41
|
+
|
|
42
|
+
# code profile — Conventional-Commits subject (optional scope + breaking `!`), no trailing period.
|
|
43
|
+
if ! printf '%s' "$TITLE" | grep -qE "^(${TYPES})(\([a-z0-9._-]+\))?!?: .+"; then
|
|
44
|
+
echo "FAIL [pr-title]: '${TITLE}' is not '<type>(<scope>)?!?: <description>' (type one of: ${TYPES//|/, })."
|
|
45
|
+
exit 1
|
|
46
|
+
fi
|
|
47
|
+
if printf '%s' "$TITLE" | grep -qE '\.$'; then
|
|
48
|
+
echo "FAIL [pr-title]: '${TITLE}' must not end with a period."
|
|
49
|
+
exit 1
|
|
50
|
+
fi
|
|
51
|
+
echo "PASS [pr-title]: '${TITLE}' (profile: code)"
|
package/skills/yad-run/SKILL.md
CHANGED
|
@@ -70,7 +70,7 @@ Walk the steps for `repo` starting at `from`/`currentStep`. For each step:
|
|
|
70
70
|
the next step, and **continue the loop** (this is the Step B auto-advance for `checks`).
|
|
71
71
|
- else (**`human_approve`**) → set the step `done`/`in_review`, **stop** and report
|
|
72
72
|
"waiting for a human at `<next-step>`".
|
|
73
|
-
5. **Always stop at `engineer-review`** (it is `locked`): hand off to `yad-
|
|
73
|
+
5. **Always stop at `engineer-review`** (it is `locked`): hand off to `yad-engineer-review` for the human merge
|
|
74
74
|
gate, which finalizes the trust verdict (confirm/override the provisional one).
|
|
75
75
|
|
|
76
76
|
### `action: set-dial` — earn (or revert) a step's automation
|
|
@@ -106,4 +106,4 @@ reversible (build plan §Safety). Report the new state and that `yad-status` wil
|
|
|
106
106
|
- The loop, the trust-verdict derivation, and the threshold predicate: `references/run-loop.md`.
|
|
107
107
|
- State/trust schemas: `../yad-epic/references/state-schema.md`.
|
|
108
108
|
- The steps it drives: `../yad-spec/`, `../yad-implement/`, `../yad-checks/`; the human gate it
|
|
109
|
-
hands off to: `../yad-
|
|
109
|
+
hands off to: `../yad-engineer-review/`.
|
|
@@ -14,7 +14,7 @@ spec → tasks → implement → checks → engineer-review(locked)
|
|
|
14
14
|
|
|
15
15
|
`spec` and `tasks` are the two legs of `yad-spec` (the heavy ceremony, then the atomic `tasks.md`).
|
|
16
16
|
`implement` is one atomic task via `yad-implement`. `checks` is `yad-checks (action: run)`.
|
|
17
|
-
`engineer-review` is the human gate at `yad-
|
|
17
|
+
`engineer-review` is the human gate at `yad-engineer-review` — always a stop, never automated.
|
|
18
18
|
|
|
19
19
|
## The loop (pseudocode)
|
|
20
20
|
|
|
@@ -40,7 +40,7 @@ while step is a back step (not engineer-review):
|
|
|
40
40
|
else: # human_approve
|
|
41
41
|
bs.step.status = "done"; persist; STOP and report "waiting for human at <next>"
|
|
42
42
|
|
|
43
|
-
# reached engineer-review: always stop, hand to yad-
|
|
43
|
+
# reached engineer-review: always stop, hand to yad-engineer-review (human gate, finalizes the verdict)
|
|
44
44
|
```
|
|
45
45
|
|
|
46
46
|
`ranBy` is `machine` when the *previous* step's effective dial caused this step to run without a human
|
|
@@ -62,7 +62,7 @@ per-step dial says. `engineer-review` and the five front states are covered by `
|
|
|
62
62
|
## Deriving signals & the provisional verdict
|
|
63
63
|
|
|
64
64
|
`signals` are the raw facts of the run; the **provisional `verdict`** is derived from them. The human
|
|
65
|
-
gate for each step (the engineer review at `yad-
|
|
65
|
+
gate for each step (the engineer review at `yad-engineer-review` for `implement`; spec acceptance for `spec`;
|
|
66
66
|
first-consume for `tasks`; the gate itself for `checks`) later confirms or overrides the verdict and
|
|
67
67
|
finalizes the entry — a human always has the last word on the trust signal.
|
|
68
68
|
|
|
@@ -114,7 +114,7 @@ Reverting (`to: human_approve`) is never gated — automation must be reversible
|
|
|
114
114
|
|
|
115
115
|
## What stays human, always
|
|
116
116
|
|
|
117
|
-
- `engineer-review` — the merge gate. `yad-run` always stops here and hands to `yad-
|
|
117
|
+
- `engineer-review` — the merge gate. `yad-run` always stops here and hands to `yad-engineer-review`.
|
|
118
118
|
- The five front states (`epic`, `architecture`, `ui-design`, `stories`, `test-cases`) — not in
|
|
119
119
|
`back_steps`, in `locked_steps`; the dial-setter refuses them.
|
|
120
120
|
- Any contract-surface change — halts the loop and routes back to the architecture gate, regardless of
|