yadflow 3.18.0 → 3.19.0-next.2
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 +46 -0
- package/README.md +11 -11
- package/bin/yad.mjs +8 -8
- package/cli/artifact-status.mjs +4 -4
- package/cli/checkpoint.mjs +25 -25
- package/cli/commit.mjs +1 -1
- package/cli/companion.mjs +2 -2
- package/cli/doctor.mjs +10 -10
- package/cli/epic-state.mjs +29 -29
- package/cli/errors.mjs +1 -1
- package/cli/gate.mjs +32 -33
- package/cli/hook.mjs +4 -4
- package/cli/hubcommit.mjs +1 -1
- package/cli/ledger.mjs +3 -3
- package/cli/lib.mjs +23 -9
- package/cli/manifest.mjs +42 -21
- package/cli/migrate.mjs +54 -12
- package/cli/next.mjs +5 -5
- package/cli/openpr.mjs +8 -8
- package/cli/plan.mjs +28 -9
- package/cli/platform.mjs +1 -1
- package/cli/report.mjs +1 -1
- package/cli/review.mjs +5 -5
- package/cli/setup.mjs +22 -10
- package/cli/ship.mjs +1 -1
- package/cli/skip.mjs +1 -1
- package/cli/thread.mjs +1 -1
- package/cli/tidy.mjs +2 -2
- package/cli/update-commit.mjs +1 -1
- package/package.json +1 -1
- package/skills/sdlc/config.yaml +30 -30
- package/skills/sdlc/module-help.csv +21 -21
- package/skills/yad-analysis/SKILL.md +10 -10
- package/skills/yad-architecture/SKILL.md +10 -10
- package/skills/yad-architecture/references/contract-format.md +2 -3
- package/skills/yad-backfill/SKILL.md +5 -5
- package/skills/yad-change/SKILL.md +13 -13
- package/skills/yad-change/references/triage.md +2 -3
- package/skills/yad-checks/SKILL.md +34 -16
- package/skills/yad-checks/references/check-gates.md +63 -19
- package/skills/yad-checks/templates/checks/build-test-lint.sh +25 -7
- package/skills/yad-checks/templates/checks/epic-open.sh +1 -1
- package/skills/yad-checks/templates/checks/install-deps.sh +46 -0
- package/skills/yad-checks/templates/checks/ledger-guard.sh +41 -12
- package/skills/yad-checks/templates/checks/package-manager.sh +140 -0
- package/skills/yad-checks/templates/checks/reconcile-debt-check.sh +3 -3
- package/skills/yad-checks/templates/github/yad-checks.yml +24 -3
- package/skills/yad-checks/templates/github/yad-hub-checks.yml +2 -2
- package/skills/yad-checks/templates/github/yad-verified-commits.yml +1 -1
- package/skills/yad-checks/templates/gitlab/.gitlab-ci.yml +7 -1
- package/skills/yad-checks/templates/gitlab/yad-checks.gitlab-ci.yml +12 -3
- package/skills/yad-checks/templates/gitlab/yad-hub-checks.gitlab-ci.yml +2 -2
- package/skills/yad-checks/templates/gitlab/yad-verified-commits.gitlab-ci.yml +1 -1
- package/skills/yad-checks/templates/hooks/ledger-guard.sh +1 -1
- package/skills/yad-commit/SKILL.md +2 -2
- package/skills/yad-connect-design/SKILL.md +1 -1
- package/skills/yad-connect-docs/SKILL.md +1 -1
- package/skills/yad-connect-repos/SKILL.md +32 -15
- package/skills/yad-connect-repos/references/code-context.md +2 -2
- package/skills/yad-connect-repos/references/hub-config.md +25 -11
- package/skills/yad-connect-repos/references/repos-registry.md +3 -3
- package/skills/yad-connect-testing/SKILL.md +1 -1
- package/skills/yad-defects/SKILL.md +1 -1
- package/skills/yad-discovery/SKILL.md +6 -6
- package/skills/yad-discovery/references/discovery-schema.md +1 -1
- package/skills/yad-docs/SKILL.md +3 -3
- package/skills/yad-docs/templates/app/package-lock.json +65 -51
- package/skills/yad-docs/templates/app/package.json +1 -1
- package/skills/yad-docs-overview/SKILL.md +3 -3
- package/skills/yad-docs-overview/references/pipeline-model.md +17 -11
- package/skills/yad-engineer-review/SKILL.md +9 -9
- package/skills/yad-engineer-review/references/ship-and-record.md +8 -8
- package/skills/yad-epic/SKILL.md +15 -15
- package/skills/yad-epic/references/state-schema.md +30 -30
- package/skills/yad-hub-bridge/SKILL.md +14 -14
- package/skills/yad-hub-bridge/references/bridge.md +17 -17
- package/skills/yad-hub-bridge/references/login-roster.md +3 -3
- package/skills/yad-hub-bridge/templates/checks/hub-route.sh +1 -1
- package/skills/yad-hub-bridge/templates/gitlab/yad-gate-sync.gitlab-ci.yml +1 -1
- package/skills/yad-implement/SKILL.md +3 -3
- package/skills/yad-open-pr/SKILL.md +4 -4
- package/skills/yad-pair-review/SKILL.md +12 -12
- package/skills/yad-pair-review/references/session-state.md +3 -3
- package/skills/yad-pr-template/SKILL.md +4 -4
- package/skills/yad-pr-template/references/risk-routing.md +1 -1
- package/skills/yad-pr-template/templates/checks/pr-template.sh +18 -10
- package/skills/yad-pr-template/templates/checks/pr-title.sh +7 -7
- package/skills/yad-pr-template/templates/hub/github/pull_request_template.md +1 -1
- package/skills/yad-pr-template/templates/hub/gitlab/merge_request_templates/Default.md +1 -1
- package/skills/yad-reconcile/SKILL.md +1 -1
- package/skills/yad-report/SKILL.md +1 -1
- package/skills/yad-review-companion/SKILL.md +7 -7
- package/skills/yad-review-gate/SKILL.md +18 -18
- package/skills/yad-review-gate/references/gating.md +3 -3
- package/skills/yad-run/SKILL.md +10 -10
- package/skills/yad-run/references/run-loop.md +8 -8
- package/skills/yad-ship/SKILL.md +4 -4
- package/skills/yad-spec/SKILL.md +10 -11
- package/skills/yad-status/SKILL.md +13 -13
- package/skills/yad-stories/SKILL.md +12 -12
- package/skills/yad-stories/references/story-schema.md +3 -3
- package/skills/yad-stub/SKILL.md +3 -3
- package/skills/yad-sync-repos/SKILL.md +1 -1
- package/skills/yad-test-cases/SKILL.md +12 -13
- package/skills/yad-test-cases/references/test-cases-schema.md +1 -1
- package/skills/yad-ui/SKILL.md +10 -10
|
@@ -0,0 +1,140 @@
|
|
|
1
|
+
#!/usr/bin/env bash
|
|
2
|
+
# Shared package-manager detection for the dependency installer and build/test/lint gate.
|
|
3
|
+
# The standard package.json `packageManager` field is authoritative. A pnpm lockfile is a
|
|
4
|
+
# compatibility fallback for local gate execution, but CI installation requires an exact pnpm
|
|
5
|
+
# version so a generated workflow never silently changes toolchains.
|
|
6
|
+
|
|
7
|
+
readonly YAD_PACKAGE_JSON="package.json"
|
|
8
|
+
readonly YAD_PNPM_LOCKFILE="pnpm-lock.yaml"
|
|
9
|
+
readonly YAD_NPM_LOCKFILE="package-lock.json"
|
|
10
|
+
readonly YAD_NPM_SHRINKWRAP="npm-shrinkwrap.json"
|
|
11
|
+
|
|
12
|
+
# Corepack is the Node tool that downloads and activates the declared version. It is bundled with
|
|
13
|
+
# Node 18 through 24 (Node 25+ dropped it), and a copy older than 0.31 — before Node 18.20.7 /
|
|
14
|
+
# 20.19 / 22.14 — predates the 2025 npm registry key rotation and rejects anything published since
|
|
15
|
+
# with a raw "Cannot find matching keyid". A declared packageManager without a working Corepack must
|
|
16
|
+
# say so instead of dying with "command not found" or that error in the middle of the job.
|
|
17
|
+
readonly YAD_COREPACK_LINES="set YAD_NODE_VERSION to a current 20, 22 or 24 line, or install a current Corepack first (npm install -g corepack)"
|
|
18
|
+
yad_require_corepack() {
|
|
19
|
+
if command -v corepack >/dev/null 2>&1; then return 0; fi
|
|
20
|
+
echo "FAIL [package-manager]: package.json#packageManager is set but corepack is not on PATH (Node 25+ no longer bundles it) — $YAD_COREPACK_LINES." >&2
|
|
21
|
+
return 1
|
|
22
|
+
}
|
|
23
|
+
# `corepack prepare` with the guidance attached to every way it can fail: a stale Corepack (the
|
|
24
|
+
# keyid error above), no network, or a version the registry does not have.
|
|
25
|
+
yad_corepack_prepare() {
|
|
26
|
+
local spec="$1"
|
|
27
|
+
if corepack prepare "$spec" --activate; then return 0; fi
|
|
28
|
+
echo "FAIL [package-manager]: corepack could not activate $spec. A Corepack older than 0.31 cannot verify packages signed after the 2025 npm registry key rotation — $YAD_COREPACK_LINES; otherwise check that the version exists and the registry is reachable." >&2
|
|
29
|
+
return 1
|
|
30
|
+
}
|
|
31
|
+
|
|
32
|
+
# The command that runs the declared manager. Corepack activates a pinned npm but never shims it
|
|
33
|
+
# (`corepack enable` covers pnpm and yarn only), so a bare `npm` would be the Node image's ambient
|
|
34
|
+
# npm; a pinned npm is dispatched through Corepack instead, for `npm ci` and for the gate's `run`s.
|
|
35
|
+
# Prints the words space-separated so callers can `read -r -a` them into an array (bash 3.2 has no
|
|
36
|
+
# mapfile); the words are fixed literals, never repo input.
|
|
37
|
+
yad_package_manager_command() {
|
|
38
|
+
local spec="$1" manager="$2"
|
|
39
|
+
if [[ "$spec" == npm@* ]]; then
|
|
40
|
+
yad_require_corepack || return 1
|
|
41
|
+
printf '%s\n' "corepack npm"
|
|
42
|
+
else
|
|
43
|
+
printf '%s\n' "$manager"
|
|
44
|
+
fi
|
|
45
|
+
}
|
|
46
|
+
|
|
47
|
+
yad_validate_exact_package_manager_spec() {
|
|
48
|
+
local spec="$1"
|
|
49
|
+
# The JavaScript is deliberately single-quoted so Bash cannot expand its template literals.
|
|
50
|
+
# shellcheck disable=SC2016
|
|
51
|
+
YAD_PACKAGE_MANAGER_SPEC="$spec" node --input-type=module -e '
|
|
52
|
+
const spec = process.env.YAD_PACKAGE_MANAGER_SPEC;
|
|
53
|
+
const at = spec.indexOf("@");
|
|
54
|
+
const version = spec.slice(at + 1);
|
|
55
|
+
// The Corepack integrity suffix is `+<algorithm>.<hex digest>`: it hashes the download with the
|
|
56
|
+
// named algorithm and compares the LOWERCASE hex string byte for byte. Every algorithm Corepack
|
|
57
|
+
// has written or accepts is listed with its digest length; anything else is not a Corepack
|
|
58
|
+
// suffix and fails closed.
|
|
59
|
+
const COREPACK_DIGEST_HEX_LENGTH = { sha1: 40, sha224: 56, sha256: 64, sha384: 96, sha512: 128 };
|
|
60
|
+
const exactSemver = /^(0|[1-9]\d*)\.(0|[1-9]\d*)\.(0|[1-9]\d*)(?:-([0-9A-Za-z-]+(?:\.[0-9A-Za-z-]+)*))?(?:\+([0-9A-Za-z-]+(?:\.[0-9A-Za-z-]+)*))?$/;
|
|
61
|
+
const match = exactSemver.exec(version);
|
|
62
|
+
const invalidNumericPrerelease = match?.[4]?.split(".").some(
|
|
63
|
+
identifier => /^\d+$/.test(identifier) && identifier.length > 1 && identifier.startsWith("0"),
|
|
64
|
+
);
|
|
65
|
+
const isCorepackIntegrity = (build) => {
|
|
66
|
+
const [algorithm, digest, ...rest] = build.split(".");
|
|
67
|
+
const length = COREPACK_DIGEST_HEX_LENGTH[algorithm];
|
|
68
|
+
return rest.length === 0 && length !== undefined && new RegExp(`^[0-9a-f]{${length}}$`).test(digest ?? "");
|
|
69
|
+
};
|
|
70
|
+
const invalidBuildMetadata = match?.[5] !== undefined && !isCorepackIntegrity(match[5]);
|
|
71
|
+
if (!match || match[0] !== version || invalidNumericPrerelease || invalidBuildMetadata) {
|
|
72
|
+
const algorithms = Object.keys(COREPACK_DIGEST_HEX_LENGTH).join("|");
|
|
73
|
+
process.stderr.write(`FAIL [package-manager]: packageManager ${JSON.stringify(spec)} must name an exact semantic version, optionally followed by the Corepack integrity suffix +<${algorithms}>.<lowercase hex digest>.\n`);
|
|
74
|
+
process.exit(1);
|
|
75
|
+
}
|
|
76
|
+
'
|
|
77
|
+
}
|
|
78
|
+
|
|
79
|
+
yad_package_manager_spec() {
|
|
80
|
+
if [ ! -f "$YAD_PACKAGE_JSON" ]; then
|
|
81
|
+
echo "FAIL [package-manager]: package.json is missing." >&2
|
|
82
|
+
return 1
|
|
83
|
+
fi
|
|
84
|
+
# The JavaScript is deliberately single-quoted so Bash cannot expand its template literals.
|
|
85
|
+
# shellcheck disable=SC2016
|
|
86
|
+
node --input-type=module -e '
|
|
87
|
+
import fs from "node:fs";
|
|
88
|
+
let pkg;
|
|
89
|
+
// npm strips a UTF-8 byte-order mark before parsing (Windows editors often write one); do the same
|
|
90
|
+
// so a manifest npm itself installs from is not rejected here.
|
|
91
|
+
try { pkg = JSON.parse(fs.readFileSync("package.json", "utf8").replace(/^\uFEFF/, "")); }
|
|
92
|
+
catch { process.stderr.write("FAIL [package-manager]: package.json is not valid JSON.\n"); process.exit(1); }
|
|
93
|
+
if (pkg === null || typeof pkg !== "object" || Array.isArray(pkg)) {
|
|
94
|
+
process.stderr.write("FAIL [package-manager]: package.json must be a JSON object.\n"); process.exit(1);
|
|
95
|
+
}
|
|
96
|
+
if (pkg.packageManager !== undefined && typeof pkg.packageManager !== "string") {
|
|
97
|
+
process.stderr.write("FAIL [package-manager]: packageManager must be a string.\n"); process.exit(1);
|
|
98
|
+
}
|
|
99
|
+
if (pkg.packageManager && /[\r\n]/.test(pkg.packageManager)) {
|
|
100
|
+
process.stderr.write(`FAIL [package-manager]: packageManager ${JSON.stringify(pkg.packageManager)} must name an exact semantic version.\n`);
|
|
101
|
+
process.exit(1);
|
|
102
|
+
}
|
|
103
|
+
process.stdout.write(pkg.packageManager || "");
|
|
104
|
+
'
|
|
105
|
+
}
|
|
106
|
+
yad_detect_package_manager() {
|
|
107
|
+
local spec="${1-}"
|
|
108
|
+
case "$spec" in
|
|
109
|
+
"")
|
|
110
|
+
# No declaration: npm, exactly as before this field was read — UNLESS the repo carries a pnpm
|
|
111
|
+
# lockfile and no npm one. A repo with both (a stale package-lock.json after a migration is
|
|
112
|
+
# common) keeps the historical npm path rather than silently flipping toolchains.
|
|
113
|
+
if [ -f "$YAD_PNPM_LOCKFILE" ] && [ ! -f "$YAD_NPM_LOCKFILE" ] && [ ! -f "$YAD_NPM_SHRINKWRAP" ]; then
|
|
114
|
+
printf '%s\n' "pnpm"
|
|
115
|
+
else
|
|
116
|
+
printf '%s\n' "npm"
|
|
117
|
+
fi
|
|
118
|
+
;;
|
|
119
|
+
npm@*)
|
|
120
|
+
yad_validate_exact_package_manager_spec "$spec" || return 1
|
|
121
|
+
printf '%s\n' "npm"
|
|
122
|
+
;;
|
|
123
|
+
pnpm@*)
|
|
124
|
+
yad_validate_exact_package_manager_spec "$spec" || return 1
|
|
125
|
+
printf '%s\n' "pnpm"
|
|
126
|
+
;;
|
|
127
|
+
*)
|
|
128
|
+
# yarn/bun declared for local use while CI installs from an npm lockfile was green before this
|
|
129
|
+
# field was read; keep that repo on the historical npm path, with a warning, rather than
|
|
130
|
+
# failing every PR on upgrade. Without an npm lockfile there is nothing to fall back to.
|
|
131
|
+
if [ -f "$YAD_NPM_LOCKFILE" ] || [ -f "$YAD_NPM_SHRINKWRAP" ]; then
|
|
132
|
+
echo "WARN [package-manager]: packageManager '$spec' is not supported by the gate (npm, pnpm); an npm lockfile is present, so continuing on the historical npm path." >&2
|
|
133
|
+
printf '%s\n' "npm"
|
|
134
|
+
else
|
|
135
|
+
echo "FAIL [package-manager]: unsupported packageManager '$spec' (supported: npm, pnpm)." >&2
|
|
136
|
+
return 1
|
|
137
|
+
fi
|
|
138
|
+
;;
|
|
139
|
+
esac
|
|
140
|
+
}
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
#!/usr/bin/env bash
|
|
2
|
-
# reconcile-debt gate (Phase 6 — hotfix debt). A hotfix may ship code BEFORE its
|
|
3
|
-
# (ship-first), but it opens a reconcile-debt.json entry: the
|
|
2
|
+
# reconcile-debt gate (Phase 6 — hotfix debt). A hotfix may ship code BEFORE its Shape gates approve
|
|
3
|
+
# (ship-first), but it opens a reconcile-debt.json entry: the Shape artifacts do not yet describe what
|
|
4
4
|
# is in production. That debt must be PAID (artifacts updated + a regression test added) before the NEXT
|
|
5
5
|
# normal change on the same feature thread can ship. This gate FAILs a non-maintenance commit whose
|
|
6
6
|
# owning epic is on a thread carrying an OPEN debt that this epic does not itself own.
|
|
@@ -148,7 +148,7 @@ while IFS= read -r sha; do
|
|
|
148
148
|
if [ -n "$blockers" ]; then
|
|
149
149
|
echo "FAIL [reconcile-debt]: thread ${thread} carries OPEN hotfix debt:"
|
|
150
150
|
printf '%s\n' "$blockers" | sed 's/^/ /'
|
|
151
|
-
echo " -> Pay it first: update the
|
|
151
|
+
echo " -> Pay it first: update the Shape artifacts + add the regression test, then mark the"
|
|
152
152
|
echo " reconcile-debt.json entry status: paid. The thread is frozen for new changes until then."
|
|
153
153
|
rc=1
|
|
154
154
|
continue
|
|
@@ -34,12 +34,33 @@ jobs:
|
|
|
34
34
|
if: github.event.action != 'edited'
|
|
35
35
|
env:
|
|
36
36
|
YAD_TEST_MAX_WORKERS: "2" # cap jest/vitest test workers in CI; ignored by other runners
|
|
37
|
+
YAD_NODE_VERSION: ${{ vars.YAD_NODE_VERSION || '22' }} # repo variable; a current 20, 22 or 24 line (Node 25+ has no Corepack)
|
|
38
|
+
NX_BASE: ${{ github.event.pull_request.base.sha }}
|
|
39
|
+
NX_HEAD: ${{ github.event.pull_request.head.sha }}
|
|
40
|
+
COREPACK_HOME: ${{ github.workspace }}/.corepack-cache # pinned-manager downloads, cached below
|
|
37
41
|
steps:
|
|
38
42
|
- uses: actions/checkout@v4
|
|
39
|
-
with:
|
|
43
|
+
with:
|
|
44
|
+
fetch-depth: 0
|
|
45
|
+
filter: blob:none
|
|
40
46
|
- uses: actions/setup-node@v4
|
|
41
|
-
with:
|
|
42
|
-
|
|
47
|
+
with:
|
|
48
|
+
node-version: ${{ env.YAD_NODE_VERSION }}
|
|
49
|
+
# Dependency cache for either manager: npm's ~/.npm, pnpm's content-addressable store, and the
|
|
50
|
+
# Corepack home where `corepack prepare` keeps the pinned manager (otherwise re-downloaded from
|
|
51
|
+
# the registry on every job, even when the dependency cache hits). Keyed on the lockfiles AND
|
|
52
|
+
# package.json, since a packageManager bump changes no lockfile. setup-node's own `cache:` must
|
|
53
|
+
# name the manager up front (and needs pnpm on PATH before it runs), which package.json only
|
|
54
|
+
# decides later — so cache the directories directly.
|
|
55
|
+
- uses: actions/cache@v4
|
|
56
|
+
with:
|
|
57
|
+
path: |
|
|
58
|
+
~/.npm
|
|
59
|
+
~/.local/share/pnpm/store
|
|
60
|
+
${{ env.COREPACK_HOME }}
|
|
61
|
+
key: yad-deps-${{ runner.os }}-node${{ env.YAD_NODE_VERSION }}-${{ hashFiles('package-lock.json', 'npm-shrinkwrap.json', 'pnpm-lock.yaml', 'package.json') }}
|
|
62
|
+
restore-keys: yad-deps-${{ runner.os }}-node${{ env.YAD_NODE_VERSION }}-
|
|
63
|
+
- run: bash checks/install-deps.sh
|
|
43
64
|
- run: bash checks/build-test-lint.sh
|
|
44
65
|
|
|
45
66
|
# Phase 6 — feature-thread gates. lineage-check: the change links a real threaded epic. epic-open:
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
# yad-managed: yad-checks
|
|
2
2
|
# Pattern gates for the PRODUCT HUB. They run with `--profile hub` and split by head branch:
|
|
3
|
-
# review/EP-* PRs are
|
|
3
|
+
# review/EP-* PRs are Shape artifact-review vehicles — a `review: <artifact> (EP-<slug>)` title
|
|
4
4
|
# and the hub artifact-review template body.
|
|
5
5
|
# every other PR is a tooling/code change to the hub itself — a Conventional-Commits title and the
|
|
6
6
|
# code task template body (same convention the code repos use).
|
|
@@ -27,7 +27,7 @@ jobs:
|
|
|
27
27
|
|
|
28
28
|
# Pass the title via env (never interpolate untrusted ${{ }} into a run line — injection-safe).
|
|
29
29
|
# fetch-depth: 0 + the base ref give us the PR's changed paths, so the gate can reject an artifact
|
|
30
|
-
# change (epics/**) riding a non-review head past the
|
|
30
|
+
# change (epics/**) riding a non-review head past the Shape review with a plain code title.
|
|
31
31
|
pr-title:
|
|
32
32
|
runs-on: ubuntu-latest
|
|
33
33
|
env:
|
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
# yad-managed: yad-checks
|
|
2
|
-
# verified-commits gate for the PRODUCT HUB: every PR (including the
|
|
2
|
+
# verified-commits gate for the PRODUCT HUB: every PR (including the Shape review/EP-* PRs)
|
|
3
3
|
# must contain only commits whose signature the platform marks Verified AND whose author email is a
|
|
4
4
|
# known identity (.sdlc/verified-authors — generated by `yad check --fix` from the hub roster).
|
|
5
5
|
# Standalone workflow so it never collides with the hub-flavored yad-checks workflow.
|
|
@@ -4,7 +4,7 @@
|
|
|
4
4
|
stages: [spec-link, contract-check, build-test-lint, verified-commits]
|
|
5
5
|
|
|
6
6
|
default:
|
|
7
|
-
image: node
|
|
7
|
+
image: node:${YAD_NODE_VERSION}
|
|
8
8
|
|
|
9
9
|
.mr_only:
|
|
10
10
|
rules:
|
|
@@ -12,6 +12,9 @@ default:
|
|
|
12
12
|
|
|
13
13
|
variables:
|
|
14
14
|
GIT_DEPTH: "0" # full history so the gates can diff against the target branch
|
|
15
|
+
YAD_NODE_VERSION: "22" # override with a project/group CI variable (a current 20, 22 or 24 line; Node 25+ has no Corepack)
|
|
16
|
+
NX_BASE: $CI_MERGE_REQUEST_DIFF_BASE_SHA
|
|
17
|
+
NX_HEAD: $CI_COMMIT_SHA
|
|
15
18
|
|
|
16
19
|
spec-link:
|
|
17
20
|
stage: spec-link
|
|
@@ -28,7 +31,10 @@ contract-check:
|
|
|
28
31
|
build-test-lint:
|
|
29
32
|
stage: build-test-lint
|
|
30
33
|
extends: .mr_only
|
|
34
|
+
variables:
|
|
35
|
+
YAD_TEST_MAX_WORKERS: "2" # cap jest/vitest test workers in CI; ignored by other runners
|
|
31
36
|
script:
|
|
37
|
+
- bash checks/install-deps.sh
|
|
32
38
|
- bash checks/build-test-lint.sh
|
|
33
39
|
|
|
34
40
|
# Needs a CI/CD variable GITLAB_TOKEN (or SDLC_API_TOKEN) with read_api scope — CI_JOB_TOKEN cannot
|
|
@@ -14,10 +14,19 @@
|
|
|
14
14
|
# top-level `default:` merges into the HOST root pipeline; if the host already sets a top-level
|
|
15
15
|
# `image:`, GitLab rejects the whole config ("image is defined in top-level and 'default:' entry").
|
|
16
16
|
# Putting them on the anchor scopes them to the gate jobs (which all `extends: .sdlc_mr_only`) and
|
|
17
|
-
# never touches the host root.
|
|
17
|
+
# never touches the host root. The same goes for the gate jobs' own variables (`YAD_NODE_VERSION`,
|
|
18
|
+
# `NX_BASE`, `NX_HEAD`): an included top-level `variables:` merges into the host's globals, where a
|
|
19
|
+
# generic name like NX_BASE can collide with one the host already computes for its own Nx jobs.
|
|
20
|
+
# Only `GIT_DEPTH` stays global — the gates need the full history and a host that sets its own wins.
|
|
18
21
|
|
|
19
22
|
.sdlc_mr_only:
|
|
20
|
-
image: node
|
|
23
|
+
image: node:${YAD_NODE_VERSION}
|
|
24
|
+
variables:
|
|
25
|
+
# A project/group CI/CD variable overrides a YAML value, so YAD_NODE_VERSION can be changed in
|
|
26
|
+
# project settings without editing the managed fragment (a current 20, 22 or 24 line; Node 25+ has no Corepack).
|
|
27
|
+
YAD_NODE_VERSION: "22"
|
|
28
|
+
NX_BASE: $CI_MERGE_REQUEST_DIFF_BASE_SHA
|
|
29
|
+
NX_HEAD: $CI_COMMIT_SHA
|
|
21
30
|
# Runner selection. These jobs need a docker/dind executor; on instances whose runners are all
|
|
22
31
|
# tag-locked (run_untagged: false) an untagged image job never starts. Set the YAD_RUNNER_TAGS
|
|
23
32
|
# CI/CD variable (Settings → CI/CD → Variables, e.g. `dind_runner`) to route them — it lives in
|
|
@@ -50,7 +59,7 @@ yad-build-test-lint:
|
|
|
50
59
|
variables:
|
|
51
60
|
YAD_TEST_MAX_WORKERS: "2" # cap jest/vitest test workers in CI; ignored by other runners
|
|
52
61
|
script:
|
|
53
|
-
-
|
|
62
|
+
- bash checks/install-deps.sh
|
|
54
63
|
- bash checks/build-test-lint.sh
|
|
55
64
|
|
|
56
65
|
# Phase 6 — feature-thread gates (lineage / seal / hotfix-debt). Build on spec-link's story->epic
|
|
@@ -3,7 +3,7 @@
|
|
|
3
3
|
# .gitlab-ci.yml via:
|
|
4
4
|
# include:
|
|
5
5
|
# - local: '.gitlab/ci/yad-hub-checks.yml'
|
|
6
|
-
# MRs run with `--profile hub` and split by source branch: review/EP-* MRs are
|
|
6
|
+
# MRs run with `--profile hub` and split by source branch: review/EP-* MRs are Shape artifact-
|
|
7
7
|
# review vehicles (a `review: <artifact> (EP-<slug>)` title + the hub artifact-review template body);
|
|
8
8
|
# every other MR is a tooling/code change to the hub itself and follows the code convention (a
|
|
9
9
|
# Conventional-Commits title + the code task template body). The source branch is passed via --head so
|
|
@@ -28,7 +28,7 @@ yad-hub-commit-message:
|
|
|
28
28
|
- bash checks/commit-message.sh --profile hub "origin/$CI_MERGE_REQUEST_TARGET_BRANCH_NAME"
|
|
29
29
|
|
|
30
30
|
# GIT_DEPTH: 0 (above) gives the changed paths, so the gate can reject an artifact change (epics/**)
|
|
31
|
-
# riding a non-review source branch past the
|
|
31
|
+
# riding a non-review source branch past the Shape review with a plain code title/template.
|
|
32
32
|
yad-hub-pr-title:
|
|
33
33
|
extends: .yad_hub_mr_only
|
|
34
34
|
needs: []
|
|
@@ -3,7 +3,7 @@
|
|
|
3
3
|
# .gitlab-ci.yml via:
|
|
4
4
|
# include:
|
|
5
5
|
# - local: '.gitlab/ci/yad-verified-commits.yml'
|
|
6
|
-
# Every MR (including the
|
|
6
|
+
# Every MR (including the Shape review/EP-* MRs) must contain only commits whose signature the
|
|
7
7
|
# platform marks Verified AND whose author email is a known identity (.sdlc/verified-authors).
|
|
8
8
|
#
|
|
9
9
|
# Needs a CI/CD variable GITLAB_TOKEN (or SDLC_API_TOKEN) with read_api scope — CI_JOB_TOKEN cannot
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
#!/usr/bin/env bash
|
|
2
2
|
# ledger-guard HARNESS HOOK — the local half of the CI gate of the same name (#171).
|
|
3
3
|
#
|
|
4
|
-
# The gate ledger is CI-owned in
|
|
4
|
+
# The gate ledger is CI-owned in verified mode: `checks/ledger-guard.sh` rejects any non-bot commit
|
|
5
5
|
# that changes `epics/*/.sdlc/{state,approvals,comments,hub-prs}.json` or `epics/*/reviews/*.md`.
|
|
6
6
|
# This hook says so at the moment an agent tries the edit, instead of twenty minutes later in a
|
|
7
7
|
# failed pipeline, and names the command that owns the transition (`yad gate open`).
|
|
@@ -1,9 +1,9 @@
|
|
|
1
1
|
---
|
|
2
2
|
name: yad-commit
|
|
3
|
-
description: 'Build
|
|
3
|
+
description: 'Build helper of the gated SDLC. Commit ONE staged atomic change by the conventions — a Conventional-Commits subject, the fixed trailer order (Task → Contract-Change, plus an OPTIONAL Co-Authored-By), and an atomic-file guard (≤3 files). By default the commit carries NO AI footer: the human git author owns it, and a Co-Authored-By trailer is added ONLY when --ai <id> is explicitly passed (claude|copilot|cursor|coderabbit; default none = human-only). The flag is the sole switch — never add the footer on the AI''s own initiative. Drives the zero-dependency `yad commit` CLI; never auto-advances. Use when the user says "commit this", "commit by convention", or "make an atomic commit".'
|
|
4
4
|
---
|
|
5
5
|
|
|
6
|
-
# SDLC — Commit by Convention (
|
|
6
|
+
# SDLC — Commit by Convention (Build helper)
|
|
7
7
|
|
|
8
8
|
**Goal:** Turn ONE staged atomic change into a single commit that satisfies the project conventions
|
|
9
9
|
(`CONTRIBUTING.md` / `config.yaml` `build`): a Conventional-Commits subject, the fixed trailer order
|
|
@@ -10,7 +10,7 @@ and/or web pages — inside a design tool such as **Figma**, alongside the Markd
|
|
|
10
10
|
(`ui-design.md` / `DESIGN.md`). This skill **connects** a design tool to the product hub and records
|
|
11
11
|
*how* to reach it (the tool, the project/file references, which MCP renders it) — never a credential.
|
|
12
12
|
|
|
13
|
-
This is **setup/maintenance**, not a gated
|
|
13
|
+
This is **setup/maintenance**, not a gated Shape step — it never touches `.sdlc/state.json` or any
|
|
14
14
|
epic's approvals. It only writes the project-wide design registry. `yad-ui` consumes it: when a tool is
|
|
15
15
|
connected and its MCP is available, the `ux-designer` lens **generates** screens into the tool (or
|
|
16
16
|
**links** an existing human-made design and reads it back); when nothing is connected, `yad-ui` runs
|
|
@@ -10,7 +10,7 @@ description: 'Connects a docs/Pages publishing target to the product hub so the
|
|
|
10
10
|
instead of only committing its source. This skill **connects** a publishing target to the product hub
|
|
11
11
|
and records *how* to reach it (the platform, the publish scope, the base path) — never a credential.
|
|
12
12
|
|
|
13
|
-
This is **setup/maintenance**, not a gated
|
|
13
|
+
This is **setup/maintenance**, not a gated Shape step — it never touches `.sdlc/state.json` or any
|
|
14
14
|
epic's approvals. It only writes the project-wide docs registry. `yad-docs` / `yad-docs-overview`
|
|
15
15
|
consume it: when a target is connected, they theme + generate the site and drive `yad docs deploy`;
|
|
16
16
|
when nothing is connected (`target: "none"`), they still generate and **npm-build** the site but stop
|
|
@@ -11,15 +11,15 @@ stories that contradict or duplicate what is built. This skill **connects** code
|
|
|
11
11
|
hub and caches an AI-readable picture of each. It is the product → code half of the 2-way link (the
|
|
12
12
|
code → product half is the existing `link.md` back-pointer each spec carries).
|
|
13
13
|
|
|
14
|
-
This is **setup/maintenance**, not a gated
|
|
14
|
+
This is **setup/maintenance**, not a gated Shape step — it never touches `.sdlc/state.json` or any
|
|
15
15
|
epic's approvals. It only writes the project-wide registry and the per-repo context cache.
|
|
16
16
|
|
|
17
17
|
## Conventions
|
|
18
18
|
|
|
19
19
|
- `{project-root}` resolves from the project working directory (the **product hub**).
|
|
20
|
-
- The **product repo is the
|
|
20
|
+
- The **product repo is the Shape phase toolchain hub** (`config.yaml` `code_context`): Repomix (and
|
|
21
21
|
Impeccable, later) are installed/run **here** and target the connected code repos **by path**. The
|
|
22
|
-
code repos themselves need no install for this. (The
|
|
22
|
+
code repos themselves need no install for this. (The Build CI gates are the exception — they
|
|
23
23
|
live inside each code repo; see `yad-checks`.)
|
|
24
24
|
- **Repomix is a true CLI subprocess** (Phase 0 / RESEARCH-NOTES §3): `npx repomix@latest [flags]` —
|
|
25
25
|
NOT a slash-command. It secret-scans by default (Secretlint).
|
|
@@ -90,7 +90,7 @@ Feed the pack to the AI with the **"describe what exists, do not invent"** instr
|
|
|
90
90
|
(`references/code-context.md`) and write `{project-root}/.sdlc/code-context/<repo>/code-map.md`: a small
|
|
91
91
|
index of **stack/conventions, entry points, public endpoints/APIs, events, data models/entities, and
|
|
92
92
|
module layout**. Mark anything unclear `<!-- unverified: ... -->`; never fill gaps with invented
|
|
93
|
-
behaviour. This is the cheap artifact every
|
|
93
|
+
behaviour. This is the cheap artifact every Shape phase loads by default (the full pack is read only
|
|
94
94
|
when a phase needs depth).
|
|
95
95
|
|
|
96
96
|
### Step 4 — Record the repo in the registry
|
|
@@ -122,7 +122,7 @@ new repo later is the same `connect` action.
|
|
|
122
122
|
|
|
123
123
|
### Step 5 — Report
|
|
124
124
|
Report the connected repo, its `platform`, the pack + code-map paths, the secret-scan result, and that
|
|
125
|
-
the
|
|
125
|
+
the Shape phases will now load this repo's code-map. Nothing auto-advances; this is setup.
|
|
126
126
|
|
|
127
127
|
## Other actions
|
|
128
128
|
|
|
@@ -139,20 +139,37 @@ the front phases will now load this repo's code-map. Nothing auto-advances; this
|
|
|
139
139
|
- **`disconnect`** — remove the repo from the registry and delete its cache dir. Leaves the **code repo
|
|
140
140
|
itself untouched**.
|
|
141
141
|
|
|
142
|
-
## Hub detection + reviewer roster (the
|
|
142
|
+
## Hub detection + reviewer roster (the Shape review bridge)
|
|
143
143
|
|
|
144
|
-
The hub is itself a git repo on a platform. These actions record that so the
|
|
144
|
+
The hub is itself a git repo on a platform. These actions record that so the Shape review/comment/
|
|
145
145
|
approval cycle can run through a real PR/MR on the hub (`yad-review-gate` + `yad-hub-bridge`). They
|
|
146
146
|
write only `{project-root}/.sdlc/hub.json` (`config.yaml` `hub.config`) — never an epic's state/approvals.
|
|
147
147
|
|
|
148
148
|
- **`detect-hub`** — detect the hub's own platform and upsert `.sdlc/hub.json`. Run
|
|
149
149
|
`git remote get-url origin` **on the hub** and read the host with the SAME logic Step 1 uses for code
|
|
150
150
|
repos: `github.com` → `github`, GitLab host → `gitlab`, no remote → `platform: null`. Record
|
|
151
|
-
`git_url`, `default_branch`, `detectedAt`, and
|
|
152
|
-
|
|
153
|
-
|
|
154
|
-
|
|
155
|
-
|
|
151
|
+
`git_url`, `default_branch`, `detectedAt`, and **all three of** `ledger`, `bridge_enabled` and
|
|
152
|
+
`bridge`:
|
|
153
|
+
|
|
154
|
+
| a platform was detected | no platform (`platform: null`) |
|
|
155
|
+
|---|---|
|
|
156
|
+
| `"ledger": "verified"`, `bridge_enabled: true`, `bridge: true` | `"ledger": "local"`, `bridge_enabled: false`, `bridge: false` |
|
|
157
|
+
|
|
158
|
+
(Preserve an existing roster.)
|
|
159
|
+
|
|
160
|
+
**`ledger` is the one that decides.** `isVerifiedLedger` (`cli/manifest.mjs`) reads it first and
|
|
161
|
+
falls back to the booleans only when it is absent — so on a project that has already run
|
|
162
|
+
`yad migrate`, writing `bridge_enabled: true` while leaving `"ledger": "local"` in place turns
|
|
163
|
+
verified mode ON in the file and OFF in the engine. Nothing would be wired, no guard would arm,
|
|
164
|
+
and the report would say it worked. Write all three, and keep them saying the same thing.
|
|
165
|
+
|
|
166
|
+
The booleans are still written because a check gate committed in the repo may predate
|
|
167
|
+
`yad update`; see `docs/migrations/shape-2.md`.
|
|
168
|
+
|
|
169
|
+
A platform and a verified ledger travel together: verified mode is a platform AND the switch
|
|
170
|
+
(`isVerifiedLedger`, `cli/manifest.mjs`), and `yad setup` derives both from one value, so marking a
|
|
171
|
+
platform-less hub verified creates a state no CLI path can produce and the gates read
|
|
172
|
+
differently (#186).
|
|
156
173
|
Auth is the local user's own `gh`/`glab`/git; **store no tokens**. Idempotent — safe to re-run.
|
|
157
174
|
- **`roster`** — set one roster entry mapping a platform `login` → SDLC `name` + `email` + a per-scope
|
|
158
175
|
`roles` map (`roles: { hub: ["owner","reviewer"], <repo>: ["domain-owner", …] }`). Upsert by `login`;
|
|
@@ -166,11 +183,11 @@ write only `{project-root}/.sdlc/hub.json` (`config.yaml` `hub.config`) — neve
|
|
|
166
183
|
connected repo's role); `yad roster grant|revoke <name> <repo> <role>`; `yad roster remove <login>`.
|
|
167
184
|
A `domain-owner` grant/revoke keeps `repos.json` `domain_owners` in sync so the gate never drifts.
|
|
168
185
|
|
|
169
|
-
If the hub has no remote (`platform: null`) or the
|
|
170
|
-
|
|
186
|
+
If the hub has no remote (`platform: null`) or the verified ledger is disabled, the Shape gate runs
|
|
187
|
+
local with no error — the verified ledger is purely additive.
|
|
171
188
|
|
|
172
189
|
## Live on-demand (the third context layer)
|
|
173
|
-
The cached pack + map are the default. When a
|
|
190
|
+
The cached pack + map are the default. When a Shape phase needs an **area** not in the map, it may
|
|
174
191
|
re-run Repomix **live**, scoped to that area:
|
|
175
192
|
```bash
|
|
176
193
|
npx repomix@latest --compress --include "<area globs>" --style markdown -o -
|
|
@@ -64,12 +64,12 @@ source: repomix
|
|
|
64
64
|
<!-- the main directories/modules and what each owns -->
|
|
65
65
|
```
|
|
66
66
|
|
|
67
|
-
The code-map is deliberately small so every
|
|
67
|
+
The code-map is deliberately small so every Shape phase can load it cheaply. The full `pack.md` is read
|
|
68
68
|
only when a phase needs depth (the architecture phase, primarily).
|
|
69
69
|
|
|
70
70
|
## Layer 3 — live on-demand (a specific area, not a stale repo)
|
|
71
71
|
|
|
72
|
-
When a
|
|
72
|
+
When a Shape phase needs an area not captured in the code-map, it may re-pack that **slice** live,
|
|
73
73
|
scoped to the area, without writing the cache:
|
|
74
74
|
|
|
75
75
|
```bash
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
# Hub config — schema, detection, and the reviewer roster
|
|
2
2
|
|
|
3
|
-
The hub config is the product hub's record of **its own** platform (so the
|
|
3
|
+
The hub config is the product hub's record of **its own** platform (so the Shape review/comment/
|
|
4
4
|
approval cycle can run through a real PR/MR on the hub) and the **reviewer roster** that maps a platform
|
|
5
5
|
login to an SDLC name + role. It is a single object for the hub itself — the sibling of the per-repo
|
|
6
6
|
`repos.json` registry (see `repos-registry.md`), kept separate so it never pollutes that array.
|
|
@@ -15,10 +15,13 @@ login to an SDLC name + role. It is a single object for the hub itself — the s
|
|
|
15
15
|
|
|
16
16
|
```json
|
|
17
17
|
{
|
|
18
|
+
"schemaVersion": 2, // the file's shape. Absent means 1 (rule 1). `yad migrate` moves it; see docs/migrations/shape-2.md
|
|
18
19
|
"platform": "github", // github | gitlab (from the hub's own remote host); null when local-only
|
|
19
20
|
"git_url": "https://github.com/abdelrahmannasr/yadflow.git", // REQUIRED when platform is non-null (scopes auth + opens PRs); yad doctor warns YAD-CFG-005 if absent
|
|
20
21
|
"default_branch": "main",
|
|
21
|
-
"
|
|
22
|
+
"ledger": "verified", // WHO WRITES THE LEDGER, and the one that decides: "verified" = CI only, signed; "local" = this machine. Travels WITH platform — verified is both (isVerifiedLedger), so never "verified" beside platform: null (#186)
|
|
23
|
+
"bridge_enabled": true, // the older spelling of the same switch, kept so a check gate that predates `yad update` still reads it. Write it to MATCH `ledger`, never against it
|
|
24
|
+
"bridge": true, // older still. Same rule
|
|
22
25
|
"gate_sync_version": "3.15.3", // OPTIONAL exact pin for the wired gate-sync job; an exact 3.x.y, prereleases included (3.16.0-rc.1) — anything else is skipped. Omitted => the .sdlc/cli-version.json stamp if that qualifies, else floating 3
|
|
23
26
|
"review": { "requireEngagement": false }, // Review Companion: false (soft) counts bare approves but nudges; true counts only verified-engagement approvals
|
|
24
27
|
"detectedAt": "2026-06-08", // last detect-hub run (YYYY-MM-DD)
|
|
@@ -72,16 +75,27 @@ as the registry). `detect-hub` upserts `hub.json` in place — it is idempotent
|
|
|
72
75
|
|
|
73
76
|
**`git_url` is required whenever `platform` is non-null.** `yad doctor` uses it to scope the auth
|
|
74
77
|
probe to the hub's own host (an unscoped `glab auth status` fails on any unrelated broken instance),
|
|
75
|
-
and the
|
|
78
|
+
and the verified ledger/PR flow uses it to open PRs. Doctor flags its absence with a warn (`YAD-CFG-005`);
|
|
76
79
|
re-running `yad setup` backfills it from the origin remote (idempotent, non-interactive).
|
|
77
80
|
|
|
78
|
-
##
|
|
81
|
+
## Who writes the ledger, and what happens when it degrades
|
|
79
82
|
|
|
80
|
-
|
|
83
|
+
The switch is read in this order — `isVerifiedLedger` (`cli/manifest.mjs`) and the bash copy in
|
|
84
|
+
`checks/ledger-guard.sh` both do exactly this, and a test asserts they agree on every shape:
|
|
85
|
+
|
|
86
|
+
1. **`ledger`**, whenever the key is present. `"verified"` and nothing else means verified; any other
|
|
87
|
+
value, including an empty string, means local.
|
|
88
|
+
2. **otherwise** the older booleans `bridge_enabled`, then `bridge`.
|
|
89
|
+
3. and a non-null `platform` is required either way — without one there is no Verified badge to read.
|
|
90
|
+
|
|
91
|
+
So on a migrated project `ledger` wins, and writing a boolean that contradicts it changes nothing.
|
|
92
|
+
Keep all three in step.
|
|
93
|
+
|
|
94
|
+
- `ledger: "verified"` **and** a non-null `platform` **and** `gh`/`glab` authenticated → the Shape
|
|
81
95
|
review opens a PR/MR on the hub and `yad-review-gate action: sync` pulls platform state into the ledger.
|
|
82
|
-
- `
|
|
83
|
-
existing **
|
|
84
|
-
- The master switch `config.yaml` `hub.bridge: false` disables the
|
|
96
|
+
- `ledger: "local"`, `platform: null`, or no/unauthenticated CLI → the gate falls back to the
|
|
97
|
+
existing **local** flow with no error. The file ledger is the source of truth in both modes.
|
|
98
|
+
- The master switch `config.yaml` `hub.bridge: false` disables the verified ledger globally regardless of `hub.json`.
|
|
85
99
|
|
|
86
100
|
## Review Companion engagement (`review.requireEngagement`)
|
|
87
101
|
|
|
@@ -90,7 +104,7 @@ engagement gate. Each approval records `engagement: verified | none`. **Soft (`f
|
|
|
90
104
|
bare approve still passes but draws a friendly public nudge, so review *quality* is visible without
|
|
91
105
|
blocking. **Strict (`true`):** the predicate counts only `verified` approvals. The signal is gameable by
|
|
92
106
|
design ("visible, not impossible") — it raises the cost of a rubber-stamp, it does not prove a human
|
|
93
|
-
read the artifact. Applies to both the
|
|
107
|
+
read the artifact. Applies to both the Shape gate and the Build engineer review.
|
|
94
108
|
|
|
95
109
|
## Git tracking
|
|
96
110
|
|
|
@@ -99,6 +113,6 @@ This mirrors how `repos.json` and the per-epic `.sdlc/` state are committed.
|
|
|
99
113
|
|
|
100
114
|
## Greenfield
|
|
101
115
|
|
|
102
|
-
A brand-new hub has no `hub.json`. That is valid — the
|
|
103
|
-
records a platform. The
|
|
116
|
+
A brand-new hub has no `hub.json`. That is valid — the Shape gate runs local until `detect-hub`
|
|
117
|
+
records a platform. The verified ledger is purely additive; nothing about authoring or the gate predicate changes.
|
|
104
118
|
```
|
|
@@ -37,7 +37,7 @@ not under any `epics/EP-<slug>/.sdlc/`.
|
|
|
37
37
|
|
|
38
38
|
## Rules
|
|
39
39
|
|
|
40
|
-
- **`name`** is the join key. It MUST match the names used in epic/story `repos:` tags so the
|
|
40
|
+
- **`name`** is the join key. It MUST match the names used in epic/story `repos:` tags so the Shape
|
|
41
41
|
phases can map `epic.repos` → registry entries → code-maps. Keep it stable.
|
|
42
42
|
- **Auth is never stored.** No tokens, passwords, or PATs in the registry. `git_url` is a plain remote;
|
|
43
43
|
`connect` clones/fetches as the local user (SSH key or git credential helper).
|
|
@@ -51,7 +51,7 @@ not under any `epics/EP-<slug>/.sdlc/`.
|
|
|
51
51
|
## Git tracking
|
|
52
52
|
|
|
53
53
|
Commit the **registry** (`repos.json`) and each repo's **`code-map.md`** — they are small, reviewable,
|
|
54
|
-
and are what the
|
|
54
|
+
and are what the Shape phases actually read (a diff on a code-map shows when a repo's surface moved).
|
|
55
55
|
`yad repo refresh --push` commits and pushes exactly these (never `pack.md`) to the hub's default
|
|
56
56
|
branch as one `chore(hub): sync code-context … [skip ci]` audit commit.
|
|
57
57
|
**Ignore** the full Repomix `pack.md` — it is large and regenerable (`action: refresh`). The product
|
|
@@ -60,6 +60,6 @@ hub's `.gitignore` carries `.sdlc/code-context/*/pack.md` for this. This mirrors
|
|
|
60
60
|
|
|
61
61
|
## Greenfield
|
|
62
62
|
|
|
63
|
-
A brand-new product hub has no `repos.json` (or an empty `{ "repos": [] }`). That is valid — the
|
|
63
|
+
A brand-new product hub has no `repos.json` (or an empty `{ "repos": [] }`). That is valid — the Shape
|
|
64
64
|
phases treat "no repos connected" as "nothing to consider yet" and proceed unchanged. The registry
|
|
65
65
|
appears the first time `connect` runs.
|
|
@@ -10,7 +10,7 @@ runnable specs in a connected code repo — alongside the Markdown artifact (`te
|
|
|
10
10
|
**connects** a testing tool such as **Playwright** to the product hub and records *how* to reach it (the
|
|
11
11
|
tool, the suite references, which MCP runs it) — never a credential.
|
|
12
12
|
|
|
13
|
-
This is **setup/maintenance**, not a gated
|
|
13
|
+
This is **setup/maintenance**, not a gated Shape step — it never touches `.sdlc/state.json` or any
|
|
14
14
|
epic's approvals. It only writes the project-wide testing registry. `yad-test-cases` consumes it: when a
|
|
15
15
|
tool is connected and its MCP is available, the `test architect` lens **generates** automation tests
|
|
16
16
|
into the connected repo(s) (or **links** an existing suite and reads it back); when nothing is
|
|
@@ -34,7 +34,7 @@ Resolve the scope (`yad thread <id> --json` for a thread). Collect, across the s
|
|
|
34
34
|
(`origin`, `severity`, `escape_stage`, `root_cause`);
|
|
35
35
|
- the shipped regression fixes from each epic's build ledger (the fix that closed the defect, linking
|
|
36
36
|
the change-epic → its regression story/test);
|
|
37
|
-
- open reconcile debt (a hotfix whose
|
|
37
|
+
- open reconcile debt (a hotfix whose Shape truth is not yet restored).
|
|
38
38
|
|
|
39
39
|
The build ledger is **shard-then-fold**: read it as the **union** of the folded `.sdlc/build-log.json`
|
|
40
40
|
`ships` PLUS every loose `.sdlc/build-log/` shard, deduped by `(story, task, repo)` — a shard WINS over a
|