qfai 2.1.0 → 2.1.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/README.md +327 -55
- package/assets/defaults/agent-routing/qfai-triage.yml +9 -0
- package/assets/defaults/workflows/change-tooling.yml +0 -4
- package/assets/defaults/workflows/run-owned-cleanup.yml +12 -0
- package/assets/init/.claude/settings.json +27 -9
- package/assets/init/.codex/hooks.json +20 -8
- package/assets/init/.qfai/assistant/agent/frontend-engineer.md +5 -0
- package/assets/init/.qfai/assistant/agent/implementation-reviewer.md +14 -1
- package/assets/init/.qfai/assistant/agent/product-experience-architect.md +4 -0
- package/assets/init/.qfai/assistant/agent/product-surface-reviewer.md +7 -0
- package/assets/init/.qfai/assistant/agent/qa-gatekeeper.md +29 -0
- package/assets/init/.qfai/assistant/agent/requirements-analyst.md +8 -0
- package/assets/init/.qfai/assistant/rule/communication.md +18 -8
- package/assets/init/.qfai/assistant/rule/constitution.md +5 -4
- package/assets/init/.qfai/assistant/rule/drift-protocol.md +72 -5
- package/assets/init/.qfai/assistant/rule/references/asset-authoring.md +72 -0
- package/assets/init/.qfai/assistant/rule/references/context-summary.md +30 -0
- package/assets/init/.qfai/assistant/rule/references/gate-failure-autorepair.md +42 -0
- package/assets/init/.qfai/assistant/rule/references/griller-recommendations.md +23 -0
- package/assets/init/.qfai/assistant/rule/references/host-backstops.md +60 -0
- package/assets/init/.qfai/assistant/rule/references/placeholder-scan.md +25 -0
- package/assets/init/.qfai/assistant/rule/references/reviewer-findings.md +41 -0
- package/assets/init/.qfai/assistant/rule/references/reviewer-remit.md +35 -0
- package/assets/init/.qfai/assistant/rule/references/worker-edit-boundary.md +48 -0
- package/assets/init/.qfai/assistant/rule/shared-skill-delegation-baseline.md +39 -162
- package/assets/init/.qfai/assistant/rule/shared-skill-operating-baseline.md +14 -145
- package/assets/init/.qfai/assistant/rule/stage-cost.md +1 -1
- package/assets/init/.qfai/assistant/rule/test-layers.md +42 -0
- package/assets/init/.qfai/assistant/rule/ui-definition-protocol.md +6 -1
- package/assets/init/.qfai/assistant/skill/qfai-configure/SKILL.md +11 -45
- package/assets/init/.qfai/assistant/skill/qfai-configure/references/principles.md +25 -0
- package/assets/init/.qfai/assistant/skill/qfai-discussion/SKILL.md +1 -1
- package/assets/init/.qfai/assistant/skill/qfai-discussion/references/discussion-completion-matrix.md +12 -9
- package/assets/init/.qfai/assistant/skill/qfai-discussion/references/ui-bearing-playbook.md +2 -4
- package/assets/init/.qfai/assistant/skill/qfai-discussion/references/ui_ux/platform_baselines.md +11 -0
- package/assets/init/.qfai/assistant/skill/qfai-discussion/references/ui_ux/review_audit_playbook.md +11 -0
- package/assets/init/.qfai/assistant/skill/qfai-discussion/references/ui_ux_best_practices.md +13 -42
- package/assets/init/.qfai/assistant/skill/qfai-discussion/templates/uiux/00_index.md +0 -16
- package/assets/init/.qfai/assistant/skill/qfai-grill/SKILL.md +1 -1
- package/assets/init/.qfai/assistant/skill/qfai-grilling/SKILL.md +16 -88
- package/assets/init/.qfai/assistant/skill/qfai-grilling/references/delegated-session.md +58 -0
- package/assets/init/.qfai/assistant/skill/qfai-grilling/references/session-record.md +42 -0
- package/assets/init/.qfai/assistant/skill/qfai-implement/SKILL.md +17 -4
- package/assets/init/.qfai/assistant/skill/qfai-implement/references/credential-reuse.md +9 -0
- package/assets/init/.qfai/assistant/skill/qfai-implement/references/cross-spec-ownership.md +41 -0
- package/assets/init/.qfai/assistant/skill/qfai-implement/references/oracle-strength.md +6 -1
- package/assets/init/.qfai/assistant/skill/qfai-implement/references/parallelization-policy.md +9 -1
- package/assets/init/.qfai/assistant/skill/qfai-implement/references/red-admissibility.md +47 -1
- package/assets/init/.qfai/assistant/skill/qfai-implement/references/ui-affecting.md +4 -3
- package/assets/init/.qfai/assistant/skill/qfai-maintain/SKILL.md +4 -4
- package/assets/init/.qfai/assistant/skill/qfai-migration-v1-to-v2/SKILL.md +16 -10
- package/assets/init/.qfai/assistant/skill/qfai-migration-v1-to-v2/references/migration-guide.md +10 -260
- package/assets/init/.qfai/assistant/skill/qfai-migration-v1-to-v2/references/migration-placement.md +273 -0
- package/assets/init/.qfai/assistant/skill/qfai-prototyping/SKILL.md +5 -4
- package/assets/init/.qfai/assistant/skill/qfai-prototyping/references/design-md-spec.md +14 -5
- package/assets/init/.qfai/assistant/skill/qfai-prototyping/references/generator-prompt.md +10 -0
- package/assets/init/.qfai/assistant/skill/qfai-prototyping/references/handoff.md +1 -1
- package/assets/init/.qfai/assistant/skill/qfai-prototyping/references/iteration-loop.md +3 -4
- package/assets/init/.qfai/assistant/skill/qfai-prototyping/references/review-payload-schema.md +12 -5
- package/assets/init/.qfai/assistant/skill/qfai-prototyping/references/reviewer-prompt.md +33 -4
- package/assets/init/.qfai/assistant/skill/qfai-run/SKILL.md +34 -36
- package/assets/init/.qfai/assistant/skill/qfai-run/references/evidence-delivery.md +322 -0
- package/assets/init/.qfai/assistant/skill/qfai-run/references/extraction.md +67 -24
- package/assets/init/.qfai/assistant/skill/qfai-run/references/operator-screens.md +246 -5
- package/assets/init/.qfai/assistant/skill/qfai-run/references/plan.md +29 -5
- package/assets/init/.qfai/assistant/skill/qfai-run/references/stage-points.md +43 -0
- package/assets/init/.qfai/assistant/skill/qfai-sdd/SKILL.md +5 -4
- package/assets/init/.qfai/assistant/skill/qfai-sdd/references/concrete-abstract-cycle.md +10 -1
- package/assets/init/.qfai/assistant/skill/qfai-sdd/references/contract-artifact-rules.md +22 -9
- package/assets/init/.qfai/assistant/skill/qfai-sdd/references/design-anti-patterns.md +41 -6
- package/assets/init/.qfai/assistant/skill/qfai-sdd/references/design-md-authoring.md +11 -5
- package/assets/init/.qfai/assistant/skill/qfai-sdd/references/design-md-brand-catalog.md +17 -2
- package/assets/init/.qfai/assistant/skill/qfai-sdd/references/requirements-decomposition.md +10 -2
- package/assets/init/.qfai/assistant/skill/qfai-sdd/references/sdd-execution-playbook.md +34 -9
- package/assets/init/.qfai/assistant/skill/qfai-sdd/references/sdd-phase-checklists.md +4 -4
- package/assets/init/.qfai/assistant/skill/qfai-sdd/references/sdd-quality-gate.md +2 -2
- package/assets/init/.qfai/assistant/skill/qfai-sdd/references/sdd-triage.md +177 -7
- package/assets/init/.qfai/assistant/skill/qfai-sdd/references/spec-traceability-rules.md +29 -5
- package/assets/init/.qfai/assistant/skill/qfai-sdd/references/ui-contract-guide.md +130 -1
- package/assets/init/.qfai/assistant/skill/qfai-sdd/references/ui-design-contract-normalization.md +4 -30
- package/assets/init/.qfai/assistant/skill/qfai-sdd/templates/change-request.md +39 -2
- package/assets/init/.qfai/assistant/skill/qfai-sdd/templates/contracts/db-contract.sample.sql +2 -2
- package/assets/init/.qfai/assistant/skill/qfai-sdd/templates/contracts/ui-contract.sample.yaml +52 -5
- package/assets/init/.qfai/assistant/skill/qfai-sdd/templates/spec/03_contract/cli/cli-NNNN-title.md +2 -2
- package/assets/init/.qfai/assistant/skill/qfai-sdd/templates/spec/03_contract/tech.md +1 -1
- package/assets/init/.qfai/assistant/skill/qfai-sdd/templates/spec/decisions.md +7 -0
- package/assets/init/.qfai/assistant/skill/qfai-triage/SKILL.md +30 -20
- package/assets/init/.qfai/assistant/skill/qfai-verify/SKILL.md +6 -5
- package/assets/init/.qfai/assistant/skill/qfai-verify/references/context-load.md +9 -6
- package/assets/init/.qfai/assistant/skill/qfai-verify/references/verify-output-contract.md +92 -13
- package/assets/init/.qfai/assistant/skill/web-research/SKILL.md +37 -31
- package/assets/init/.qfai/assistant/skill/web-research/mcp-templates/brave-search/config.toml +2 -4
- package/assets/init/.qfai/assistant/skill/web-research/mcp-templates/brave-search/mcp-config.json +9 -5
- package/assets/init/.qfai/assistant/skill/web-research/mcp-templates/firecrawl/.mcp.json +1 -2
- package/assets/init/.qfai/assistant/skill/web-research/mcp-templates/firecrawl/config.toml +3 -3
- package/assets/init/.qfai/assistant/skill/web-research/mcp-templates/firecrawl/mcp-config.json +11 -8
- package/assets/init/.qfai/assistant/skill/web-research/mcp-templates/playwright/config.toml +1 -1
- package/assets/init/.qfai/assistant/skill/web-research/mcp-templates/playwright/mcp-config.json +7 -3
- package/assets/init/.qfai/assistant/step/common-design-md/STEP.md +17 -7
- package/assets/init/.qfai/assistant/step/common-gate-run/STEP.md +126 -13
- package/assets/init/.qfai/assistant/step/common-review-cycle/STEP.md +3 -2
- package/assets/init/.qfai/assistant/step/discussion-pack/STEP.md +1 -0
- package/assets/init/.qfai/assistant/step/discussion-research/STEP.md +2 -0
- package/assets/init/.qfai/assistant/step/discussion-uiux/STEP.md +12 -4
- package/assets/init/.qfai/assistant/step/implement-backport/STEP.md +1 -1
- package/assets/init/.qfai/assistant/step/implement-benchmark/STEP.md +7 -4
- package/assets/init/.qfai/assistant/step/implement-dep-bump/STEP.md +11 -1
- package/assets/init/.qfai/assistant/step/implement-diagnose/STEP.md +2 -0
- package/assets/init/.qfai/assistant/step/implement-oracle-parity/STEP.md +2 -2
- package/assets/init/.qfai/assistant/step/implement-quarantine/STEP.md +3 -3
- package/assets/init/.qfai/assistant/step/implement-refactor/STEP.md +2 -2
- package/assets/init/.qfai/assistant/step/implement-regression-fix/STEP.md +4 -3
- package/assets/init/.qfai/assistant/step/implement-retire/STEP.md +6 -3
- package/assets/init/.qfai/assistant/step/implement-revert/STEP.md +4 -3
- package/assets/init/.qfai/assistant/step/implement-scaffold/STEP.md +3 -3
- package/assets/init/.qfai/assistant/step/implement-seam/STEP.md +9 -6
- package/assets/init/.qfai/assistant/step/implement-stress-harness/STEP.md +1 -1
- package/assets/init/.qfai/assistant/step/implement-sweep/STEP.md +4 -3
- package/assets/init/.qfai/assistant/step/implement-tdd/STEP.md +42 -6
- package/assets/init/.qfai/assistant/step/implement-test-fix/STEP.md +2 -0
- package/assets/init/.qfai/assistant/step/implement-tooling/STEP.md +22 -2
- package/assets/init/.qfai/assistant/step/maintain-edit/STEP.md +18 -14
- package/assets/init/.qfai/assistant/step/prototyping-grill/STEP.md +4 -3
- package/assets/init/.qfai/assistant/step/prototyping-loop/STEP.md +4 -0
- package/assets/init/.qfai/assistant/step/prototyping-preflight/STEP.md +1 -3
- package/assets/init/.qfai/assistant/step/sdd-contract/STEP.md +11 -0
- package/assets/init/.qfai/assistant/step/sdd-flow/STEP.md +4 -0
- package/assets/init/.qfai/assistant/step/sdd-gate/STEP.md +4 -0
- package/assets/init/.qfai/assistant/step/sdd-story/STEP.md +10 -0
- package/assets/init/.qfai/assistant/step/sdd-triage/STEP.md +37 -11
- package/assets/init/.qfai/assistant/step/triage-answer/STEP.md +5 -4
- package/assets/init/.qfai/assistant/step/triage-close/STEP.md +33 -23
- package/assets/init/.qfai/assistant/step/triage-cluster/STEP.md +5 -3
- package/assets/init/.qfai/assistant/step/triage-decompose/STEP.md +2 -0
- package/assets/init/.qfai/assistant/step/triage-dedupe/STEP.md +4 -0
- package/assets/init/.qfai/assistant/step/triage-handoff/STEP.md +13 -4
- package/assets/init/.qfai/assistant/step/triage-investigate/STEP.md +8 -5
- package/assets/init/.qfai/assistant/step/triage-owned-cleanup/STEP.md +86 -0
- package/assets/init/.qfai/assistant/step/triage-request-info/STEP.md +2 -0
- package/assets/init/.qfai/assistant/step/triage-security-intake/STEP.md +6 -3
- package/assets/init/.qfai/assistant/step/verify-change-note/STEP.md +9 -5
- package/assets/init/.qfai/assistant/step/verify-commit/STEP.md +39 -6
- package/assets/init/.qfai/assistant/step/verify-external/STEP.md +5 -2
- package/assets/init/.qfai/assistant/step/verify-qfai-gate/STEP.md +10 -2
- package/assets/init/.qfai/assistant/step/verify-release-notes/STEP.md +1 -0
- package/assets/init/.qfai/assistant/step/verify-repeat-run/STEP.md +7 -5
- package/assets/init/.qfai/assistant/step/verify-repo-gate/STEP.md +136 -28
- package/assets/init/.qfai/waivers.yml +1 -1
- package/assets/init/root/.agents/rules/ai-readable-markdown.md +98 -0
- package/assets/init/root/.agents/rules/api-budget.md +191 -13
- package/assets/init/root/.agents/rules/documentation-clarity.md +192 -35
- package/assets/init/root/.agents/rules/grilling.md +4 -4
- package/assets/init/root/.agents/rules/interface-clarity.md +5 -5
- package/assets/init/root/.agents/rules/minimal-implementation.md +11 -3
- package/assets/init/root/.agents/rules/reminders.json +27 -14
- package/assets/init/root/.agents/rules/session-feedback.md +136 -0
- package/assets/init/root/.agents/rules/temporary-files.md +47 -5
- package/assets/init/root/.agents/rules/untrusted-content.md +3 -3
- package/assets/init/root/.agents/rules/user-questions.md +74 -36
- package/assets/init/root/.gitattributes +9 -0
- package/assets/init/root/.github/workflows/qfai-docs.yml +44 -12
- package/assets/init/root/.github/workflows/qfai-tests.yml +58 -15
- package/assets/init/root/.github/workflows/qfai-validate.yml +49 -42
- package/assets/init/root/AGENTS.md +23 -21
- package/assets/mdschema/story/03_contract/tech.mdschema.yml +7 -3
- package/assets/sandbox-templates/default-deny.yaml +9 -5
- package/assets/schemas/workflow/extraction.schema.json +85 -5
- package/assets/schemas/workflow/plan.schema.json +9 -2
- package/assets/scripts/check-mdschema.mjs +172 -5
- package/assets/uix-rev/comparison-review.md +1 -1
- package/assets/uix-rev/contracts-review.md +1 -2
- package/dist/cli/index.cjs +6499 -7688
- package/dist/cli/index.cjs.map +1 -1
- package/dist/cli/index.mjs +6449 -7641
- package/dist/cli/index.mjs.map +1 -1
- package/dist/index.cjs +5548 -7823
- package/dist/index.cjs.map +1 -1
- package/dist/index.d.cts +40 -666
- package/dist/index.d.ts +40 -666
- package/dist/index.mjs +5397 -7648
- package/dist/index.mjs.map +1 -1
- package/docs/MIGRATION-2.0.0.md +1 -1
- package/package.json +5 -7
- package/assets/init/root/CLAUDE.md +0 -45
package/README.md
CHANGED
|
@@ -79,11 +79,21 @@ Then open your AI coding agent in the repository and describe the change in your
|
|
|
79
79
|
|
|
80
80
|
> Let each customer register up to five notification addresses, with no duplicates.
|
|
81
81
|
|
|
82
|
+
If you only have an idea, say so: the run starts with a discussion that structures scope and open questions.
|
|
83
|
+
|
|
82
84
|
The agent announces the goal, the stages it will run and the files it may change, then runs them.
|
|
83
85
|
It asks you only what it cannot decide for you, such as whether to create a new story.
|
|
86
|
+
Answer its questions, or say `stop` to end the run.
|
|
84
87
|
The stages fill the seeded story tree and follow the project's Standard commands in
|
|
85
88
|
`<paths.contractsDir>/tech.md` (by default `.qfai/spec/03_contract/tech.md`) for its quality gates.
|
|
86
89
|
|
|
90
|
+
When the run ends, check the result:
|
|
91
|
+
|
|
92
|
+
```bash
|
|
93
|
+
npx qfai validate
|
|
94
|
+
npx qfai report
|
|
95
|
+
```
|
|
96
|
+
|
|
87
97
|
To drive the stages yourself instead:
|
|
88
98
|
Run `/qfai-discussion` and `/qfai-sdd` to fill the seeded story tree.
|
|
89
99
|
See [Invoking a stage directly](#invoking-a-stage-directly-expert-path).
|
|
@@ -92,7 +102,7 @@ See [Invoking a stage directly](#invoking-a-stage-directly-expert-path).
|
|
|
92
102
|
|
|
93
103
|
You state the change once, in your own words.
|
|
94
104
|
The `qfai-run` skill reads it into facts: what it asks for, its risks, and how sure that reading is.
|
|
95
|
-
`npx qfai workflow plan` then picks one of
|
|
105
|
+
`npx qfai workflow plan` then picks one of the fixed routes from those facts by ordered decision rules
|
|
96
106
|
and returns the route's plan, writing nothing. The session runs each step of the plan in order and
|
|
97
107
|
asks you only the decisions that are yours and each release. You type no stage name.
|
|
98
108
|
|
|
@@ -313,27 +323,22 @@ flowchart LR
|
|
|
313
323
|
(`assistant/rule/`, `skill/`, `agent/` and `prompt/`), plus `qfai.config.yaml`.
|
|
314
324
|
- Options:
|
|
315
325
|
|
|
316
|
-
| Flag
|
|
317
|
-
|
|
|
318
|
-
| `--dir <path>`
|
|
319
|
-
| `--root <path>`
|
|
320
|
-
| `--force`
|
|
321
|
-
| `--dry-run`
|
|
322
|
-
| `--
|
|
323
|
-
| `--
|
|
324
|
-
| `--
|
|
325
|
-
| `--
|
|
326
|
-
| `--version`, `-V` | Print the installed QFAI version to stdout and exit 0. Accepted by every command, `init` included, and handled before the command runs, so it works outside a project too. |
|
|
327
|
-
|
|
328
|
-
- `D-DEPRECATED-PATH` means the legacy assistant layout remains past its
|
|
329
|
-
supported window. Run `npx qfai init --upgrade-assistant-tree` to copy
|
|
330
|
-
recognized files into the current tree without deleting their sources.
|
|
326
|
+
| Flag | Effect |
|
|
327
|
+
| ----------------- | ----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
|
|
328
|
+
| `--dir <path>` | Output directory (default: the current directory). Wins over `--root` when both are given. |
|
|
329
|
+
| `--root <path>` | Every other command reads this as the target directory; `init` reads it as the output directory too, but only when `--dir` is omitted. |
|
|
330
|
+
| `--force` | Overwrite the shipped skills, steps, agents and rules, the rule masters under `.agents/rules/`, their host wrappers, and generated Copilot instructions, whether or not you edited them. Project content, `qfai.config.yaml`, `DESIGN.md`, `AGENTS.md` and routing overrides are preserved. The managed `.gitignore` block and `core.symlinks` setting are repaired on every non-dry-run. |
|
|
331
|
+
| `--dry-run` | Report what would change and write nothing. |
|
|
332
|
+
| `--yes` | Reserved for a future interactive mode; no behavioural difference today. |
|
|
333
|
+
| `--verbose` | Expand the run report's `skipped` list to the full path listing. Off by default, so a no-op re-run prints the skip count and a pointer to this flag instead of every shipped asset path. It does not gate the written or removed listings: those are printed whenever they have entries, with or without this flag. |
|
|
334
|
+
| `--help`, `-h` | Print the CLI usage banner and exit without writing anything. Accepted by every command, `init` included, and handled before the command runs. |
|
|
335
|
+
| `--version`, `-V` | Print the installed QFAI version to stdout and exit 0. Accepted by every command, `init` included, and handled before the command runs, so it works outside a project too. |
|
|
331
336
|
|
|
332
337
|
- `npx qfai validate`
|
|
333
338
|
- Validates the story tree, contracts and test obligations, writes `.qfai/report/validate.json`,
|
|
334
339
|
and appends run logs to `.qfai/report/run-*/`; use `--fail-on error` (or `--fail-on warning`) to turn it into a CI gate,
|
|
335
340
|
and `--format github` to emit GitHub-friendly annotations.
|
|
336
|
-
Use `--flow BF-0001` to scope a run to one business flow.
|
|
341
|
+
Use `--flow BF-0001` to scope a run to one business flow.
|
|
337
342
|
Use `--profile discussion|sdd|prototyping|atdd|tdd|verify` for local skill-owned checks; CI should use default/full validation (or `verify` / `tdd` for the dedicated CI gates).
|
|
338
343
|
- `npx qfai report`
|
|
339
344
|
- Produces a human-readable report (`report.md` by default) or an internal JSON export (`report.json`) from `validate.json`; use `--base-url` to link file paths in Markdown to your repository viewer.
|
|
@@ -403,6 +408,8 @@ paths:
|
|
|
403
408
|
testsDir: tests
|
|
404
409
|
validation:
|
|
405
410
|
failOn: error # error | warning | never
|
|
411
|
+
staleTerms: # terms the specs must no longer state, such as a rejected option
|
|
412
|
+
- SMTP
|
|
406
413
|
traceability:
|
|
407
414
|
testFileGlobs:
|
|
408
415
|
- "src/**/*.test.ts"
|
|
@@ -416,6 +423,7 @@ uiux:
|
|
|
416
423
|
|
|
417
424
|
Notes.
|
|
418
425
|
|
|
426
|
+
- `validation.staleTerms` lists terms a project no longer wants in its specs. `qfai validate` warns on each line of a spec document that states one, apart from `decisions.md` and `open-questions.md`.
|
|
419
427
|
- `validate.json` is a **public** surface: its keys are documented in
|
|
420
428
|
`.qfai/assistant/skill/qfai-verify/references/validate-json-schema.md`.
|
|
421
429
|
Changes to its keys follow the `@api` classification in
|
|
@@ -423,15 +431,29 @@ Notes.
|
|
|
423
431
|
issue order are not stable; match on `issues[].code`.
|
|
424
432
|
- `report.json`, `doctor.json`, and `run-*` JSON logs are internal exports and are not a stable external contract; prefer `report.md` for integrations that must survive tool upgrades.
|
|
425
433
|
|
|
426
|
-
##
|
|
434
|
+
## Dependency security
|
|
435
|
+
|
|
436
|
+
The glob-matching dependency `braces` has an unresolved
|
|
437
|
+
[stack-exhaustion denial-of-service advisory](https://github.com/advisories/GHSA-vfj7-8cjw-p6xm).
|
|
438
|
+
QFAI accepts this residual risk only for reviewed project patterns and paths,
|
|
439
|
+
trusted configuration and trusted SDK callers. This is risk acceptance, not a
|
|
440
|
+
clean audit or proof that QFAI is unaffected. Reproduction and exploitation in
|
|
441
|
+
QFAI remain unverified.
|
|
442
|
+
|
|
443
|
+
Review include, ignore and negative patterns, constructed paths and SDK inputs.
|
|
444
|
+
`validateProject` accepts a caller-supplied `ConfigLoadResult` without invoking
|
|
445
|
+
the configuration loader; the caller must review those values too. Catching
|
|
446
|
+
errors and limiting results after glob expansion do not defend against stack
|
|
447
|
+
exhaustion during expansion.
|
|
427
448
|
|
|
428
|
-
|
|
429
|
-
|
|
430
|
-
|
|
431
|
-
|
|
432
|
-
4. Run `npx qfai validate` then `npx qfai report`.
|
|
449
|
+
Untrusted pull requests, externally supplied configuration and service request
|
|
450
|
+
inputs are outside this acceptance. Review those inputs and restrict access;
|
|
451
|
+
do not expose glob processing to them until your mitigation and security review
|
|
452
|
+
cover them.
|
|
433
453
|
|
|
434
|
-
|
|
454
|
+
Reassess the risk when a compatible patch becomes available or untrusted input
|
|
455
|
+
is needed. A forced downgrade to `qfai@0.4.0` is not a compatible fix for the
|
|
456
|
+
current major API; do not apply it through `npm audit fix --force`.
|
|
435
457
|
|
|
436
458
|
## FAQ
|
|
437
459
|
|
|
@@ -464,10 +486,16 @@ there, and all three open with a ``# Generated by `qfai init` `` line. All three
|
|
|
464
486
|
every push to `main` or `master` and on every pull request, and all three run on the
|
|
465
487
|
runner `vars.QFAI_CI_RUNNER` names (`ubuntu-latest` when you set nothing).
|
|
466
488
|
|
|
489
|
+
`npx qfai init` writes a workflow again whenever its file is missing. To stop it
|
|
490
|
+
writing one, set `workflow.skipShipped` in `qfai.config.yaml` to a list of file
|
|
491
|
+
names, for example `[qfai-tests.yml]`, and delete the file.
|
|
492
|
+
|
|
467
493
|
- `qfai-validate.yml` runs `npx qfai validate --profile full --fail-on error`,
|
|
468
|
-
and on a pull request also `npx qfai validate --profile drift --fail-on error
|
|
469
|
-
The `full` profile evaluates every gate group
|
|
470
|
-
second run nothing there could fail on a downstream
|
|
494
|
+
and on a pull request also `npx qfai validate --profile drift --fail-on error`,
|
|
495
|
+
as a second step of the same job. The `full` profile evaluates every gate group
|
|
496
|
+
except drift, so without the second run nothing there could fail on a downstream
|
|
497
|
+
edit to upstream SSOT. The second step runs after a failing first one, so one run
|
|
498
|
+
reports both profiles, and the dependencies are installed once.
|
|
471
499
|
It installs dependencies from whichever lockfile the repository has (pnpm /
|
|
472
500
|
yarn / npm) and falls back to `npm install` when there is none, and it takes
|
|
473
501
|
the Node version from your `.nvmrc` or `.node-version`, warning and
|
|
@@ -477,9 +505,10 @@ runner `vars.QFAI_CI_RUNNER` names (`ubuntu-latest` when you set nothing).
|
|
|
477
505
|
holding a `pnpm-lock.yaml` with no such field fails the job with an
|
|
478
506
|
annotation naming the field rather than reporting a validation it never ran.
|
|
479
507
|
Declare `"packageManager": "pnpm@X.Y.Z"` so CI matches the version you
|
|
480
|
-
develop against. The `full` profile includes the
|
|
481
|
-
|
|
482
|
-
CI never checked.
|
|
508
|
+
develop against. The `full` profile includes the test stub gate
|
|
509
|
+
(`QFAI-TEST-001` for a todo, `QFAI-TEST-003` for a skip), so the job can fail
|
|
510
|
+
your default branch on findings your existing CI never checked. See
|
|
511
|
+
"Skipped and todo tests" below for what the gate reports and what it cannot see.
|
|
483
512
|
- `qfai-tests.yml` declares one lane per test layer (unit, component,
|
|
484
513
|
integration, api, e2e) and runs none of them until you opt in: a lane runs
|
|
485
514
|
only when your `package.json` declares the matching `test:<layer>` script
|
|
@@ -506,7 +535,32 @@ A push to `main` or `master` runs the test lanes and the document checks again b
|
|
|
506
535
|
default, because nothing in the files can tell whether that commit passed a pull
|
|
507
536
|
request first. If your branch protection requires these checks before every merge,
|
|
508
537
|
set the repository variable `QFAI_CI_PUSH_POLICY` to `protected`: the push then runs
|
|
509
|
-
neither, and `qfai validate` still runs as the post-merge check.
|
|
538
|
+
neither, and `qfai validate` still runs as the post-merge check. If you run
|
|
539
|
+
`qfai validate` in a post-merge job of your own, set it to `none` instead: the
|
|
540
|
+
push then starts no job of the validate workflow either.
|
|
541
|
+
|
|
542
|
+
`protected` is safe only when GitHub requires the branch to be up to date before
|
|
543
|
+
a pull request can merge: the branch protection option "Require branches to be up
|
|
544
|
+
to date before merging", called `strict` in the API. Without it, two pull requests
|
|
545
|
+
can each pass on their own and break the branch once both are merged. One that
|
|
546
|
+
changes a function signature and one that starts calling the old signature is the
|
|
547
|
+
usual case. The default branch is then red while every pull request was green.
|
|
548
|
+
|
|
549
|
+
Requiring up-to-date branches makes every parallel pull request update and rerun
|
|
550
|
+
after each merge. If that costs too much, there is a middle option between running
|
|
551
|
+
the full lanes again and running nothing: keep `QFAI_CI_PUSH_POLICY` at
|
|
552
|
+
`protected`, and add a small post-merge job of your own to a workflow you
|
|
553
|
+
maintain.
|
|
554
|
+
|
|
555
|
+
- It runs only what can break when two pull requests combine: the type check, and
|
|
556
|
+
the schema or contract consistency checks. The shipped `qfai-validate.yml`
|
|
557
|
+
already runs the validator on every push, so the job does not repeat it.
|
|
558
|
+
- It installs dependencies once, and uses one concurrency group with
|
|
559
|
+
`cancel-in-progress: true`, so a newer push cancels an older run. The newest
|
|
560
|
+
commit contains the older ones, so nothing goes unchecked.
|
|
561
|
+
- It leaves out the test suites. A break that only they would catch shows up on
|
|
562
|
+
the next pull request, which fails on code it did not change. In one project the
|
|
563
|
+
job took about two billed minutes where the full lanes took about 29.
|
|
510
564
|
|
|
511
565
|
All three files are copied create-only — `qfai init` writes a workflow only
|
|
512
566
|
where no file of that name exists, and never overwrites one, not even with
|
|
@@ -572,11 +626,231 @@ Waiver policy.
|
|
|
572
626
|
- Expired waivers are reported as warnings (`QFAI-WAIVER-003`) and must be renewed or removed with evidence.
|
|
573
627
|
- Suppressed findings remain visible in reports as `suppressed=true`; waivers do not erase findings.
|
|
574
628
|
|
|
629
|
+
When upgrading a project with `.qfai/waivers.yml`, back up that file. Check the
|
|
630
|
+
current public finding codes and the release notes for confirmed removals or
|
|
631
|
+
renames. Update a `rule:` value only when the documented rename preserves the
|
|
632
|
+
finding's meaning and scope. Remove confirmed retired or inapplicable waivers,
|
|
633
|
+
keeping the backup and recording each removal's reason for the operator. Do not
|
|
634
|
+
rename whole code prefixes or automatically delete an unknown rule.
|
|
635
|
+
|
|
636
|
+
Rerun full validation and require zero errors. An unknown waiver rule produces
|
|
637
|
+
`QFAI-WAIVER-004` at `warning` and is not applied in that run; investigate it
|
|
638
|
+
against the current diagnostics and release notes.
|
|
639
|
+
|
|
575
640
|
Typical customizations.
|
|
576
641
|
|
|
577
642
|
- Add a `doctor` step before validate if you want to fail fast on path/glob/config issues.
|
|
578
643
|
- Publish `.qfai/report/validate.json`, `report.md`, and relevant `.qfai/report/run-*/` logs as CI artifacts.
|
|
579
644
|
|
|
645
|
+
### What a run costs
|
|
646
|
+
|
|
647
|
+
On a private repository with GitHub-hosted runners, cost follows the number of
|
|
648
|
+
jobs, not how long they run. Each job rounds up to a whole minute, a skipped job
|
|
649
|
+
costs nothing, and a workflow that starts several quick jobs on every event costs
|
|
650
|
+
more than one slow job. A closed pull request starts a run too, but every job in
|
|
651
|
+
it declines, so nothing is billed.
|
|
652
|
+
|
|
653
|
+
Jobs the shipped workflows start on each `opened`, `synchronize` and `reopened`
|
|
654
|
+
event of a pull request:
|
|
655
|
+
|
|
656
|
+
| Workflow | Nothing to run | Lane runs |
|
|
657
|
+
| ------------------- | --------------------------------- | --------------------------------------------------- |
|
|
658
|
+
| `qfai-validate.yml` | 1: `qfai validate`, both profiles | 1 |
|
|
659
|
+
| `qfai-tests.yml` | 1: `change detection` | 2, plus one per selected lane (at most 5) |
|
|
660
|
+
| `qfai-docs.yml` | 1: `change scope` | 4: adds the `shape` and `mermaid` checks and `docs` |
|
|
661
|
+
|
|
662
|
+
When nothing is selected, `verdict` is skipped, and when nothing a document check
|
|
663
|
+
reads changed, `docs` is skipped. Each workflow then starts one job, and the
|
|
664
|
+
detection and scope jobs say in a notice annotation why. One pull request event
|
|
665
|
+
starts 3 jobs in all, and the most it can start is 12. On a push to the default
|
|
666
|
+
branch, `qfai-validate.yml` starts 1 job, `QFAI_CI_PUSH_POLICY=protected` brings the
|
|
667
|
+
other two workflows down to their idle counts, and `none` also skips the validate
|
|
668
|
+
job, which leaves `change detection` and `change scope`.
|
|
669
|
+
|
|
670
|
+
Four of those jobs install nothing and run no test: `change detection`, `verdict`,
|
|
671
|
+
`change scope` and `docs`. They take seconds, so each bills one minute.
|
|
672
|
+
They read `vars.QFAI_CI_LIGHT_RUNNER`, so the price of that minute is a choice.
|
|
673
|
+
On a private repository with GitHub-hosted runners, set it to `ubuntu-slim`:
|
|
674
|
+
|
|
675
|
+
```bash
|
|
676
|
+
gh variable set QFAI_CI_LIGHT_RUNNER --body ubuntu-slim
|
|
677
|
+
```
|
|
678
|
+
|
|
679
|
+
`ubuntu-slim` has 1 CPU and 5 GB of memory, runs unprivileged, limits a job to 15
|
|
680
|
+
minutes, and bills at a lower per-minute rate than `ubuntu-latest`; GitHub's
|
|
681
|
+
pricing page has the current figure. The light jobs run only Bash, Git and Node, all
|
|
682
|
+
of which it carries, and the workflows keep `ubuntu-latest` as the default, so this
|
|
683
|
+
is your variable to set. Do not point `QFAI_CI_RUNNER` at it: the jobs that install
|
|
684
|
+
dependencies, need Docker or can run past 15 minutes do not belong on it. A label
|
|
685
|
+
GitHub does not offer to your account leaves a job queued rather than failing it.
|
|
686
|
+
|
|
687
|
+
Each workflow file states its own counts in a "Jobs per pull request event" row of
|
|
688
|
+
its header table. `npx qfai doctor` reports the same counts for the workflows
|
|
689
|
+
installed in your repository, with the runner each job asks for. It is an `info`
|
|
690
|
+
finding and reads the files only. It reads none of your repository variables, so it
|
|
691
|
+
shows the variables a job falls back through and not the label they resolve to.
|
|
692
|
+
|
|
693
|
+
### Required checks and branch protection
|
|
694
|
+
|
|
695
|
+
Require these three checks, by exactly these names:
|
|
696
|
+
|
|
697
|
+
- From `qfai-tests.yml`: `verdict`
|
|
698
|
+
- From `qfai-docs.yml`: `qfai docs (document shape and Mermaid syntax)`
|
|
699
|
+
- From `qfai-validate.yml`: `qfai validate (full profile, fail on error)`
|
|
700
|
+
|
|
701
|
+
Each one fails when the work behind it fails. `verdict` and the `qfai docs` check
|
|
702
|
+
are skipped when nothing was selected or nothing a document check reads changed,
|
|
703
|
+
and GitHub counts a skipped job as satisfying a required check. The jobs behind
|
|
704
|
+
them are named by their matrix value, such as `qfai tests (unit)`, and a skipped
|
|
705
|
+
matrix job is reported under its unexpanded name, so a required check cannot name
|
|
706
|
+
them.
|
|
707
|
+
|
|
708
|
+
A check name is what branch protection matches. When you rename a job, or change
|
|
709
|
+
what it covers, change the required check in the same step. While the two differ
|
|
710
|
+
the required check is never reported, and every pull request is blocked. The
|
|
711
|
+
validate check above is the one to watch: on a pull request it covers the `full`
|
|
712
|
+
and `drift` profiles, and if you change the profiles you run, its name keeps
|
|
713
|
+
saying "full profile".
|
|
714
|
+
|
|
715
|
+
A job that an `if:` condition skips is reported as skipped, and that satisfies a
|
|
716
|
+
required check. A workflow that a workflow-level `paths` or `paths-ignore` filter
|
|
717
|
+
keeps from starting reports nothing, so its required check stays pending and the
|
|
718
|
+
pull request cannot merge. Put the decision in a job, and skip jobs. The shipped
|
|
719
|
+
`change detection` and `change scope` jobs do that. Do not put a `paths` filter on
|
|
720
|
+
a workflow with a required check.
|
|
721
|
+
|
|
722
|
+
The "Required check" row of each workflow's header table names the job to require.
|
|
723
|
+
|
|
724
|
+
### Checking workflow files
|
|
725
|
+
|
|
726
|
+
GitHub starts no job from a workflow file it cannot parse. The run shows as failed
|
|
727
|
+
with no jobs, on every push to every branch, and a change to the file does not show
|
|
728
|
+
up in its own pull request's checks, because the broken workflow never starts. A key
|
|
729
|
+
that appears twice in one mapping is enough, such as `env:` twice in one step after a
|
|
730
|
+
scripted edit, and many YAML loaders accept it without a word.
|
|
731
|
+
|
|
732
|
+
`npx qfai doctor` parses each `.yml` and `.yaml` file under `.github/workflows/` and
|
|
733
|
+
`.github/actions/` and warns with the file and the line. Run `actionlint` as well, and
|
|
734
|
+
run it after any scripted edit to a workflow. It also reports duplicate keys with line
|
|
735
|
+
numbers, and it checks expressions and job references that a YAML parser cannot. It
|
|
736
|
+
can be one step of a job you already run, such as a change-detection job, so it adds
|
|
737
|
+
no job.
|
|
738
|
+
|
|
739
|
+
### Skipped and todo tests
|
|
740
|
+
|
|
741
|
+
The stub gate is a static scan of the files that
|
|
742
|
+
`validation.traceability.testFileGlobs` selects. It blanks comments and string
|
|
743
|
+
literals first, then matches text patterns. The shipped workflow runs
|
|
744
|
+
`--fail-on error`, and every finding below is an error.
|
|
745
|
+
|
|
746
|
+
| What the scan finds | Finding |
|
|
747
|
+
| -------------------------------------------------------------------------------------------------------- | --------------- |
|
|
748
|
+
| `it.todo`, `test.todo`, `describe.todo` | `QFAI-TEST-001` |
|
|
749
|
+
| `it.skip`, `test.skip`, `describe.skip`, with a modifier before or after (`.skip.each`, `.concurrent`) | `QFAI-TEST-003` |
|
|
750
|
+
| The other stacks' placeholders: `pytest.skip`, `t.Skip`, `@Disabled`, `@Ignore`, `#[ignore]`, `[Ignore]` | `QFAI-TEST-001` |
|
|
751
|
+
|
|
752
|
+
It cannot see a skip that is not a text pattern, and none of these is reported:
|
|
753
|
+
|
|
754
|
+
- a conditional skip: `describe.skipIf(...)`, `it.skipIf(...)` and `it.runIf(...)`
|
|
755
|
+
- a form that selects the skip at run time, such as
|
|
756
|
+
`const suite = enabled ? describe : describe.skip`
|
|
757
|
+
- a skip called inside a running test, such as `ctx.skip()`
|
|
758
|
+
- a suite that returns early when the environment is missing, such as an unset
|
|
759
|
+
database URL
|
|
760
|
+
- a test file that the globs do not select; with no globs set the scan reports
|
|
761
|
+
`QFAI-TEST-002` and reads nothing
|
|
762
|
+
|
|
763
|
+
A suite skipped for a missing database therefore passes CI, and so does a suite
|
|
764
|
+
whose database failed to start. Only the test runner knows what was skipped in a
|
|
765
|
+
given run. Have it write a JSON report, and fail the job when a file skips more
|
|
766
|
+
tests than a list of named, allowed skips permits. Jest and Vitest write the same
|
|
767
|
+
shape: `jest --json --outputFile=test-report.json`, or
|
|
768
|
+
`vitest run --reporter=json --outputFile=test-report.json`. Add the flags to
|
|
769
|
+
your `test:<layer>` script, save this script as `scripts/check-skipped-tests.mjs`,
|
|
770
|
+
and run it in a step of `qfai-tests.yml` after the step that runs the tests:
|
|
771
|
+
|
|
772
|
+
```js
|
|
773
|
+
import { readFileSync } from "node:fs";
|
|
774
|
+
import path from "node:path";
|
|
775
|
+
|
|
776
|
+
const allowed = JSON.parse(readFileSync("allowed-skips.json", "utf8"));
|
|
777
|
+
const report = JSON.parse(readFileSync("test-report.json", "utf8"));
|
|
778
|
+
let failed = false;
|
|
779
|
+
for (const file of report.testResults) {
|
|
780
|
+
const name = path.relative(process.cwd(), file.name).split(path.sep).join("/");
|
|
781
|
+
const skipped = file.assertionResults.filter(
|
|
782
|
+
(test) => test.status !== "passed" && test.status !== "failed",
|
|
783
|
+
).length;
|
|
784
|
+
if (skipped > (allowed[name] ?? 0)) {
|
|
785
|
+
console.error(`${name}: ${skipped} tests did not run, ${allowed[name] ?? 0} allowed`);
|
|
786
|
+
failed = true;
|
|
787
|
+
}
|
|
788
|
+
}
|
|
789
|
+
process.exit(failed ? 1 : 0);
|
|
790
|
+
```
|
|
791
|
+
|
|
792
|
+
`allowed-skips.json` maps a test file to the number of tests it may skip, such as
|
|
793
|
+
`{ "orders.test.ts": 2 }`. Start from the count you measure today. The
|
|
794
|
+
list should only ever shrink: a pull request may remove an entry or lower a count,
|
|
795
|
+
and raising one is a decision a reviewer makes on purpose.
|
|
796
|
+
|
|
797
|
+
### Writing a change-scope gate for your own workflows
|
|
798
|
+
|
|
799
|
+
If you write a gate that skips your own heavy jobs on a small change, copy the
|
|
800
|
+
shape of the shipped `change detection` job: it falls back to running every lane
|
|
801
|
+
when the base commit is missing, the clone is shallow, the base is unreachable, the
|
|
802
|
+
diff fails, or a changed path is outside the set it knows. The rules that keep a
|
|
803
|
+
gate from skipping what it should have run:
|
|
804
|
+
|
|
805
|
+
- Decide from what the runners and tests read, not from directory names.
|
|
806
|
+
- Fail open. When the input is unknown, run everything: a skipped check claims the
|
|
807
|
+
change is fine, and a check that runs costs only its minutes.
|
|
808
|
+
- Run the gate's own table of cases, sample paths with the decision each must
|
|
809
|
+
get, before the gate. A pull request that changes the gate runs the checks that
|
|
810
|
+
cover the gate.
|
|
811
|
+
- Keep job names fixed, so required checks stay satisfied.
|
|
812
|
+
- Decide in a job and skip jobs with `if:`. Never use a workflow-level `paths`
|
|
813
|
+
filter, as the section above explains.
|
|
814
|
+
|
|
815
|
+
Three mistakes this prevents:
|
|
816
|
+
|
|
817
|
+
- **Excluding a directory the runner reads.** A gate treated all of
|
|
818
|
+
`tests/integration/` as irrelevant to end-to-end tests, but the browser runner's
|
|
819
|
+
configuration runs the `*.browser.spec.ts` files in it. A pull request that fixed
|
|
820
|
+
one of them ran no end-to-end job and passed. Exclude only the files the runner
|
|
821
|
+
does not read.
|
|
822
|
+
- **Trusting a general plan over the repository.** "A change to tests only can
|
|
823
|
+
skip the production build" is wrong where the build type-checks the tests
|
|
824
|
+
through the compiler's `include`. Read the configuration before you write the
|
|
825
|
+
rule.
|
|
826
|
+
- **A gate that skips its own tests.** See the third rule above.
|
|
827
|
+
|
|
828
|
+
### Measuring Actions minutes
|
|
829
|
+
|
|
830
|
+
Cost on a private repository is hard to read from the outside. The billing
|
|
831
|
+
endpoint for an organization needs an admin scope and may answer with an error,
|
|
832
|
+
the timing endpoint for a single run reports `billable` as zero, and the detailed
|
|
833
|
+
usage report needs an admin. This method needs only read access to the repository:
|
|
834
|
+
|
|
835
|
+
1. List the runs of one pull request, by its head commit:
|
|
836
|
+
`gh api "repos/OWNER/REPO/actions/runs?head_sha=SHA" --jq '.workflow_runs[].id'`
|
|
837
|
+
2. For each run, list its jobs:
|
|
838
|
+
`gh api "repos/OWNER/REPO/actions/runs/RUN_ID/jobs?per_page=100" --jq '.jobs[] | [.name, .conclusion, .started_at, .completed_at] | @tsv'`
|
|
839
|
+
3. A job bills `max(1, ceil(seconds / 60))` minutes, where the seconds run from
|
|
840
|
+
`started_at` to `completed_at`. A skipped job bills zero.
|
|
841
|
+
4. Compare pull requests by the same author and of the same kind of change, and
|
|
842
|
+
compare jobs and runs as well as minutes. Pull requests that only changed CI
|
|
843
|
+
settings are the case a change helps most, so they overstate the saving.
|
|
844
|
+
Compare pull requests that changed source and tests.
|
|
845
|
+
5. Count the runs of a day with
|
|
846
|
+
`gh api "repos/OWNER/REPO/actions/runs?created=YYYY-MM-DD&per_page=1" --jq .total_count`.
|
|
847
|
+
It is one cheap call per day, and it shows days that stand out. It also follows
|
|
848
|
+
the amount of development, so it cannot prove a reduction by itself.
|
|
849
|
+
|
|
850
|
+
A job that never started looks different from a job that failed: it has no steps,
|
|
851
|
+
an empty runner name and a duration of about two seconds. Its logs are not found,
|
|
852
|
+
which is not the logs having expired.
|
|
853
|
+
|
|
580
854
|
### Keeping QFAI itself up to date
|
|
581
855
|
|
|
582
856
|
A `qfai` bump is the one dependency update that is not finished when the version
|
|
@@ -590,6 +864,23 @@ Moving a project from the spec-pack layout to the story tree also requires
|
|
|
590
864
|
`/qfai-migration-v1-to-v2`. `init --force` refreshes shipped assets; the
|
|
591
865
|
migration skill moves project content and reports items that need a person.
|
|
592
866
|
|
|
867
|
+
To upgrade by hand:
|
|
868
|
+
|
|
869
|
+
1. Install the new version with your package manager, for example
|
|
870
|
+
`npm i -D qfai@<version>`.
|
|
871
|
+
2. Move every edit you made to a shipped skill, step, agent or rule into
|
|
872
|
+
`.qfai/assistant/skill.local/` or a rule overlay. The next step overwrites
|
|
873
|
+
the shipped copies.
|
|
874
|
+
3. Run `npx qfai init --force`. It replaces the skills and steps an agent may
|
|
875
|
+
be reading, so an agent upgrading the project reads them again from disk
|
|
876
|
+
afterwards.
|
|
877
|
+
4. Delete the files the release notes of the new version list as retired, once
|
|
878
|
+
nothing you keep reads them.
|
|
879
|
+
5. Run `npx qfai doctor` and `npx qfai validate`, and fix what they report.
|
|
880
|
+
6. Commit the result in one change.
|
|
881
|
+
|
|
882
|
+
An agent asked to upgrade `qfai` follows these steps as a dependency update.
|
|
883
|
+
|
|
593
884
|
Merging the bump on its own leaves the repository claiming a version whose
|
|
594
885
|
skills it does not have. If you use Renovate, QFAI publishes a preset that keeps
|
|
595
886
|
the two together:
|
|
@@ -668,7 +959,6 @@ commit that bumps the package, and to keep the two from being merged separately.
|
|
|
668
959
|
│ │ └── open-questions.md
|
|
669
960
|
│ └── waivers.yml
|
|
670
961
|
├── AGENTS.md
|
|
671
|
-
├── CLAUDE.md
|
|
672
962
|
└── qfai.config.yaml
|
|
673
963
|
```
|
|
674
964
|
|
|
@@ -705,17 +995,6 @@ provide those defaults to the agent.
|
|
|
705
995
|
The `.claude` / `.github` agent wrappers are symlinks and follow the canonical document
|
|
706
996
|
automatically; the Codex profiles are generated files, so rerun `npx qfai init --force`
|
|
707
997
|
to refresh them (and any other wrapper asset that has drifted).
|
|
708
|
-
`--force` deletes as well as overwrites: it removes the command and prompt wrappers
|
|
709
|
-
under `.claude/commands/` and `.github/prompts/`, and the skill wrappers under
|
|
710
|
-
`.claude/skills/`, `.agents/skills/`, `.codex/skills/` and `.github/skills/` for skills that are
|
|
711
|
-
not in the current release, whether those wrappers are directories or symlinks.
|
|
712
|
-
Files it did not write — a project's own slash command, prompt file or skill,
|
|
713
|
-
including one published from a project-authored `.qfai/assistant/skill/` entry — are left in place,
|
|
714
|
-
whatever they are named. Ownership is read from the file, not the name: a wrapper is removed only when
|
|
715
|
-
it carries the delegation line to the canonical document of the same name, or is a symlink into
|
|
716
|
-
`.qfai/assistant/skill/`. One consequence of that: a symlink has no content to prove who wrote it, so
|
|
717
|
-
if you publish a canonical skill of your own under a name QFAI itself once shipped, `--force` removes
|
|
718
|
-
that link. Your `.qfai/assistant/skill/` entry is untouched; re-create the link to publish it again.
|
|
719
998
|
|
|
720
999
|
### Supported hosts
|
|
721
1000
|
|
|
@@ -725,7 +1004,9 @@ No host is declared supported in this release.
|
|
|
725
1004
|
### Cross-AI rules and the writing reminder
|
|
726
1005
|
|
|
727
1006
|
`npx qfai init` seeds `.agents/rules/**`, the rule set every AI coding agent in
|
|
728
|
-
the project shares, and points `AGENTS.md`
|
|
1007
|
+
the project shares, and points `AGENTS.md` at it, with a line for each rule that says when
|
|
1008
|
+
to read it. Claude Code reads `AGENTS.md` when the project has no `CLAUDE.md` (Claude Code
|
|
1009
|
+
2.1.277 or later). One of those
|
|
729
1010
|
rules, `documentation-clarity.md`, sets the writing standard for pull requests,
|
|
730
1011
|
issues, code comments and Markdown: no project-local identifiers, no account of
|
|
731
1012
|
how the work went, cut to what a reader outside the team can follow.
|
|
@@ -747,8 +1028,8 @@ Each hook runs `node` directly, with no shell and no network, and prints one
|
|
|
747
1028
|
message from `.agents/rules/reminders.json`. A missing or unreadable message
|
|
748
1029
|
file prints nothing. `qfai init` refreshes that file wherever the project has
|
|
749
1030
|
not edited it, so a new release's wording reaches an existing project without
|
|
750
|
-
changing `.claude/settings.json`. Remove the entries
|
|
751
|
-
the rule still applies.
|
|
1031
|
+
changing `.claude/settings.json`. Remove the entries from that file and from
|
|
1032
|
+
`.codex/hooks.json` to turn the reminder off; the rule still applies.
|
|
752
1033
|
|
|
753
1034
|
Codex gets the same reminders from `.codex/hooks.json` once you trust the
|
|
754
1035
|
project's hooks with `/hooks`. Each is one command line that runs the same under
|
|
@@ -764,15 +1045,6 @@ kept, and the run names it. To update one by hand, run
|
|
|
764
1045
|
`npx qfai init --dir <scratch-dir>` in an unused scratch directory and compare
|
|
765
1046
|
its `.claude/settings.json` with your project's file, group by group.
|
|
766
1047
|
|
|
767
|
-
## Contributing (for QFAI maintainers)
|
|
768
|
-
|
|
769
|
-
This repository is a monorepo, and the distributable package is under `packages/qfai`.
|
|
770
|
-
The repository root `README.md` and `packages/qfai/README.md` are kept aligned by
|
|
771
|
-
`scripts/check-readme-alignment.mjs`, which CI runs as part of `pnpm ci:lint`: every line
|
|
772
|
-
outside a `readme-align:ignore-start` / `readme-align:ignore-end` HTML-comment block must be
|
|
773
|
-
identical in both files. When you change documentation, apply the edit to both READMEs, or
|
|
774
|
-
wrap the intentionally file-specific part in those markers.
|
|
775
|
-
|
|
776
1048
|
## License
|
|
777
1049
|
|
|
778
1050
|
MIT
|
|
@@ -4,6 +4,15 @@
|
|
|
4
4
|
routing:
|
|
5
5
|
# The triage steps change no tracked file, so each has one author and no
|
|
6
6
|
# build or test phase.
|
|
7
|
+
- step: triage-owned-cleanup
|
|
8
|
+
phases:
|
|
9
|
+
- id: cleanup
|
|
10
|
+
mandatory_agents: [devops-ci-engineer]
|
|
11
|
+
conditional_agents: []
|
|
12
|
+
parallel_groups: []
|
|
13
|
+
rerun_policy: changed-scope-dependents
|
|
14
|
+
review_profile: default
|
|
15
|
+
|
|
7
16
|
- step: triage-close
|
|
8
17
|
phases:
|
|
9
18
|
- id: record
|