Initial commit of the L'Ami Fiduciaire SaaS platform built on Laravel 12, Vue 3, Inertia.js 2, and Tailwind CSS 4. Story 0.1 (rename folders to declarations in database) is implemented and code-reviewed: migration, rollback, and 6 Pest tests all passing. Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
11 KiB
name, description, nextStepFile, outputFile
| name | description | nextStepFile | outputFile |
|---|---|---|---|
| step-02-generate-pipeline | Generate CI pipeline configuration with adaptive orchestration (agent-team, subagent, or sequential) | ./step-03-configure-quality-gates.md | {test_artifacts}/ci-pipeline-progress.md |
Step 2: Generate CI Pipeline
STEP GOAL
Create platform-specific CI configuration with test execution, sharding, burn-in, and artifacts.
MANDATORY EXECUTION RULES
- 📖 Read the entire step file before acting
- ✅ Speak in
{communication_language} - ✅ Resolve execution mode from explicit user request first, then config
- ✅ Apply fallback rules deterministically when requested mode is unsupported
EXECUTION PROTOCOLS:
- 🎯 Follow the MANDATORY SEQUENCE exactly
- 💾 Record outputs before proceeding
- 📖 Load the next step only when instructed
CONTEXT BOUNDARIES:
- Available context: config, loaded artifacts, and knowledge fragments
- Focus: this step's goal only
- Limits: do not execute future steps
- Dependencies: prior steps' outputs (if any)
MANDATORY SEQUENCE
CRITICAL: Follow this sequence exactly. Do not skip, reorder, or improvise.
0. Resolve Execution Mode (User Override First)
const orchestrationContext = {
config: {
execution_mode: config.tea_execution_mode || 'auto', // "auto" | "subagent" | "agent-team" | "sequential"
capability_probe: config.tea_capability_probe !== false, // true by default
},
timestamp: new Date().toISOString().replace(/[:.]/g, '-'),
};
const normalizeUserExecutionMode = (mode) => {
if (typeof mode !== 'string') return null;
const normalized = mode.trim().toLowerCase().replace(/[-_]/g, ' ').replace(/\s+/g, ' ');
if (normalized === 'auto') return 'auto';
if (normalized === 'sequential') return 'sequential';
if (normalized === 'subagent' || normalized === 'sub agent' || normalized === 'subagents' || normalized === 'sub agents') {
return 'subagent';
}
if (normalized === 'agent team' || normalized === 'agent teams' || normalized === 'agentteam') {
return 'agent-team';
}
return null;
};
const normalizeConfigExecutionMode = (mode) => {
if (mode === 'subagent') return 'subagent';
if (mode === 'auto' || mode === 'sequential' || mode === 'subagent' || mode === 'agent-team') {
return mode;
}
return null;
};
// Explicit user instruction in the active run takes priority over config.
const explicitModeFromUser = normalizeUserExecutionMode(runtime.getExplicitExecutionModeHint?.() || null);
const requestedMode = explicitModeFromUser || normalizeConfigExecutionMode(orchestrationContext.config.execution_mode) || 'auto';
const probeEnabled = orchestrationContext.config.capability_probe;
const supports = { subagent: false, agentTeam: false };
if (probeEnabled) {
supports.subagent = runtime.canLaunchSubagents?.() === true;
supports.agentTeam = runtime.canLaunchAgentTeams?.() === true;
}
let resolvedMode = requestedMode;
if (requestedMode === 'auto') {
if (supports.agentTeam) resolvedMode = 'agent-team';
else if (supports.subagent) resolvedMode = 'subagent';
else resolvedMode = 'sequential';
} else if (probeEnabled && requestedMode === 'agent-team' && !supports.agentTeam) {
resolvedMode = supports.subagent ? 'subagent' : 'sequential';
} else if (probeEnabled && requestedMode === 'subagent' && !supports.subagent) {
resolvedMode = 'sequential';
}
Resolution precedence:
- Explicit user request in this run (
agent team=>agent-team;subagent=>subagent;sequential;auto) tea_execution_modefrom config- Runtime capability fallback (when probing enabled)
1. Resolve Output Path and Select Template
Determine the pipeline output file path based on the detected ci_platform:
| CI Platform | Output Path | Template File |
|---|---|---|
github-actions |
{project-root}/.github/workflows/test.yml |
{installed_path}/github-actions-template.yaml |
gitlab-ci |
{project-root}/.gitlab-ci.yml |
{installed_path}/gitlab-ci-template.yaml |
jenkins |
{project-root}/Jenkinsfile |
{installed_path}/jenkins-pipeline-template.groovy |
azure-devops |
{project-root}/azure-pipelines.yml |
{installed_path}/azure-pipelines-template.yaml |
harness |
{project-root}/.harness/pipeline.yaml |
{installed_path}/harness-pipeline-template.yaml |
circle-ci |
{project-root}/.circleci/config.yml |
(no template; generate from first principles) |
Use templates from {installed_path} when available. Adapt the template to the project's test_stack_type and test_framework.
Security: Script Injection Prevention
CRITICAL: Treat
${{ inputs.* }}and the entire${{ github.event.* }}namespace as unsafe by default. ALWAYS route them throughenv:intermediaries and reference as double-quoted"$ENV_VAR"inrun:blocks. NEVER interpolate them directly.
When the generated pipeline is extended into reusable workflows (on: workflow_call), manual dispatch (on: workflow_dispatch), or composite actions, these values become user-controllable and can inject arbitrary shell commands.
Two rules for generated run: blocks:
- No direct interpolation — pass unsafe contexts through
env:, reference as"$ENV_VAR" - Inputs must be DATA, not COMMANDS — never accept command-shaped inputs (e.g.,
inputs.install-command) that get executed as shell code. Even throughenv:, running$CMDwhere CMD comes from an input is still command injection. Use fixed commands and pass inputs only as arguments.
# ✅ SAFE — input is DATA interpolated into a fixed command
- name: Run tests
env:
TEST_GREP: ${{ inputs.test-grep }}
run: |
# Security: inputs passed through env: to prevent script injection
npx playwright test --grep "$TEST_GREP"
# ❌ NEVER — direct GitHub expression injection
- name: Run tests
run: |
npx playwright test --grep "${{ inputs.test-grep }}"
# ❌ NEVER — executing input-derived env var as a command
- name: Install
env:
CMD: ${{ inputs.install-command }}
run: $CMD
Include a # Security: inputs passed through env: to prevent script injection comment in generated YAML wherever this pattern is applied.
Safe contexts (do NOT need env: intermediaries): ${{ steps.*.outputs.* }}, ${{ matrix.* }}, ${{ runner.os }}, ${{ github.sha }}, ${{ github.ref }}, ${{ secrets.* }}, ${{ env.* }}.
2. Pipeline Stages
Include stages:
- lint
- test (parallel shards)
- contract-test (if
tea_use_pactjs_utilsenabled) - burn-in (flaky detection)
- report (aggregate + publish)
3. Test Execution
- Parallel sharding enabled
- CI retries configured
- Capture artifacts (HTML report, JUnit XML, traces/videos on failure)
- Cache dependencies (language-appropriate: node_modules, .venv, .m2, go module cache, NuGet, bundler)
Write the selected pipeline configuration to the resolved output path from step 1. Adjust test commands based on test_stack_type and test_framework:
- Frontend/Fullstack: Include browser install, E2E/component test commands, Playwright/Cypress artifacts
- Backend (Node.js): Use
npm testor framework-specific commands (vitest,jest), skip browser install - Backend (Python): Use
pytestwith coverage (pytest --cov), install viapip install -r requirements.txtorpoetry install - Backend (Java/Kotlin): Use
mvn testorgradle test, cache.m2/repositoryor.gradle/caches - Backend (Go): Use
go test ./...with coverage (-coverprofile), cache Go modules - Backend (C#/.NET): Use
dotnet testwith coverage, restore NuGet packages - Backend (Ruby): Use
bundle exec rspecwith coverage, cachevendor/bundle
Contract Testing Pipeline (if tea_use_pactjs_utils enabled)
When tea_use_pactjs_utils is enabled, add a contract-test stage after test:
Required env block (add to the generated pipeline):
env:
PACT_BROKER_BASE_URL: ${{ secrets.PACT_BROKER_BASE_URL }}
PACT_BROKER_TOKEN: ${{ secrets.PACT_BROKER_TOKEN }}
GITHUB_SHA: ${{ github.sha }} # auto-set by GitHub Actions
GITHUB_BRANCH: ${{ github.head_ref || github.ref_name }} # NOT auto-set — must be defined explicitly
Note:
GITHUB_SHAis auto-set by GitHub Actions, butGITHUB_BRANCHis not — it must be derived fromgithub.head_ref(for PRs) orgithub.ref_name(for pushes). The pactjs-utils library reads both fromprocess.env.
-
Consumer test + publish: Run consumer contract tests, then publish pacts to broker
npm run test:pact:consumernpm run publish:pact- Only publish on PR and main branch pushes
-
Provider verification: Run provider verification against published pacts
npm run test:pact:provider:remote:contractbuildVerifierOptionsauto-readsPACT_BROKER_BASE_URL,PACT_BROKER_TOKEN,GITHUB_SHA,GITHUB_BRANCH- Verification results published to broker when
CI=true
-
Can-I-Deploy gate: Block deployment if contracts are incompatible
npm run can:i:deploy:provider- Ensure the script adds
--retry-while-unknown 6 --retry-interval 10for async verification
-
Webhook job: Add
repository_dispatchtrigger forpact_changedevent- Provider verification runs when consumers publish new pacts
- Ensures compatibility is checked on both consumer and provider changes
-
Breaking change handling: When
PACT_BREAKING_CHANGE=trueenv var is set:- Provider test passes
includeMainAndDeployed: falsetobuildVerifierOptions— verifies only matching branch - Coordinate with consumer team before removing the flag
- Provider test passes
-
Record deployment: After successful deployment, record version in broker
npm run record:provider:deployment --env=production
Required CI secrets: PACT_BROKER_BASE_URL, PACT_BROKER_TOKEN
If tea_pact_mcp is "mcp": Reference the SmartBear MCP Can I Deploy and Matrix tools for pipeline guidance in pact-mcp.md.
4. Save Progress
Save this step's accumulated work to {outputFile}.
-
If
{outputFile}does not exist (first save), create it with YAML frontmatter:--- stepsCompleted: ['step-02-generate-pipeline'] lastStep: 'step-02-generate-pipeline' lastSaved: '{date}' ---Then write this step's output below the frontmatter.
-
If
{outputFile}already exists, update:- Add
'step-02-generate-pipeline'tostepsCompletedarray (only if not already present) - Set
lastStep: 'step-02-generate-pipeline' - Set
lastSaved: '{date}' - Append this step's output to the appropriate section of the document.
- Add
5. Orchestration Notes for This Step
For this step, treat these work units as parallelizable when resolvedMode is agent-team or subagent:
- Worker A: resolve platform path/template and produce base pipeline skeleton (section 1)
- Worker B: construct stage definitions and test execution blocks (sections 2-3)
- Worker C: contract-testing block (only when
tea_use_pactjs_utilsis true)
If resolvedMode is sequential, execute sections 1→4 in order.
Load next step: {nextStepFile}
🚨 SYSTEM SUCCESS/FAILURE METRICS:
✅ SUCCESS:
- Step completed in full with required outputs
❌ SYSTEM FAILURE:
- Skipped sequence steps or missing outputs Master Rule: Skipping steps is FORBIDDEN.