Single-commit clean baseline after security scrub of niche-tells, project codenames, internal jargon, and contributor-email leaks. Contents: - 100 Rust crates (_primitives/_rust/) - 37 agent manifests (_manifests/) + generated specs (_generated/) - 67 user-invocable skills (skills/) - 33 hooks (hooks/) - Composition blocks (_blocks/) - Documentation (docs/, README.md) - TS adapter packages (_ts_packages/) - Assembler (_assembler/) - Roles (_roles/) - Templates (_templates/) - Forgejo CI (.forgejo/) Author: Denis Parfionovich <info@greendragon.info> License: see LICENSE.
98 lines
4.6 KiB
Markdown
98 lines
4.6 KiB
Markdown
# Phase 5 — Verify via kei-ci-lint, then final report
|
||
|
||
Close the pipeline by validating every generated workflow with `_primitives/kei-ci-lint.sh`. The lint has seven rules (R1–R7); each finding drives one AskUserQuestion for fix/skip/abort.
|
||
|
||
## 5a — Run the linter
|
||
|
||
Execute:
|
||
|
||
```
|
||
sh _primitives/kei-ci-lint.sh --dir .github/workflows
|
||
# or, if PLATFORM = Forgejo Actions:
|
||
sh _primitives/kei-ci-lint.sh --dir .forgejo/workflows
|
||
```
|
||
|
||
Capture stdout + stderr. Parse output — one line per finding, format `FAIL <file> <R#> <message>` or `WARN …`.
|
||
|
||
## 5b — Per-finding triage (AskUserQuestion, single-select per finding)
|
||
|
||
For EACH `FAIL` line, emit:
|
||
|
||
```json
|
||
{
|
||
"questions": [
|
||
{
|
||
"question": "Lint finding: <R#> in <file> — <message>. Action?",
|
||
"header": "Lint",
|
||
"multiSelect": false,
|
||
"options": [
|
||
{"label": "Fix now (skill applies the recommended patch)",
|
||
"description": "Skill edits the YAML file inline; next lint run must show clean"},
|
||
{"label": "Skip (add to allowlist with justification)",
|
||
"description": "Skill prompts for a 1-line justification; stored as a YAML comment + ledger line"},
|
||
{"label": "Abort (stop the pipeline; user investigates manually)",
|
||
"description": "Scaffold stays in place, but final report marks the skill run as INCOMPLETE"}
|
||
]
|
||
}
|
||
]
|
||
}
|
||
```
|
||
|
||
Store each answer under `LINT.triage[<finding-key>]`.
|
||
|
||
## 5c — Fix recipes (applied inline when user picks "Fix now")
|
||
|
||
| Rule | Fix |
|
||
|---|---|
|
||
| R1 missing `name:` / `on:` / `jobs:` | Insert the field with a sensible default (`name` from filename; `on: { pull_request: , push: { branches: [main] } }`) |
|
||
| R2 no top-level `permissions:` | Insert `permissions: { contents: read }` at top level |
|
||
| R2 `permissions: write-all` | Replace with `contents: read`; move `write` to the single job that needs it |
|
||
| R3 OIDC + AWS keys present | Ask AskUserQuestion: "Which one do you keep? OIDC / keys" — remove the other |
|
||
| R4 `key: github.ref` | Replace with `key: <name>-${{ hashFiles('<lockfile>') }}` |
|
||
| R5 action pinned by tag | Look up the tag's commit SHA on the action's repo, replace `@vX.Y` with the full 40-hex SHA, add `# vX.Y` comment. If lookup fails, leave the tag with a TODO comment and ABORT rather than inventing a SHA (RULE 0.4) |
|
||
| R6 `::set-output` / `::save-state` | Replace with `$GITHUB_OUTPUT` / `$GITHUB_STATE` redirect (GH docs 2023+) |
|
||
| R6 `actions/checkout@v1` / `v2` | Upgrade to `@v4` (and re-run R5 pin-by-SHA) |
|
||
| R7 `pull_request_target` + PR-head checkout | Either remove `pull_request_target` (prefer) OR remove the `ref: ${{ github.event.pull_request.head.sha }}` line. Present both to user |
|
||
|
||
## 5d — Re-run linter after fixes
|
||
|
||
After all fixes applied, re-run `kei-ci-lint` once. If still failing, enter the 3-Level Escalation (dev-workflow.md): after 2 automatic fix attempts, STOP and escalate — present the remaining findings to the user with a numbered plan (NO DOWNGRADE: alternative scaffolds, not "accept the violation").
|
||
|
||
## 5e — Emit final report
|
||
|
||
Template (from SKILL.md):
|
||
|
||
```
|
||
=== CI-SCAFFOLD REPORT ===
|
||
Repo: <REPO>
|
||
Platform: <PLATFORM>
|
||
Languages: <LANGS joined>
|
||
Deploy: <DEPLOY>
|
||
Release: <RELEASE>
|
||
Matrix: <|os|> × <|versions|> × <|targets|> = <N> cells
|
||
Workflows: <paths, one per line>
|
||
Secrets: <|SECRETS.required|> env names scaffolded to secrets/ci.env (posture: <SECRETS.posture>)
|
||
Lint: <PASS | WARN-<N> | FAIL-<N>> — <fixes applied count>/<skips count>/<aborts count>
|
||
Next: git diff → review → commit on feat/<name>-ci → PR
|
||
|
||
Citations used (RULE 0.4):
|
||
- actions/checkout@v4 [VERIFIED: https://github.com/actions/checkout]
|
||
- actions/cache@v4 [VERIFIED: https://github.com/actions/cache]
|
||
- <one line per every uses: in generated files>
|
||
```
|
||
|
||
## 5f — Handoff
|
||
|
||
If `LINT` is `PASS` or `WARN-only`, advise:
|
||
|
||
> Scaffold complete. Next: `git add .github/ .forgejo/ secrets/ci.env` (NOT the secret values — just the scaffold), commit on a `feat/ci-*` branch, push, and request review.
|
||
|
||
If `LINT = FAIL` after 2 fix passes, advise the user to invoke `compose-solution` with the remaining findings as new components — the meta-orchestrator may find missing `_blocks/` or suggest a new primitive.
|
||
|
||
## Verify-criterion
|
||
|
||
- `kei-ci-lint` was executed against the generated files.
|
||
- Every `FAIL` line produced exactly one AskUserQuestion triage.
|
||
- No action tag was invented to satisfy R5 — unresolvable SHA lookups must ABORT with a TODO (RULE 0.4 hard).
|
||
- Final report lists every citation used in every generated workflow.
|
||
- `Next:` line tells the user exactly what to stage, where to branch, and where to PR.
|