azcodr 2.4.0 → 2.6.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/.agents/hooks.json +18 -3
- package/.agents/hooks.json.example +18 -3
- package/.agents/lib/agent-guard-command.js +103 -0
- package/.agents/lib/agent-guard-file.js +77 -0
- package/.agents/lib/agent-guard-tdd.js +77 -0
- package/.agents/lib/agent-guard.js +80 -0
- package/.agents/lib/boundaries.js +158 -0
- package/.agents/scripts/agent_guard.js +35 -3
- package/.agents/scripts/boundary_guard.js +93 -0
- package/.agents/skills/clean-code-refactor/SKILL.md +1 -0
- package/.agents/skills/lets-build/SKILL.md +3 -2
- package/.agents/skills/lets-build/scripts/bootstrap_workspace.sh +166 -0
- package/.agents/skills/relentless-questioner/SKILL.md +1 -1
- package/AGENTS.md +3 -3
- package/CONTRIBUTING.md +10 -4
- package/README.md +14 -12
- package/docs/generated-enforcement-analysis.md +162 -0
- package/docs/rules/clean_code.md +3 -2
- package/docs/rules/test_driven_development.md +8 -5
- package/lib/index.d.ts +1 -1
- package/lib/index.js +1 -1
- package/lib/scaffold.d.ts.map +1 -1
- package/lib/scaffold.js +4 -1
- package/lib/scaffold.js.map +1 -1
- package/lib/starter-ci.d.ts +29 -0
- package/lib/starter-ci.d.ts.map +1 -0
- package/lib/starter-ci.js +59 -0
- package/lib/starter-ci.js.map +1 -0
- package/memory.md +24 -0
- package/package.json +3 -3
- package/scripts/validate/toolchain.js +60 -0
- package/scripts/validate.js +12 -2
- package/src/index.ts +1 -1
- package/src/scaffold.ts +4 -1
- package/src/starter-ci.ts +61 -0
|
@@ -0,0 +1,93 @@
|
|
|
1
|
+
#!/usr/bin/env node
|
|
2
|
+
|
|
3
|
+
/**
|
|
4
|
+
* Cross-platform architectural boundary & cycle guard.
|
|
5
|
+
*
|
|
6
|
+
* Ships inside scaffolded projects so structural drift (circular imports and
|
|
7
|
+
* Clean/Hexagonal layer breaches) is machine-checked with zero third-party
|
|
8
|
+
* dependencies. The engine is vendored under `.agents/lib/` and byte-locked to
|
|
9
|
+
* `lib/boundaries.js`; this wrapper only resolves it and reports the verdict.
|
|
10
|
+
*/
|
|
11
|
+
import fs from 'node:fs';
|
|
12
|
+
import path from 'node:path';
|
|
13
|
+
import process from 'node:process';
|
|
14
|
+
import { fileURLToPath, pathToFileURL } from 'node:url';
|
|
15
|
+
|
|
16
|
+
const selfDir = path.dirname(fileURLToPath(import.meta.url));
|
|
17
|
+
|
|
18
|
+
// Resolution order (first existing file wins):
|
|
19
|
+
// 1. AZCODR_BOUNDARY_ENGINE override (tests, embedders).
|
|
20
|
+
// 2. ../lib/boundaries.js — vendored engine inside `.agents/`
|
|
21
|
+
// (present in scaffolded projects; `.agents` is copied recursively).
|
|
22
|
+
// 3. ../../lib/boundaries.js — azcodr repo dev layout (fallback only).
|
|
23
|
+
const engineCandidates = [
|
|
24
|
+
process.env.AZCODR_BOUNDARY_ENGINE,
|
|
25
|
+
path.resolve(selfDir, '../lib/boundaries.js'),
|
|
26
|
+
path.resolve(selfDir, '../../lib/boundaries.js')
|
|
27
|
+
].filter(Boolean);
|
|
28
|
+
|
|
29
|
+
async function getEngine() {
|
|
30
|
+
const tried = [];
|
|
31
|
+
for (const candidate of engineCandidates) {
|
|
32
|
+
if (!fs.existsSync(candidate)) {
|
|
33
|
+
tried.push(candidate);
|
|
34
|
+
continue;
|
|
35
|
+
}
|
|
36
|
+
try {
|
|
37
|
+
return await import(pathToFileURL(candidate).href);
|
|
38
|
+
} catch (err) {
|
|
39
|
+
tried.push(`${candidate} (unreadable: ${err.message})`);
|
|
40
|
+
}
|
|
41
|
+
}
|
|
42
|
+
// Fail CLOSED: a guard with no engine is a broken install, never a silent pass.
|
|
43
|
+
console.error(
|
|
44
|
+
'🚨 Boundary Guard misconfigured: engine module not found, refusing to fail open. Tried:\n' +
|
|
45
|
+
tried.map((t) => ` - ${t}`).join('\n')
|
|
46
|
+
);
|
|
47
|
+
process.exit(2);
|
|
48
|
+
}
|
|
49
|
+
|
|
50
|
+
function resolveTarget(positional) {
|
|
51
|
+
const explicit = positional[0];
|
|
52
|
+
if (explicit) return path.resolve(explicit);
|
|
53
|
+
const srcDir = path.resolve(process.cwd(), 'src');
|
|
54
|
+
return fs.existsSync(srcDir) ? srcDir : process.cwd();
|
|
55
|
+
}
|
|
56
|
+
|
|
57
|
+
function rel(p) {
|
|
58
|
+
return path.relative(process.cwd(), p) || '.';
|
|
59
|
+
}
|
|
60
|
+
|
|
61
|
+
function printReport(report) {
|
|
62
|
+
console.log('🔍 Inspecting Architectural Boundaries in: ' + rel(report.targetDir));
|
|
63
|
+
console.log('--------------------------------------------------------------');
|
|
64
|
+
if (report.ok) {
|
|
65
|
+
console.log(`✅ No cycles or boundary violations across ${report.moduleCount} module(s).`);
|
|
66
|
+
return;
|
|
67
|
+
}
|
|
68
|
+
for (const cycle of report.cycles) {
|
|
69
|
+
console.error(' - Circular Dependency: ' + cycle.map(rel).join(' -> '));
|
|
70
|
+
}
|
|
71
|
+
for (const v of report.violations) {
|
|
72
|
+
console.error(` - Layer Boundary Breach: ${rel(v.file)} imports ${rel(v.importedFile)} (${v.fromLayer} -> ${v.toLayer})`);
|
|
73
|
+
}
|
|
74
|
+
}
|
|
75
|
+
|
|
76
|
+
function emit(report, silent) {
|
|
77
|
+
if (!silent) printReport(report);
|
|
78
|
+
}
|
|
79
|
+
|
|
80
|
+
async function main() {
|
|
81
|
+
const args = process.argv.slice(2).filter((a) => a !== '--silent');
|
|
82
|
+
const silent = process.argv.includes('--silent');
|
|
83
|
+
const { inspectBoundaries } = await getEngine();
|
|
84
|
+
const target = resolveTarget(args);
|
|
85
|
+
const report = inspectBoundaries(target);
|
|
86
|
+
emit({ ...report, targetDir: target }, silent);
|
|
87
|
+
process.exit(report.ok ? 0 : 1);
|
|
88
|
+
}
|
|
89
|
+
|
|
90
|
+
main().catch((err) => {
|
|
91
|
+
console.error(`🚨 Boundary Guard crashed: ${err?.message || err}`);
|
|
92
|
+
process.exit(2);
|
|
93
|
+
});
|
|
@@ -51,6 +51,7 @@ Target concrete flaws:
|
|
|
51
51
|
### Step 5: Verify Continuous Green State
|
|
52
52
|
- Run tests after every single atomic change. Use the workspace's own command — do not assume one exists. Verify with the package manifest first (`node -p "JSON.stringify(require('./package.json').scripts)"`); for this template that is `npm test`, with `npm run test:coverage` for the coverage gate.
|
|
53
53
|
- Ensure coverage remains at **100.00%**.
|
|
54
|
+
- Verify architectural boundaries: Run `npx azcodr boundaries` to guarantee the refactoring introduced 0 circular dependencies and 0 layer boundary breaches.
|
|
54
55
|
|
|
55
56
|
---
|
|
56
57
|
|
|
@@ -100,7 +100,7 @@ Upon user confirmation:
|
|
|
100
100
|
- *Extension:* `manifest.json`, `src/background/index.ts`, `src/content/index.ts`, `src/popup/index.html`.
|
|
101
101
|
- *Game / Engine:* `src/core/`, `src/ecs/`, asset manifest, frame loop entrypoint.
|
|
102
102
|
- *CLI:* `src/cmd/`, `src/core/`, CLI entrypoint with exit code handling.
|
|
103
|
-
3. Generate build manifests (`Cargo.toml`, `package.json`, `go.mod`, `pyproject.toml`),
|
|
103
|
+
3. Generate build manifests (`Cargo.toml`, `package.json`, `go.mod`, `pyproject.toml`) for the recorded language, install the pinned linter from the emitted gate configuration (`eslint.config.js`, `ruff.toml`, `clippy.toml`, `.golangci.yml`, `checkstyle.xml`, `.editorconfig` CA block, `.clang-tidy` — written deterministically by `bootstrap_workspace.sh`, never invented). Node profiles arrive with `package.json` lint already rewired to `eslint .`; other profiles need the lint entry wired by hand. Prove the gate in Phase 5, and keep the boundary smoke test (`scripts/smoke_test.sh`).
|
|
104
104
|
4. **Replace Starter README with Project-Specific README**:
|
|
105
105
|
Generate a clean, project-specific `README.md` using [references/project_readme_template.md](./references/project_readme_template.md), completely replacing meta-template content with the project's actual name, mission, stack highlights, quickstart commands, and directory tree.
|
|
106
106
|
|
|
@@ -114,6 +114,7 @@ Upon user confirmation:
|
|
|
114
114
|
2. Execute toolchain dependency checks, build commands, and health/smoke tests:
|
|
115
115
|
- Compile code and verify zero compiler or lint errors.
|
|
116
116
|
- Verify boundary verification smoke test (`scripts/smoke_test.sh`).
|
|
117
|
+
- **Prove enforcement is live:** enable the shipped hooks in `.agents/hooks.json` (`safety-guard`, `architectural-guard`), then deliberately attempt a blocked action (e.g. append lines to a file already over budget, or a denied command) and confirm the hook rejects it before re-disabling nothing — hooks stay enabled. A guard that has never blocked anything is a rumor, not a control.
|
|
117
118
|
3. **Mandatory Handover to Domain Analysis (STOP & PIVOT):**
|
|
118
119
|
- **`lets-build` IS NOW COMPLETE.** Do NOT proceed to write domain business entities, repositories, or application features.
|
|
119
120
|
- Present the bootstrapped technical skeleton to the user.
|
|
@@ -160,7 +161,7 @@ Upon user confirmation:
|
|
|
160
161
|
|
|
161
162
|
## 4. Quality & Verification
|
|
162
163
|
- **Testing Strategy:** Outside-In TDD with Nano-Cycles (Uncle Bob's 3 Laws)
|
|
163
|
-
- **Code Health Gates:** 100
|
|
164
|
+
- **Code Health Gates:** 100% coverage on all metrics + mutation kill gate on guards, zero lint errors
|
|
164
165
|
- **DevSecOps:** <Semgrep / Trivy / Gitleaks / None>
|
|
165
166
|
```
|
|
166
167
|
|
|
@@ -324,6 +324,165 @@ EOF
|
|
|
324
324
|
;;
|
|
325
325
|
esac
|
|
326
326
|
|
|
327
|
+
# ------------------------------------------------------------------------------
|
|
328
|
+
# DETERMINISTIC TOOLCHAIN FILES. Directories alone enforce nothing: until this
|
|
329
|
+
# section existed, every language produced zero gate configurations and the
|
|
330
|
+
# starter `lint` script was an echo placeholder, so all enforcement was
|
|
331
|
+
# agent-authored. Each profile below emits its pinned gate configuration with
|
|
332
|
+
# values mirroring docs/rules/clean_code.md (300/30/10/3); the agent installs
|
|
333
|
+
# the named tool and proves the gate in Phase 5. Files are created only when
|
|
334
|
+
# absent, so re-runs never clobber agent-authored configs. Build manifests
|
|
335
|
+
# (Cargo.toml, go.mod, csproj, ...) stay with the agent: they carry project
|
|
336
|
+
# naming and version decisions no script may invent.
|
|
337
|
+
# ------------------------------------------------------------------------------
|
|
338
|
+
write_unless_exists() {
|
|
339
|
+
local target="$1"
|
|
340
|
+
if [[ -f "${target}" ]]; then
|
|
341
|
+
echo " keeping existing ${target}"
|
|
342
|
+
return
|
|
343
|
+
fi
|
|
344
|
+
mkdir -p "$(dirname "${target}")"
|
|
345
|
+
cat > "${target}"
|
|
346
|
+
}
|
|
347
|
+
|
|
348
|
+
append_unless_present() {
|
|
349
|
+
local target="$1"
|
|
350
|
+
local marker="$2"
|
|
351
|
+
if [[ -f "${target}" ]] && grep -qF "${marker}" "${target}"; then
|
|
352
|
+
echo " keeping existing ${target} gates"
|
|
353
|
+
return
|
|
354
|
+
fi
|
|
355
|
+
cat >> "${target}"
|
|
356
|
+
}
|
|
357
|
+
|
|
358
|
+
echo "6. Emitting deterministic toolchain configs for '${LANGUAGE}'..."
|
|
359
|
+
case "${LANGUAGE}" in
|
|
360
|
+
typescript|javascript|deno|bun)
|
|
361
|
+
write_unless_exists "${WORKSPACE_ROOT}/eslint.config.js" << 'EOF'
|
|
362
|
+
// Deterministic fitness functions (azcodr clean_code.md section 5).
|
|
363
|
+
// Install the pinned tool, then prove the gate: npm run lint
|
|
364
|
+
export default [
|
|
365
|
+
{
|
|
366
|
+
files: ['src/**/*.{js,ts}', 'tests/**/*.{js,ts}'],
|
|
367
|
+
rules: {
|
|
368
|
+
'max-lines': ['error', 300],
|
|
369
|
+
'max-lines-per-function': ['error', 30],
|
|
370
|
+
complexity: ['error', 10],
|
|
371
|
+
'max-params': ['error', 3]
|
|
372
|
+
}
|
|
373
|
+
}
|
|
374
|
+
];
|
|
375
|
+
EOF
|
|
376
|
+
;;
|
|
377
|
+
python)
|
|
378
|
+
write_unless_exists "${WORKSPACE_ROOT}/ruff.toml" << 'EOF'
|
|
379
|
+
# Deterministic fitness functions (azcodr clean_code.md section 5).
|
|
380
|
+
# Install the pinned tool, then prove the gate: ruff check .
|
|
381
|
+
[lint]
|
|
382
|
+
select = ["E", "F", "C901", "PLR0912", "PLR0913", "PLR0915"]
|
|
383
|
+
[lint.mccabe]
|
|
384
|
+
max-complexity = 10
|
|
385
|
+
[lint.pylint]
|
|
386
|
+
max-args = 3
|
|
387
|
+
max-statements = 30
|
|
388
|
+
# NOTE: ruff has no file-length rule; the 300-line file cap is enforced by
|
|
389
|
+
# the project's lint entry (see lets-build Phase 5 proof).
|
|
390
|
+
EOF
|
|
391
|
+
;;
|
|
392
|
+
rust)
|
|
393
|
+
write_unless_exists "${WORKSPACE_ROOT}/clippy.toml" << 'EOF'
|
|
394
|
+
# Deterministic fitness functions (azcodr clean_code.md section 5).
|
|
395
|
+
# Enforce with: cargo clippy -- -D clippy::too_many_lines -D clippy::cognitive_complexity -D clippy::too_many_arguments
|
|
396
|
+
too-many-lines-threshold = 30
|
|
397
|
+
cognitive-complexity-threshold = 10
|
|
398
|
+
too-many-arguments-threshold = 3
|
|
399
|
+
# NOTE: clippy has no file-length lint; the 300-line file cap is enforced by
|
|
400
|
+
# the project's lint entry (see lets-build Phase 5 proof).
|
|
401
|
+
EOF
|
|
402
|
+
;;
|
|
403
|
+
go)
|
|
404
|
+
write_unless_exists "${WORKSPACE_ROOT}/.golangci.yml" << 'EOF'
|
|
405
|
+
# Deterministic fitness functions (azcodr clean_code.md section 5).
|
|
406
|
+
# Install the pinned tool, then prove the gate: golangci-lint run ./...
|
|
407
|
+
linters:
|
|
408
|
+
enable: [funlen, gocyclo]
|
|
409
|
+
linters-settings:
|
|
410
|
+
funlen:
|
|
411
|
+
lines: 30
|
|
412
|
+
statements: 25
|
|
413
|
+
gocyclo:
|
|
414
|
+
min-complexity: 10
|
|
415
|
+
# NOTE: no golangci-native file-length check; the 300-line file cap is
|
|
416
|
+
# enforced by the project's lint entry (see lets-build Phase 5 proof).
|
|
417
|
+
EOF
|
|
418
|
+
;;
|
|
419
|
+
java)
|
|
420
|
+
write_unless_exists "${WORKSPACE_ROOT}/checkstyle.xml" << 'EOF'
|
|
421
|
+
<?xml version="1.0"?>
|
|
422
|
+
<!-- Deterministic fitness functions (azcodr clean_code.md section 5). -->
|
|
423
|
+
<!DOCTYPE module PUBLIC "-//Checkstyle//DTD Checkstyle Configuration 1.3//EN" "https://checkstyle.org/dtds/configuration_1_3.dtd">
|
|
424
|
+
<module name="Checker">
|
|
425
|
+
<module name="FileLength">
|
|
426
|
+
<property name="max" value="300"/>
|
|
427
|
+
</module>
|
|
428
|
+
<module name="TreeWalker">
|
|
429
|
+
<module name="MethodLength">
|
|
430
|
+
<property name="max" value="30"/>
|
|
431
|
+
</module>
|
|
432
|
+
<module name="CyclomaticComplexity">
|
|
433
|
+
<property name="max" value="10"/>
|
|
434
|
+
</module>
|
|
435
|
+
<module name="ParameterNumber">
|
|
436
|
+
<property name="max" value="3"/>
|
|
437
|
+
</module>
|
|
438
|
+
</module>
|
|
439
|
+
</module>
|
|
440
|
+
EOF
|
|
441
|
+
;;
|
|
442
|
+
csharp)
|
|
443
|
+
append_unless_present "${WORKSPACE_ROOT}/.editorconfig" "azcodr fitness functions" << 'EOF'
|
|
444
|
+
|
|
445
|
+
# --- azcodr fitness functions (CA gates; exact numbers in lint entry) ---
|
|
446
|
+
[*.cs]
|
|
447
|
+
dotnet_diagnostic.CA1501.severity = error
|
|
448
|
+
dotnet_diagnostic.CA1502.severity = error
|
|
449
|
+
EOF
|
|
450
|
+
;;
|
|
451
|
+
cpp|c)
|
|
452
|
+
write_unless_exists "${WORKSPACE_ROOT}/.clang-tidy" << 'EOF'
|
|
453
|
+
# Deterministic fitness functions (azcodr clean_code.md section 5).
|
|
454
|
+
Checks: 'readability-function-size,readability-function-cognitive-complexity'
|
|
455
|
+
CheckOptions:
|
|
456
|
+
- { key: readability-function-size.LineThreshold, value: 30 }
|
|
457
|
+
- { key: readability-function-size.ParameterThreshold, value: 3 }
|
|
458
|
+
- { key: readability-function-cognitive-complexity.Threshold, value: 10 }
|
|
459
|
+
# NOTE: clang-tidy has no file-length check; the 300-line file cap is
|
|
460
|
+
# enforced by the project's lint entry (see lets-build Phase 5 proof).
|
|
461
|
+
EOF
|
|
462
|
+
;;
|
|
463
|
+
generic)
|
|
464
|
+
echo " language undecided: no toolchain configs emitted (re-run with a language profile)"
|
|
465
|
+
;;
|
|
466
|
+
esac
|
|
467
|
+
|
|
468
|
+
# For Node profiles the starter package.json ships a lint placeholder that
|
|
469
|
+
# always succeeds. Point it at the emitted config so `npm run lint` fails
|
|
470
|
+
# until the pinned eslint is installed (fail-closed) instead of echoing.
|
|
471
|
+
# Only the placeholder is ever replaced; agent-wired entries are sacred.
|
|
472
|
+
case "${LANGUAGE}" in
|
|
473
|
+
typescript|javascript|deno|bun)
|
|
474
|
+
STARTER_PKG="${WORKSPACE_ROOT}/package.json"
|
|
475
|
+
if [[ -f "${STARTER_PKG}" ]] && grep -q 'No linter configured yet' "${STARTER_PKG}"; then
|
|
476
|
+
if command -v node >/dev/null 2>&1; then
|
|
477
|
+
node -e 'const fs=require("fs");const p=process.argv[1];const j=JSON.parse(fs.readFileSync(p,"utf8"));j.scripts=j.scripts||{};j.scripts.lint="eslint .";fs.writeFileSync(p,JSON.stringify(j,null,2)+"\n");' "${STARTER_PKG}"
|
|
478
|
+
echo " wired package.json lint -> eslint ."
|
|
479
|
+
else
|
|
480
|
+
echo " node not found: leaving starter lint placeholder (agent wires it in Phase 4)"
|
|
481
|
+
fi
|
|
482
|
+
fi
|
|
483
|
+
;;
|
|
484
|
+
esac
|
|
485
|
+
|
|
327
486
|
# ------------------------------------------------------------------------------
|
|
328
487
|
# memory.md is an APPEND-ONLY LEDGER. It is never rewritten automatically.
|
|
329
488
|
#
|
|
@@ -408,7 +567,14 @@ if [[ ! -f "${SMOKE_TEST}" ]]; then
|
|
|
408
567
|
# ==============================================================================
|
|
409
568
|
set -euo pipefail
|
|
410
569
|
|
|
570
|
+
ROOT="$(cd "$(dirname "${BASH_SOURCE[0]}")/.." && pwd)"
|
|
571
|
+
|
|
411
572
|
echo "Running boundary smoke verification..."
|
|
573
|
+
if [[ -f "${ROOT}/.agents/scripts/boundary_guard.js" ]] && command -v node >/dev/null 2>&1; then
|
|
574
|
+
node "${ROOT}/.agents/scripts/boundary_guard.js" "${ROOT}/src"
|
|
575
|
+
else
|
|
576
|
+
echo "⚠️ Boundary guard skipped (node or guard script unavailable)."
|
|
577
|
+
fi
|
|
412
578
|
# Extend with project-specific runtime health checks (e.g. ping health endpoint, CLI --help)
|
|
413
579
|
echo "✅ Boundary smoke verification passed!"
|
|
414
580
|
EOF
|
|
@@ -119,7 +119,7 @@ Synthesize the answers into an unambiguous **Feature Alignment Specification (FA
|
|
|
119
119
|
When [Action]
|
|
120
120
|
Then [Observable Outcome]
|
|
121
121
|
```
|
|
122
|
-
- **Test Strategy:** [Contract / Integration / Unit tests required
|
|
122
|
+
- **Test Strategy:** [Contract / Integration / Unit tests required; 100% on all metrics, assertion-free tests rejected]
|
|
123
123
|
```
|
|
124
124
|
|
|
125
125
|
---
|
package/AGENTS.md
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
# AGENTS.md
|
|
2
2
|
|
|
3
|
-
> **azcodr:
|
|
3
|
+
> **azcodr: Architecture governance toolkit, with an optional starter**
|
|
4
4
|
> **Workspace Mission:** Problem-first, topology-aligned production architectures governed by strict systemic atomicity, 100% open-source standards, true incremental TDD nano-cycles, and zero speculative bloat.
|
|
5
5
|
> **Runtime & Tools:** Node.js (`>=22.8.0`), npm (`>=10.0.0`) | `npm test` (test runner), `npm run test:coverage` (coverage gate), `npm run lint`, `npm run validate`.
|
|
6
6
|
> **Node floor rationale:** `>=22.8.0` satisfies Jest native ESM requirements (`--experimental-vm-modules`) and modern LTS security baselines. Node 18 (EOL 2025-04-30) and 20 (EOL 2026-04-30) no longer receive security patches.
|
|
@@ -48,7 +48,7 @@ Progress all tasks systematically through the unified **Agent Cognitive & Agile
|
|
|
48
48
|
2. INTERROGATE / DOMAIN ──► Relentless questioning; Ubiquitous Language, Aggregate invariants & state machines.
|
|
49
49
|
3. PLAN / OUTER TDD ──► Minimal blast radius; failing Outer Acceptance Test (UI/API RED).
|
|
50
50
|
4. EXECUTE / INNER TDD ──► Incremental nano-cycles (Uncle Bob's 3 Laws: 1 micro-assertion RED ➔ MINIMAL pass GREEN ➔ REFACTOR).
|
|
51
|
-
5. VERIFY / DoD & PROOF ──► Outer test turns GREEN; boundary smoke tests & 100
|
|
51
|
+
5. VERIFY / DoD & PROOF ──► Outer test turns GREEN; boundary smoke tests & 100% coverage on all metrics + mutation gate.
|
|
52
52
|
```
|
|
53
53
|
---
|
|
54
54
|
|
|
@@ -58,7 +58,7 @@ To prevent context bloat and keep prompt overhead minimal, detailed engineering
|
|
|
58
58
|
|
|
59
59
|
| Domain | Rule Reference File | When to Consult |
|
|
60
60
|
|---|---|---|
|
|
61
|
-
| **TDD & Isolation** | [docs/rules/test_driven_development.md](./docs/rules/test_driven_development.md) | Outside-In TDD, Uncle Bob's 3 Laws, 100% coverage, test isolation & DB rollback. |
|
|
61
|
+
| **TDD & Isolation** | [docs/rules/test_driven_development.md](./docs/rules/test_driven_development.md) | Outside-In TDD, Uncle Bob's 3 Laws, 100% coverage on all metrics + mutation gate, test isolation & DB rollback. |
|
|
62
62
|
| **Clean Code** | [docs/rules/clean_code.md](./docs/rules/clean_code.md) | Naming, small functions, CQS, SLAP, DRY, DbC, zero side-effects. |
|
|
63
63
|
| **Design Patterns** | [docs/rules/design_patterns.md](./docs/rules/design_patterns.md) | Adapter, Factory, Strategy, Result `<T, E>`, and GoF pattern catalog. |
|
|
64
64
|
| **Type Safety** | [docs/rules/type_safety.md](./docs/rules/type_safety.md) | Compiler strictness, branded nominal types, type discriminators across polyglot languages. |
|
package/CONTRIBUTING.md
CHANGED
|
@@ -49,15 +49,21 @@ Before submitting any code changes, all 5 quality gates must pass with zero erro
|
|
|
49
49
|
npm test
|
|
50
50
|
npm run test:coverage
|
|
51
51
|
```
|
|
52
|
-
*Coverage gates enforced:*
|
|
52
|
+
*Coverage gates enforced (CI fails below 100% on any metric):*
|
|
53
53
|
- **100% lines coverage**
|
|
54
|
-
- **
|
|
55
|
-
- **
|
|
54
|
+
- **100% functions coverage**
|
|
55
|
+
- **100% branches coverage**
|
|
56
|
+
- **100% statements coverage**
|
|
57
|
+
- Plus **100% mutant-kill on guards** (`npm run test:mutation`) and rejection of assertion-free tests.
|
|
56
58
|
5. **Agentic Architecture Validation:**
|
|
57
59
|
```bash
|
|
58
60
|
npm run validate
|
|
59
61
|
```
|
|
60
|
-
Validates root harness parity, progressive disclosure rules, skill formats, markdown links,
|
|
62
|
+
Validates root harness parity, progressive disclosure rules, skill formats, markdown links, ADR ledger consistency, and toolchain gate presence.
|
|
63
|
+
6. **Vendored Engine Sync:** after any change under `src/agent-guard*.ts` or `src/boundaries.ts` and `npm run build`, re-copy the compiled engine files into `.agents/lib/` (byte-equality is enforced by `tests/agent-guard.test.ts` and `tests/boundary-guard.test.ts`):
|
|
64
|
+
```bash
|
|
65
|
+
node -e "const fs=require('fs');for(const f of['agent-guard.js','agent-guard-command.js','agent-guard-file.js','agent-guard-tdd.js','boundaries.js'])fs.copyFileSync('lib/'+f,'.agents/lib/'+f)"
|
|
66
|
+
```
|
|
61
67
|
|
|
62
68
|
---
|
|
63
69
|
|
package/README.md
CHANGED
|
@@ -1,13 +1,15 @@
|
|
|
1
|
-
# azcodr:
|
|
1
|
+
# azcodr: Architecture governance toolkit, with an optional starter
|
|
2
2
|
|
|
3
3
|
[](https://www.npmjs.com/package/azcodr)
|
|
4
4
|
[](https://jsr.io/@azcodr/azcodr)
|
|
5
5
|
[](https://github.com/prosubodh/azcodr/actions/workflows/ci.yml)
|
|
6
|
-
[](https://github.com/prosubodh/azcodr)
|
|
6
|
+
[](https://github.com/prosubodh/azcodr/actions/workflows/ci.yml)
|
|
7
|
+
[](https://github.com/prosubodh/azcodr/blob/main/benchmark/RESULTS.md)
|
|
8
8
|
[](https://www.npmjs.com/package/azcodr)
|
|
9
9
|
[](./LICENSE)
|
|
10
10
|
|
|
11
|
+
> CI-enforced 100% gate (lines / branches / functions / statements) + 100% mutant kill on guards; the public report is the `coverage-report` artifact on every CI run.
|
|
12
|
+
|
|
11
13
|
> **Production-oriented architecture governance and topology-scoped scaffolding for AI-assisted development (early release).**
|
|
12
14
|
> *AI agents move fast. Architecture drifts. Azcodr turns architectural intent into executable constraints your agent cannot skip.*
|
|
13
15
|
|
|
@@ -34,7 +36,7 @@
|
|
|
34
36
|
|
|
35
37
|
## ⚡ 60-Second Demo: See Drift Prevention in Action
|
|
36
38
|
|
|
37
|
-
Azcodr turns architectural philosophy into machine-checked constraints
|
|
39
|
+
Azcodr turns architectural philosophy into machine-checked constraints. In a fresh scaffold the runtime hooks ship **enabled by default**, and the boundary engine runs in CI, so drift is caught both while the agent edits and after it commits.
|
|
38
40
|
|
|
39
41
|
### 1. Standalone Architectural Check
|
|
40
42
|
Run the validator on any repository without scaffolding:
|
|
@@ -63,7 +65,7 @@ When an AI coding agent attempts to dump new logic into a file already exceeding
|
|
|
63
65
|
```
|
|
64
66
|
|
|
65
67
|
### 3. Zero-Dependency Boundary & Cycle Enforcement
|
|
66
|
-
Inspect dependency cycles and layer boundaries on demand without third-party linters:
|
|
68
|
+
Inspect dependency cycles and layer boundaries on demand without third-party linters. The same engine is vendored into every scaffolded project (`.agents/scripts/boundary_guard.js`) and runs in the generated CI:
|
|
67
69
|
```bash
|
|
68
70
|
npx azcodr boundaries [directory]
|
|
69
71
|
```
|
|
@@ -76,17 +78,17 @@ npx azcodr boundaries [directory]
|
|
|
76
78
|
Action Required: Invert dependencies via Ports or extract shared modules.
|
|
77
79
|
```
|
|
78
80
|
|
|
79
|
-
### 4.
|
|
80
|
-
|
|
81
|
+
### 4. Detector Validation on Synthetic Fixtures (Not a Live-Agent Trial)
|
|
82
|
+
The evaluator's ability to detect the 3 trap classes is exercised against **hand-written fixtures**, not live agent output ([`benchmark/RESULTS.md`](https://github.com/prosubodh/azcodr/blob/main/benchmark/RESULTS.md)):
|
|
81
83
|
|
|
82
84
|
| Metric | Arm A (Control) | Arm B (Hooks Only) | Arm C (Full Azcodr) |
|
|
83
85
|
|---|:---:|:---:|:---:|
|
|
84
86
|
| **Files >300 Lines** | 1 (365 lines in `auth.ts`) | **0** (Modularized) | **0** (Modularized) |
|
|
85
87
|
| **Circular Dependency Cycles** | 1 (`billing <-> tenant`) | 1 (`billing <-> tenant`) | **0** (Decoupled Port) |
|
|
86
88
|
| **Layer Boundary Breaches** | 1 (`domain -> infra`) | 1 (`domain -> infra`) | **0** (Hexagonal Port) |
|
|
87
|
-
| **
|
|
89
|
+
| **Detected drift-free** | ❌ FAILED | ❌ FAILED | ✅ **0 detector violations** |
|
|
88
90
|
|
|
89
|
-
Run the
|
|
91
|
+
These fixtures are committed by hand to prove the detector fires; they are **not evidence** that an AI agent drifts. Real-agent results (tokens, completion, review minutes) are planned and not yet measured. Run the detector yourself:
|
|
90
92
|
```bash
|
|
91
93
|
node benchmark/run-benchmark.js
|
|
92
94
|
```
|
|
@@ -127,7 +129,7 @@ The architecture enforces 28 cohesive, single-responsibility domain rules. Read
|
|
|
127
129
|
|
|
128
130
|
| Domain | Rule Reference File | Key Focus & Invariants |
|
|
129
131
|
|---|---|---|
|
|
130
|
-
| **TDD & Isolation** | [`test_driven_development.md`](./docs/rules/test_driven_development.md) | Outside-In TDD, Uncle Bob's 3 Laws, 100% coverage, test isolation & DB rollback. |
|
|
132
|
+
| **TDD & Isolation** | [`test_driven_development.md`](./docs/rules/test_driven_development.md) | Outside-In TDD, Uncle Bob's 3 Laws, 100% coverage on all metrics + mutation gate, test isolation & DB rollback. |
|
|
131
133
|
| **Clean Code** | [`clean_code.md`](./docs/rules/clean_code.md) | Naming, small functions, CQS, SLAP, DRY, DbC, zero side-effects. |
|
|
132
134
|
| **Design Patterns** | [`design_patterns.md`](./docs/rules/design_patterns.md) | Adapter, Factory, Strategy, Result `<T, E>`, and GoF pattern catalog. |
|
|
133
135
|
| **Type Safety** | [`type_safety.md`](./docs/rules/type_safety.md) | Compiler strictness, branded nominal types, type discriminators across polyglot languages. |
|
|
@@ -171,10 +173,10 @@ The architecture enforces 28 cohesive, single-responsibility domain rules. Read
|
|
|
171
173
|
|
|
172
174
|
## 🚀 Starting a New Project with `/lets-build`
|
|
173
175
|
|
|
174
|
-
This repository serves as an **
|
|
176
|
+
This repository serves as an **architecture governance toolkit, with an optional starter**. When beginning a new software project:
|
|
175
177
|
|
|
176
178
|
### Step 1: Initialize Workspace with npx
|
|
177
|
-
Pull and scaffold the complete
|
|
179
|
+
Pull and scaffold the complete architecture governance toolkit into your project directory using `npx`:
|
|
178
180
|
```bash
|
|
179
181
|
npx azcodr my-new-project
|
|
180
182
|
cd my-new-project
|
|
@@ -0,0 +1,162 @@
|
|
|
1
|
+
# Generated-Project Enforcement Analysis: What a Scaffolded Project Actually Gets
|
|
2
|
+
|
|
3
|
+
> **Status:** evidence, not prose. Every claim below was produced by running the
|
|
4
|
+
> scaffolder on 2026-10-08, not by reading the skills docs.
|
|
5
|
+
> **Answers the plan's open question:** which linters does a non-TypeScript
|
|
6
|
+
> project actually get — and whether the "executable architecture" promise holds
|
|
7
|
+
> outside azcodr's own repo.
|
|
8
|
+
|
|
9
|
+
---
|
|
10
|
+
|
|
11
|
+
## Method
|
|
12
|
+
|
|
13
|
+
1. Ran `scaffold({ force: true, noGit: true })` from compiled `lib/` into a clean
|
|
14
|
+
temp dir; inventoried every emitted file.
|
|
15
|
+
2. Ran `bootstrap_workspace.sh . <topology> <language>` under Git Bash for
|
|
16
|
+
`backend+typescript`, `backend+python`, `cli+go`, `extension+typescript`,
|
|
17
|
+
`systems-library+c`; diffed the file lists.
|
|
18
|
+
3. Executed the scaffolded project's `.agents/scripts/agent_guard.js` with a
|
|
19
|
+
must-block payload (`rm -rf /`), with the azcodr repo itself as control.
|
|
20
|
+
|
|
21
|
+
## Finding 1: No deterministic linter in any generated project
|
|
22
|
+
|
|
23
|
+
The scaffolded project contains exactly one toolchain-adjacent file:
|
|
24
|
+
`.editorconfig`. Its `package.json` lint script is:
|
|
25
|
+
|
|
26
|
+
```json
|
|
27
|
+
"lint": "echo \"No linter configured yet. Run /lets-build to configure toolchain.\""
|
|
28
|
+
```
|
|
29
|
+
|
|
30
|
+
The polyglot fitness-function table (`docs/rules/clean_code.md`, § Polyglot
|
|
31
|
+
Fitness Function Standards: ESLint / ruff / clippy / golangci-lint /
|
|
32
|
+
Checkstyle / Roslyn) ships as **documentation only**. Phase 4 step 3 of
|
|
33
|
+
`lets-build/SKILL.md` instructs the *agent* to "generate … deterministic
|
|
34
|
+
linter configurations" — i.e. enforcement in a user's project is agent-authored
|
|
35
|
+
and non-deterministic, exactly the gap the plan flagged. **A non-TypeScript
|
|
36
|
+
project gets no linter at all unless the agent writes one.**
|
|
37
|
+
|
|
38
|
+
## Finding 2: LANGUAGE does not change generated output
|
|
39
|
+
|
|
40
|
+
`backend+typescript` and `backend+python` produce byte-identical file lists
|
|
41
|
+
(18 files each: `.gitkeep` dirs, `tokens.json`, `smoke_test.sh`,
|
|
42
|
+
`workspace-profile.env`). `LANGUAGE` is validated and recorded but never
|
|
43
|
+
branches generation. Topology *does* scope directories (7–18 files by
|
|
44
|
+
topology). So: topology-scoping is deterministic; language support is a
|
|
45
|
+
recorded intention, not a generated artifact.
|
|
46
|
+
|
|
47
|
+
## Finding 3: The shipped runtime guard is inert in generated projects (fail-open)
|
|
48
|
+
|
|
49
|
+
`TEMPLATE_ITEMS` (`src/scaffold.ts`) ships `docs`, `.agents`, `scripts`,
|
|
50
|
+
`.github` — but **not** `src/`, `lib/`, or `bin/`. Consequences, all verified:
|
|
51
|
+
|
|
52
|
+
| Check | azcodr repo (control) | Scaffolded project |
|
|
53
|
+
|---|---|---|
|
|
54
|
+
| `.agents/scripts/agent_guard.js` vs `rm -rf /` payload | **BLOCKED** (exit 1) | **ALLOWED** (exit 0) |
|
|
55
|
+
| `lib/agent-guard.js` present | yes | **missing** — the guard's dynamic import rejects, and `main().catch(() => process.exit(0))` fails open |
|
|
56
|
+
| `.agents/hooks.json` references `agent_guard.js` | no | no |
|
|
57
|
+
| All hook blocks in `hooks.json` | `enabled: false` | `enabled: false` (shipped copy) |
|
|
58
|
+
|
|
59
|
+
The flagship "agent cannot skip" control therefore degrades, in a generated
|
|
60
|
+
project, to: an unwired hook script, with its engine missing, configured off,
|
|
61
|
+
that permits on error. The `boundaries` engine (`npx azcodr boundaries`)
|
|
62
|
+
likewise does not ship — only `scripts/validate-cli.js` (config/ledger/link
|
|
63
|
+
checks) is present.
|
|
64
|
+
|
|
65
|
+
## What *does* transfer deterministically
|
|
66
|
+
|
|
67
|
+
- 28 rule docs, 6 skills, `AGENTS.md` parity pointers, empty ADR ledger
|
|
68
|
+
(`data/memory.template`), `safety_guard.sh` + `verify_completion.sh` (present
|
|
69
|
+
but disabled in `hooks.json`), `smoke_test.sh` placeholder, topology-scoped
|
|
70
|
+
directories, `tokens.json` (backend/web only), `.azcodr/workspace-profile.env`.
|
|
71
|
+
|
|
72
|
+
## Recommendations (product decisions, not taken here)
|
|
73
|
+
|
|
74
|
+
1. **Either ship the engine or stop implying it ships.** Options: (a) add a
|
|
75
|
+
dependency on the published `azcodr` package + `lib/`- backed guard entry in
|
|
76
|
+
the starter `package.json`; (b) vendor a self-contained guard bundle into
|
|
77
|
+
`.agents/scripts/` with no `../../lib` import; (c) reword SKILL.md Phase 4
|
|
78
|
+
step 3 from "generate deterministic linter configurations" to an explicit
|
|
79
|
+
agent-authored checklist with verification (`npm run lint` must fail before
|
|
80
|
+
configs land, not echo).
|
|
81
|
+
2. **Fail closed, and wire the hook.** `agent_guard.js`'s catch-all `exit(0)`
|
|
82
|
+
is the wrong default for a security boundary; and `hooks.json` should ship
|
|
83
|
+
with at least the safety guard enabled plus a setup step that proves the
|
|
84
|
+
harness honors it (harnesses ignore unknown/unenabled hooks silently).
|
|
85
|
+
3. **Make LANGUAGE generative or say it isn't.** Either branch
|
|
86
|
+
`bootstrap_workspace.sh` per language (build manifests + pinned linter
|
|
87
|
+
configs per `clean_code.md` table) or change the skill wording to record the
|
|
88
|
+
language decision for the agent to implement in Phase 4.
|
|
89
|
+
4. **Close the benchmark gap this reveals.** `benchmark/RESULTS.md` Arm B/C
|
|
90
|
+
assume working hooks + boundary engine; in a real scaffolded project neither
|
|
91
|
+
is present. A fourth arm — *raw scaffolded project, no agent-authored
|
|
92
|
+
additions* — would measure the actual out-of-box enforcement: expect 0/3
|
|
93
|
+
traps caught.
|
|
94
|
+
|
|
95
|
+
---
|
|
96
|
+
|
|
97
|
+
## Addendum (2026-10-08): findings fixed — verify, don't trust
|
|
98
|
+
|
|
99
|
+
The three findings above are closed by the enforcement change set; each fix
|
|
100
|
+
names the test that locks it:
|
|
101
|
+
|
|
102
|
+
1. **No deterministic linter → per-language gate configs emitted.**
|
|
103
|
+
`bootstrap_workspace.sh` now writes the pinned config for the recorded
|
|
104
|
+
language (`eslint.config.js`, `ruff.toml`, `clippy.toml`, `.golangci.yml`,
|
|
105
|
+
`checkstyle.xml`, `.editorconfig` CA block, `.clang-tidy`; `generic` emits
|
|
106
|
+
none). Locked by `tests/bootstrap-toolchain.test.ts` (9 tests); presence is
|
|
107
|
+
re-checked on every `validate` run by the new phase 7
|
|
108
|
+
(`scripts/validate/toolchain.js`, 100% covered).
|
|
109
|
+
2. **LANGUAGE decorative → generative for toolchain.**
|
|
110
|
+
`backend+typescript` and `backend+python` still share directory trees
|
|
111
|
+
(topology-scoping, by design) but now differ in emitted gate configs; the
|
|
112
|
+
profile feed (`readProfileLanguage`) drives the validator. The agent still
|
|
113
|
+
owns build manifests (naming decisions) plus tool install and the Phase 5
|
|
114
|
+
live-block proof (`lets-build/SKILL.md`).
|
|
115
|
+
3. **Fail-open guard → vendored engine + fail-closed install.**
|
|
116
|
+
The guard engine ships inside `.agents/` (`.agents/lib/`, byte-locked to
|
|
117
|
+
`lib/` output by test), `agent_guard.js` resolves vendored-first, and a
|
|
118
|
+
missing engine exits 2 naming every path tried. Unparseable *payloads*
|
|
119
|
+
still fail open inside `inspectPreTool` per ADR-005 (ambiguous input, not a
|
|
120
|
+
broken install). `hooks.json` (+`.example`) wires an `architectural-guard`
|
|
121
|
+
PreToolUse entry. Locked by the three new `tests/agent-guard.test.ts` cases.
|
|
122
|
+
4. **Benchmark assumes working hooks → Arm D measures the scaffold.**
|
|
123
|
+
`runArmD()` + `auditScaffoldEnforcement()` score a real scaffold before and
|
|
124
|
+
after bootstrap; `benchmark/RESULTS.md` §5 carries the scorecard.
|
|
125
|
+
5. **Echo lint placeholder → rewired for Node profiles.** `bootstrap` points
|
|
126
|
+
the starter `lint` script at the emitted `eslint.config.js` (placeholder
|
|
127
|
+
only, never agent-wired entries; skipped when node is unavailable), so
|
|
128
|
+
`npm run lint` fails until the pinned tool lands instead of echoing
|
|
129
|
+
success.
|
|
130
|
+
|
|
131
|
+
## Addendum (2026-10-09): boundaries shipped, starter CI generated, hooks on
|
|
132
|
+
|
|
133
|
+
6. **Boundary engine now ships in the scaffold.** `lib/boundaries.js` is
|
|
134
|
+
vendored into `.agents/lib/boundaries.js` (byte-locked by
|
|
135
|
+
`tests/boundary-guard.test.ts`, re-copied after every build per
|
|
136
|
+
`CONTRIBUTING.md`) and a vendored-first runner `.agents/scripts/boundary_guard.js`
|
|
137
|
+
exits 0/1 on a repo's cycle & layer verdict (exit 2 on a missing engine).
|
|
138
|
+
The starter `package.json` gains a `boundaries` script pointing at it.
|
|
139
|
+
7. **Generated CI is now green out of the box.** azcodr's own dev workflows
|
|
140
|
+
(`ci.yml`, `publish.yml`) call scripts a fresh project does not have, so
|
|
141
|
+
shipping them verbatim made a scaffolded repo's CI fail on every push. The
|
|
142
|
+
scaffolder now replaces them with a starter `.github/workflows/ci.yml` that
|
|
143
|
+
only needs Node, the vendored boundary guard, and `scripts/validate-cli.js`.
|
|
144
|
+
Locked by `tests/scaffold-ci.test.ts`.
|
|
145
|
+
8. **Hooks ship enabled.** `.agents/hooks.json` (+`.example`) now ships all four
|
|
146
|
+
hooks `enabled: true` (safety, architectural, post-tool-lint, stop-verifier),
|
|
147
|
+
amending ADR-020 which deliberately shipped them disabled. The trade-off is
|
|
148
|
+
recorded in the 2026-10-09 ADR: default-on means a harness that loads the
|
|
149
|
+
file blocks immediately, at the cost that lint/stop hooks can interrupt
|
|
150
|
+
worthless-but-harmless sessions in a bare scaffold.
|
|
151
|
+
|
|
152
|
+
## Reproduce
|
|
153
|
+
|
|
154
|
+
```bash
|
|
155
|
+
# 1. Scaffold inventory
|
|
156
|
+
node -e "const {scaffold}=require('./lib/scaffold.js'); scaffold({targetDir:'<tmp>',force:true,noGit:true})"
|
|
157
|
+
# 2. Topology x language matrix (Git Bash)
|
|
158
|
+
bash .agents/skills/lets-build/scripts/bootstrap_workspace.sh <tmp> backend python
|
|
159
|
+
# 3. Guard fail-open proof
|
|
160
|
+
echo '{"tool_name":"run_command","tool_input":{"command":"rm -rf /"}}' \
|
|
161
|
+
| node <scaffold>/.agents/scripts/agent_guard.js; echo "exit=$?"
|
|
162
|
+
```
|
package/docs/rules/clean_code.md
CHANGED
|
@@ -57,13 +57,13 @@ Before writing production code for any new feature or user story, the agent must
|
|
|
57
57
|
Prevent AI-generated code rot using automated fitness functions integrated into linting and continuous verification:
|
|
58
58
|
- **File Length Gates**: Maximum 250–300 lines per file (ESLint `max-lines`).
|
|
59
59
|
- **Function Length Gates**: Maximum 20–30 lines per function (ESLint `max-lines-per-function`).
|
|
60
|
-
- **Dependency Direction Gates**: Enforce unidirectional import rules (
|
|
60
|
+
- **Dependency Direction & Boundary Gates**: Enforce unidirectional import rules and cycle prevention natively with Azcodr's zero-dependency boundary linter (`npx azcodr boundaries [dir]`) or polyglot equivalents (ArchUnit, dependency-cruiser) ensuring domain core never imports infrastructure or transport adapters, and circular dependencies are forbidden.
|
|
61
61
|
- **Complexity Budgets**: Enforce cyclomatic complexity limits (maximum 10 per function).
|
|
62
62
|
If an AI attempt to add code violates any fitness function, the build fails immediately, blocking completion until the architecture is refactored.
|
|
63
63
|
|
|
64
64
|
### Polyglot Fitness Function Standards
|
|
65
65
|
|
|
66
|
-
When bootstrapping
|
|
66
|
+
When bootstrapping projects via `/lets-build`, `bootstrap_workspace.sh` emits the pinned gate configuration for the recorded language (never invented, never absent); the agent then installs the named tool, wires the project's lint entry to it, and proves the gate in Phase 5. Gates must match these exact rules:
|
|
67
67
|
|
|
68
68
|
| Language | Linter / Static Tool | Max File Lines (300) | Max Function Lines (30) | Max Complexity (10) | Max Arguments (3) |
|
|
69
69
|
|---|---|---|---|---|---|
|
|
@@ -73,3 +73,4 @@ When bootstrapping non-TypeScript projects via `/lets-build`, the agent must ins
|
|
|
73
73
|
| **Go** | `golangci-lint` | `maintidx: 300` | `funlen: lines = 30` | `gocyclo: min-complexity = 10` | `funlen: statements = 25` |
|
|
74
74
|
| **Java** | `Checkstyle` + `ArchUnit` | `FileLength: max 300` | `MethodLength: max 30` | `CyclomaticComplexity: max 10` | `ParameterNumber: max 3` |
|
|
75
75
|
| **C# / .NET** | `.editorconfig` + Roslyn | `file_length = 300:error` | `method_length = 30:error` | `CA1502: Avoid excessive complexity <= 10` | `CA1501: max 3 params` |
|
|
76
|
+
| **C / C++** | `clang-tidy` | project lint entry (no native check) | `readability-function-size LineThreshold = 30` | `readability-function-cognitive-complexity Threshold = 10` | `readability-function-size ParameterThreshold = 3` |
|