azcodr 2.4.0 → 2.5.1

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.
@@ -14,6 +14,21 @@
14
14
  }
15
15
  ]
16
16
  },
17
+ "architectural-guard": {
18
+ "enabled": false,
19
+ "PreToolUse": [
20
+ {
21
+ "matcher": "run_command",
22
+ "hooks": [
23
+ {
24
+ "type": "command",
25
+ "command": "./.agents/scripts/agent_guard.js",
26
+ "timeout": 15
27
+ }
28
+ ]
29
+ }
30
+ ]
31
+ },
17
32
  "post-tool-lint": {
18
33
  "enabled": false,
19
34
  "PostToolUse": [
@@ -14,6 +14,21 @@
14
14
  }
15
15
  ]
16
16
  },
17
+ "architectural-guard": {
18
+ "enabled": false,
19
+ "PreToolUse": [
20
+ {
21
+ "matcher": "run_command",
22
+ "hooks": [
23
+ {
24
+ "type": "command",
25
+ "command": "./.agents/scripts/agent_guard.js",
26
+ "timeout": 15
27
+ }
28
+ ]
29
+ }
30
+ ]
31
+ },
17
32
  "post-tool-lint": {
18
33
  "enabled": false,
19
34
  "PostToolUse": [
@@ -0,0 +1,103 @@
1
+ /**
2
+ * Command safety guard inspecting shell commands against a destructive denylist.
3
+ */
4
+ export const DESTRUCTIVE_RULES = [
5
+ {
6
+ pattern: /\brm\s+(-[a-z-]*[rf][a-z-]*\s+)+(\/|\/\*|~|~\/\*|\$home|\$\{home\}|\.|\.\.|\.\/|[a-z]:\\|[a-z]:\/)/i,
7
+ reason: 'destructive rm targeting root, home, drive, or the current directory'
8
+ },
9
+ {
10
+ pattern: /(^|\s)rm\s+(-[a-z-]*\s+)*(\/|~|[a-z]:\\|[a-z]:\/)($|\s)/i,
11
+ reason: 'destructive rm targeting root or home'
12
+ },
13
+ {
14
+ pattern: /\brm\s+--recursive.*--force\s+(\/|~|\$home|\.)/i,
15
+ reason: 'destructive rm using long-form flags'
16
+ },
17
+ {
18
+ pattern: /\brm\s+.*--no-preserve-root/i,
19
+ reason: 'rm --no-preserve-root is forbidden under agent execution'
20
+ },
21
+ {
22
+ pattern: /\b(wipefs\s+-a|shred\s+-u|find\s+.*-delete)\b/i,
23
+ reason: 'irreversible disk or mass-delete operation'
24
+ },
25
+ {
26
+ pattern: /\bgit\s+push\s+.*(-f|--force|--mirror)\b/i,
27
+ reason: 'force-push or mirror-push can destroy remote history'
28
+ },
29
+ {
30
+ pattern: /\bgit\s+push\b.*--force-with-lease\b/i,
31
+ reason: 'force-push variant detected'
32
+ },
33
+ {
34
+ pattern: /\bgit\s+(reset\s+--hard|clean\s+-[a-z]*[fd])/i,
35
+ reason: 'destructive git worktree operation (reset --hard / clean)'
36
+ },
37
+ {
38
+ pattern: /\bgit\s+checkout\s+--\s+\./i,
39
+ reason: 'git checkout -- . discards all uncommitted work'
40
+ },
41
+ {
42
+ pattern: /\bgit\s+branch\s+-D\b/i,
43
+ reason: 'force branch delete'
44
+ },
45
+ {
46
+ pattern: /\b(drop\s+(database|schema|table)|truncate\s+(table\s+)?[a-z_])/i,
47
+ reason: 'destructive SQL DDL'
48
+ },
49
+ {
50
+ pattern: /\b(delete\s+from|update\s+[a-z_]+\s+set|alter\s+table)\b/i,
51
+ reason: 'destructive SQL DML'
52
+ },
53
+ {
54
+ pattern: /\b(grant\s+all|revoke\s+all)\b/i,
55
+ reason: 'privilege escalation in SQL'
56
+ },
57
+ {
58
+ pattern: /\b(mkfs|dd\s+if=|fdisk|parted\s+\/dev)\b/i,
59
+ reason: 'raw disk operation'
60
+ },
61
+ {
62
+ pattern: /(:[\s]*\([\s]*\)[\s]*\{|:[\s]*\|[\s]*:)/,
63
+ reason: 'fork bomb'
64
+ },
65
+ {
66
+ pattern: /\b(curl|wget)\s+.*\|\s*(sudo\s+)?(ba)?sh\b/i,
67
+ reason: 'piping download directly into shell execution'
68
+ },
69
+ {
70
+ pattern: /\b(base64\s+-d|base64\s+--decode)\s+.*\|/i,
71
+ reason: 'decoding encoded payload into a pipe'
72
+ },
73
+ {
74
+ pattern: /\b(npm|yarn|pnpm)\s+publish\b/i,
75
+ reason: 'package publish must run via release workflow, not ad-hoc tool call'
76
+ }
77
+ ];
78
+ export function normalizeCommand(raw) {
79
+ return raw.replace(/[\r\n\t]+/g, ' ').replace(/\s+/g, ' ').trim();
80
+ }
81
+ /**
82
+ * Checks a command string against the safety denylist.
83
+ *
84
+ * @param command - Raw shell command string.
85
+ * @returns Violation details if blocked, or clean outcome.
86
+ */
87
+ export function inspectCommand(command) {
88
+ const normalized = normalizeCommand(command);
89
+ if (!normalized)
90
+ return { blocked: false };
91
+ for (const rule of DESTRUCTIVE_RULES) {
92
+ if (rule.pattern.test(normalized)) {
93
+ return {
94
+ blocked: true,
95
+ reason: rule.reason,
96
+ command: normalized.slice(0, 300)
97
+ };
98
+ }
99
+ }
100
+ return { blocked: false, command: normalized };
101
+ }
102
+ export default { DESTRUCTIVE_RULES, normalizeCommand, inspectCommand };
103
+ //# sourceMappingURL=agent-guard-command.js.map
@@ -0,0 +1,77 @@
1
+ import fs from 'node:fs';
2
+ import path from 'node:path';
3
+ export const DEFAULT_MAX_FILE_LINES = 300;
4
+ export function countLines(text) {
5
+ if (!text)
6
+ return 0;
7
+ return text.split('\n').length;
8
+ }
9
+ export function readExistingLines(filePath) {
10
+ if (!fs.existsSync(filePath))
11
+ return 0;
12
+ try {
13
+ const content = fs.readFileSync(filePath, 'utf-8');
14
+ return countLines(content);
15
+ }
16
+ catch {
17
+ return 0;
18
+ }
19
+ }
20
+ function calculateProjectedLines(currentLines, input) {
21
+ if (input.incomingContent !== undefined) {
22
+ return countLines(input.incomingContent);
23
+ }
24
+ if (input.replacementContent !== undefined) {
25
+ const addedLines = countLines(input.replacementContent);
26
+ const removedLines = input.targetContent !== undefined ? countLines(input.targetContent) : 1;
27
+ return Math.max(0, currentLines + addedLines - removedLines);
28
+ }
29
+ return currentLines;
30
+ }
31
+ function evaluateLineThresholds(params) {
32
+ const { filePath, currentLines, projectedLines, maxLines } = params;
33
+ const base = { currentLines, projectedLines, maxLines };
34
+ const relPath = path.basename(filePath);
35
+ if (currentLines > maxLines) {
36
+ if (projectedLines >= currentLines) {
37
+ return {
38
+ ...base,
39
+ blocked: true,
40
+ reason: `Refactor-Before-Add violation: '${relPath}' currently has ${currentLines} lines (limit: ${maxLines}). Adding or maintaining lines in an overflowing file is blocked. Refactor into modular units under green tests first.`
41
+ };
42
+ }
43
+ return { ...base, blocked: false };
44
+ }
45
+ if (projectedLines > maxLines) {
46
+ return {
47
+ ...base,
48
+ blocked: true,
49
+ reason: `File line budget exceeded: '${relPath}' would grow to ${projectedLines} lines (limit: ${maxLines}). Decompose into modular components before appending more code.`
50
+ };
51
+ }
52
+ return { ...base, blocked: false };
53
+ }
54
+ /**
55
+ * Checks a proposed file write or edit against Refactor-Before-Add rules.
56
+ *
57
+ * @param input - File path and proposed content.
58
+ * @returns Decision result indicating whether the write is blocked.
59
+ */
60
+ export function inspectFileWrite(input) {
61
+ const maxLines = input.maxLines ?? DEFAULT_MAX_FILE_LINES;
62
+ const currentLines = readExistingLines(input.filePath);
63
+ const projectedLines = calculateProjectedLines(currentLines, input);
64
+ return evaluateLineThresholds({
65
+ filePath: input.filePath,
66
+ currentLines,
67
+ projectedLines,
68
+ maxLines
69
+ });
70
+ }
71
+ export default {
72
+ DEFAULT_MAX_FILE_LINES,
73
+ countLines,
74
+ readExistingLines,
75
+ inspectFileWrite
76
+ };
77
+ //# sourceMappingURL=agent-guard-file.js.map
@@ -0,0 +1,77 @@
1
+ import fs from 'node:fs';
2
+ import path from 'node:path';
3
+ export function isTestFile(filePath) {
4
+ const norm = filePath.replace(/\\/g, '/').toLowerCase();
5
+ if (/(^|\/)(tests?|__tests__)(\/|$)/i.test(norm)) {
6
+ return true;
7
+ }
8
+ return /\.(test|spec)\.[a-z0-9]+$/i.test(norm);
9
+ }
10
+ export function isNonCodeFile(filePath) {
11
+ const ext = path.extname(filePath).toLowerCase();
12
+ const nonCodeExts = new Set(['.md', '.json', '.yml', '.yaml', '.txt', '.toml', '.lock', '.svg', '.png']);
13
+ return nonCodeExts.has(ext);
14
+ }
15
+ export function isProductionFile(filePath) {
16
+ if (isNonCodeFile(filePath))
17
+ return false;
18
+ if (isTestFile(filePath))
19
+ return false;
20
+ const norm = filePath.replace(/\\/g, '/').toLowerCase();
21
+ return norm.includes('src/') || norm.includes('lib/') || norm.includes('app/');
22
+ }
23
+ export function readTddState(stateFile) {
24
+ if (!fs.existsSync(stateFile)) {
25
+ return { lastFailingTestRecorded: false };
26
+ }
27
+ try {
28
+ const raw = fs.readFileSync(stateFile, 'utf-8');
29
+ return JSON.parse(raw);
30
+ }
31
+ catch {
32
+ return { lastFailingTestRecorded: false };
33
+ }
34
+ }
35
+ export function writeTddState(stateFile, state) {
36
+ try {
37
+ const dir = path.dirname(stateFile);
38
+ if (!fs.existsSync(dir))
39
+ fs.mkdirSync(dir, { recursive: true });
40
+ fs.writeFileSync(stateFile, JSON.stringify(state, null, 2), 'utf-8');
41
+ }
42
+ catch {
43
+ // Fail-safe write: do not crash agent if state cannot be persisted
44
+ }
45
+ }
46
+ /**
47
+ * Checks whether an edit to a file is allowed under RED-before-GREEN TDD rules.
48
+ *
49
+ * @param filePath - Path to file being edited.
50
+ * @param state - Current session TDD state.
51
+ * @param enforceTestFirst - Whether test-first enforcement is strictly enabled.
52
+ * @returns Decision result indicating whether edit is blocked.
53
+ */
54
+ export function inspectTddRequirement(filePath, state, enforceTestFirst = false) {
55
+ const prod = isProductionFile(filePath);
56
+ if (!enforceTestFirst || !prod) {
57
+ return { blocked: false, isProductionFile: prod };
58
+ }
59
+ if (!state.lastFailingTestRecorded) {
60
+ const baseName = path.basename(filePath);
61
+ return {
62
+ blocked: true,
63
+ isProductionFile: true,
64
+ reason: `Test-First (RED-before-GREEN) requirement: Production file '${baseName}' cannot be edited before a failing test (RED) is recorded. Author a failing unit or acceptance test first, verify failure output, then edit production code.`
65
+ };
66
+ }
67
+ return { blocked: false, isProductionFile: true };
68
+ }
69
+ export default {
70
+ isTestFile,
71
+ isNonCodeFile,
72
+ isProductionFile,
73
+ readTddState,
74
+ writeTddState,
75
+ inspectTddRequirement
76
+ };
77
+ //# sourceMappingURL=agent-guard-tdd.js.map
@@ -0,0 +1,80 @@
1
+ import path from 'node:path';
2
+ import { inspectCommand } from './agent-guard-command.js';
3
+ import { inspectFileWrite } from './agent-guard-file.js';
4
+ import { inspectTddRequirement, readTddState, writeTddState } from './agent-guard-tdd.js';
5
+ function parseEnvelope(raw) {
6
+ try {
7
+ const trimmed = raw.trim();
8
+ if (!trimmed.startsWith('{'))
9
+ return null;
10
+ return JSON.parse(trimmed);
11
+ }
12
+ catch {
13
+ return null;
14
+ }
15
+ }
16
+ function extractKey(input, keys) {
17
+ for (const k of keys) {
18
+ if (typeof input[k] === 'string')
19
+ return input[k];
20
+ }
21
+ return undefined;
22
+ }
23
+ function extractFilePath(input) {
24
+ return extractKey(input, ['TargetFile', 'file_path', 'path', 'filePath']);
25
+ }
26
+ function extractCommand(input) {
27
+ return extractKey(input, ['CommandLine', 'command', 'cmd']);
28
+ }
29
+ function inspectPreCommand(cmd) {
30
+ const violation = inspectCommand(cmd);
31
+ if (violation.blocked) {
32
+ return { allowed: false, reason: violation.reason, source: 'command' };
33
+ }
34
+ return { allowed: true };
35
+ }
36
+ function inspectPreFile(filePath, input, options) {
37
+ const incoming = extractKey(input, ['CodeContent', 'content']);
38
+ const replacement = extractKey(input, ['ReplacementContent', 'replacement']);
39
+ const target = extractKey(input, ['TargetContent', 'target']);
40
+ const fileDecision = inspectFileWrite({
41
+ filePath,
42
+ incomingContent: incoming,
43
+ replacementContent: replacement,
44
+ targetContent: target,
45
+ maxLines: options.maxFileLines
46
+ });
47
+ if (fileDecision.blocked) {
48
+ return { allowed: false, reason: fileDecision.reason, source: 'file' };
49
+ }
50
+ const root = options.workspaceRoot ?? process.cwd();
51
+ const statePath = path.join(root, '.agents', '.session-state.json');
52
+ const state = readTddState(statePath);
53
+ const tddDecision = inspectTddRequirement(filePath, state, options.enforceTestFirst);
54
+ if (tddDecision.blocked) {
55
+ return { allowed: false, reason: tddDecision.reason, source: 'tdd' };
56
+ }
57
+ return { allowed: true };
58
+ }
59
+ /**
60
+ * Inspects a tool-use request before execution (PreToolUse hook).
61
+ *
62
+ * @param rawInput - Raw command string, JSON envelope, or argv slice.
63
+ * @param options - Guard configuration options.
64
+ * @returns Guard decision indicating whether tool execution is permitted.
65
+ */
66
+ export function inspectPreTool(rawInput, options = {}) {
67
+ const env = parseEnvelope(rawInput);
68
+ if (env && env.tool_input) {
69
+ const cmd = extractCommand(env.tool_input);
70
+ if (cmd)
71
+ return inspectPreCommand(cmd);
72
+ const targetFile = extractFilePath(env.tool_input);
73
+ if (targetFile)
74
+ return inspectPreFile(targetFile, env.tool_input, options);
75
+ }
76
+ return inspectPreCommand(rawInput);
77
+ }
78
+ export { inspectCommand, inspectFileWrite, inspectTddRequirement, readTddState, writeTddState };
79
+ export default { inspectPreTool, inspectCommand, inspectFileWrite, inspectTddRequirement };
80
+ //# sourceMappingURL=agent-guard.js.map
@@ -14,10 +14,39 @@ import process from 'node:process';
14
14
  import { fileURLToPath, pathToFileURL } from 'node:url';
15
15
 
16
16
  const selfDir = path.dirname(fileURLToPath(import.meta.url));
17
- const guardModulePath = path.resolve(selfDir, '../../lib/agent-guard.js');
17
+
18
+ // Resolution order (first existing file wins):
19
+ // 1. AZCODR_GUARD_ENGINE override (tests, embedders).
20
+ // 2. ../lib/agent-guard.js — vendored engine shipped inside `.agents/`
21
+ // (present in scaffolded projects; `.agents` is copied recursively).
22
+ // 3. ../../lib/agent-guard.js — azcodr repo dev layout (fallback only).
23
+ const guardCandidates = [
24
+ process.env.AZCODR_GUARD_ENGINE,
25
+ path.resolve(selfDir, '../lib/agent-guard.js'),
26
+ path.resolve(selfDir, '../../lib/agent-guard.js')
27
+ ].filter(Boolean);
18
28
 
19
29
  async function getGuardModule() {
20
- return import(pathToFileURL(guardModulePath).href);
30
+ const tried = [];
31
+ for (const candidate of guardCandidates) {
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 must be loud, never a silent allow.
43
+ // (Unparseable tool payloads still fail open inside inspectPreTool per
44
+ // ADR-005; a missing engine is a broken install, not an ambiguous input.)
45
+ console.error(
46
+ '🚨 Architectural Guard misconfigured: engine module not found, refusing to fail open. Tried:\n' +
47
+ tried.map((t) => ` - ${t}`).join('\n')
48
+ );
49
+ process.exit(2);
21
50
  }
22
51
 
23
52
  async function readStdin(timeoutMs = 1500) {
@@ -60,4 +89,7 @@ async function main() {
60
89
  process.exit(0);
61
90
  }
62
91
 
63
- main().catch(() => process.exit(0));
92
+ main().catch((err) => {
93
+ console.error(`🚨 Architectural Guard crashed: ${err?.message || err}`);
94
+ process.exit(2);
95
+ });
@@ -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`), deterministic linter configurations strictly enforcing the [Polyglot Fitness Function Standards](../../../docs/rules/clean_code.md#polyglot-fitness-function-standards), and boundary smoke test (`scripts/smoke_test.sh`).
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.00% test coverage gate, zero lint errors
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
  #
@@ -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 for 100% coverage]
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: Enterprise Architecture & Agentic Engineering Starter Template**
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.00% test coverage.
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
- - **97% functions coverage**
55
- - **98% branches coverage**
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, and ADR ledger consistency.
62
+ Validates root harness parity, progressive disclosure rules, skill formats, markdown links, ADR ledger consistency, and toolchain gate presence.
63
+ 6. **Vendored Guard Sync:** after any change under `src/agent-guard*.ts` and `npm run build`, re-copy the four compiled engine files into `.agents/lib/` (byte-equality is enforced by `tests/agent-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'])fs.copyFileSync('lib/'+f,'.agents/lib/'+f)"
66
+ ```
61
67
 
62
68
  ---
63
69
 
package/README.md CHANGED
@@ -1,10 +1,14 @@
1
- # azcodr: Enterprise Architecture & Agentic Engineering Starter Template
1
+ # azcodr: Architecture governance toolkit, with an optional starter
2
2
 
3
3
  [![npm version](https://img.shields.io/npm/v/azcodr.svg?color=cb3837)](https://www.npmjs.com/package/azcodr)
4
4
  [![JSR Package](https://jsr.io/badges/@azcodr/azcodr)](https://jsr.io/@azcodr/azcodr)
5
5
  [![CI Status](https://github.com/prosubodh/azcodr/actions/workflows/ci.yml/badge.svg)](https://github.com/prosubodh/azcodr/actions/workflows/ci.yml)
6
- [![Coverage](https://img.shields.io/badge/coverage-100.00%25-brightgreen.svg)](https://github.com/prosubodh/azcodr)
7
- [![Mutation Score](https://img.shields.io/badge/mutants%20killed-100%25-brightgreen.svg)](https://github.com/prosubodh/azcodr)
6
+ [![Coverage](https://img.shields.io/badge/coverage-100%25-brightgreen.svg)](https://github.com/prosubodh/azcodr/actions/workflows/ci.yml)
7
+ [![Mutation Score](https://img.shields.io/badge/mutants%20killed-100%25-brightgreen.svg)](https://github.com/prosubodh/azcodr/blob/main/benchmark/RESULTS.md)
8
+ [![Dependencies](https://img.shields.io/badge/dependencies-0-success.svg)](https://www.npmjs.com/package/azcodr)
9
+ [![License: MIT](https://img.shields.io/badge/license-MIT-blue.svg)](./LICENSE)
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.
8
12
  [![Dependencies](https://img.shields.io/badge/dependencies-0-success.svg)](https://www.npmjs.com/package/azcodr)
9
13
  [![License: MIT](https://img.shields.io/badge/license-MIT-blue.svg)](./LICENSE)
10
14
 
@@ -127,7 +131,7 @@ The architecture enforces 28 cohesive, single-responsibility domain rules. Read
127
131
 
128
132
  | Domain | Rule Reference File | Key Focus & Invariants |
129
133
  |---|---|---|
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. |
134
+ | **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
135
  | **Clean Code** | [`clean_code.md`](./docs/rules/clean_code.md) | Naming, small functions, CQS, SLAP, DRY, DbC, zero side-effects. |
132
136
  | **Design Patterns** | [`design_patterns.md`](./docs/rules/design_patterns.md) | Adapter, Factory, Strategy, Result `<T, E>`, and GoF pattern catalog. |
133
137
  | **Type Safety** | [`type_safety.md`](./docs/rules/type_safety.md) | Compiler strictness, branded nominal types, type discriminators across polyglot languages. |
@@ -171,10 +175,10 @@ The architecture enforces 28 cohesive, single-responsibility domain rules. Read
171
175
 
172
176
  ## 🚀 Starting a New Project with `/lets-build`
173
177
 
174
- This repository serves as an **enterprise architectural starter template**. When beginning a new software project:
178
+ This repository serves as an **architecture governance toolkit, with an optional starter**. When beginning a new software project:
175
179
 
176
180
  ### Step 1: Initialize Workspace with npx
177
- Pull and scaffold the complete enterprise architectural template into your project directory using `npx`:
181
+ Pull and scaffold the complete architecture governance toolkit into your project directory using `npx`:
178
182
  ```bash
179
183
  npx azcodr my-new-project
180
184
  cd my-new-project
@@ -0,0 +1,141 @@
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
+ ## Reproduce
132
+
133
+ ```bash
134
+ # 1. Scaffold inventory
135
+ node -e "const {scaffold}=require('./lib/scaffold.js'); scaffold({targetDir:'<tmp>',force:true,noGit:true})"
136
+ # 2. Topology x language matrix (Git Bash)
137
+ bash .agents/skills/lets-build/scripts/bootstrap_workspace.sh <tmp> backend python
138
+ # 3. Guard fail-open proof
139
+ echo '{"tool_name":"run_command","tool_input":{"command":"rm -rf /"}}' \
140
+ | node <scaffold>/.agents/scripts/agent_guard.js; echo "exit=$?"
141
+ ```
@@ -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 (e.g. `import/no-restricted-paths`, `dependency-cruiser`, `ArchUnit`) ensuring domain core never imports infrastructure or transport adapters.
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 non-TypeScript projects via `/lets-build`, the agent must instantiate deterministic, automated fitness function gates matching these exact rules:
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` |
@@ -1,6 +1,6 @@
1
1
  # Test-Driven Development (London School TDD) & Test Isolation Standards
2
2
 
3
- > **Core Mandate:** Drive all features through the non-negotiable 5-Phase Agile Domain Lifecycle (Outside-In Double-Loop TDD, Uncle Bob's 3 Laws), enforcing transactional database rollback per test, zero-sleep determinism, and non-negotiable 100.00% statement, branch, and function coverage gates.
3
+ > **Core Mandate:** Drive all features through the non-negotiable 5-Phase Agile Domain Lifecycle (Outside-In Double-Loop TDD, Uncle Bob's 3 Laws), enforcing transactional database rollback per test, zero-sleep determinism, and CI-enforced 100% coverage on all metrics plus mutation floor (assertion-free tests rejected).
4
4
 
5
5
  ---
6
6
 
@@ -14,7 +14,7 @@ flowchart TD
14
14
  P2["Phase 2: Tactical Domain Analysis<br/>• Ubiquitous Language & Bounded Contexts<br/>• Aggregate Roots & Business Invariants"]
15
15
  P3["Phase 3: Outer Acceptance Test (RED)<br/>• Failing UI component or API route test<br/>• Verifies failure for expected reason"]
16
16
  P4["Phase 4: Inner TDD & Collaborator Discovery (RED-GREEN-REFACTOR)<br/>• Discovers Use Cases & Ports<br/>• Nano-cycles with Uncle Bob's 3 Laws"]
17
- P5["Phase 5: Outer Verification & Proof (GREEN)<br/>• Outer test passes with zero regressions<br/>• 100.00% coverage & boundary smoke verification"]
17
+ P5["Phase 5: Outer Verification & Proof (GREEN)<br/>• Outer test passes with zero regressions<br/>• 100% coverage on all metrics + mutation gate & boundary smoke verification"]
18
18
 
19
19
  P1 --> P2 --> P3 --> P4 --> P5
20
20
  ```
@@ -125,10 +125,13 @@ sequenceDiagram
125
125
 
126
126
  ---
127
127
 
128
- ## 7. Mandatory 100.00% Test Coverage Thresholds
128
+ ## 7. Mandatory 100% Coverage on All Metrics + Mutation Floor (No Assertion-Free Tests)
129
129
 
130
- - **Strict Coverage Thresholds**: Maintain line, function, branch, and statement test coverage at **100.00%** across all backend domain logic, adapters, contracts, and frontend suites. Strictly enforce 100% threshold failure gates in CI pipelines (`scripts/test_coverage.js`).
131
- - **Exhaustive Status Codes & Error Branches**: Explicitly test all HTTP/gRPC response codes:
130
+ - **Strict 100% thresholds:** CI fails unless line, function, branch, AND statement coverage are all 100% (`jest.config.js`: lines 100 / functions 100 / branches 100 / statements 100). Generated projects must hold the same 100% bar in their own stack via the per-language gates in `docs/rules/clean_code.md`. Lowering any metric requires an ADR.
131
+ - **Mutation floor on guards:** line coverage alone proves little. Behavioral guards (`agent-guard-*`, `boundaries.ts`, protected-target checks) must hold a 100% mutant-kill gate (`npm run test:mutation`, `benchmark/mutation-test.js`). A green suite that lets a `blocked: true → false` or `return cycles → return []` mutant survive is a failure, even at 100% lines.
132
+ - **Assertion-density check:** agents asked to hit a line number write assertion-free tests to cover lines. Reject that explicitly: every new behavioral test must contain at least one behavior-asserting expectation (no `expect(true).toBe(true)`, no tests without assertions). Prefer `benchmark/evaluate.js --strict-tests` style checks (assertions per test ≥ 1, critical paths ≥ 2) over raising the line percentage.
133
+ - **What this repo enforces vs what users get:** this repo's exact thresholds live in `jest.config.js` (100% lines, branches, functions, statements) and are locked by `tests/coverage-config.test.ts`. Generated polyglot projects get the equivalent per-language fitness gates in `docs/rules/clean_code.md` (ESLint / ruff / clippy / golangci-lint / Checkstyle / Roslyn) at the same 100% bar — the tooling differs by stack, the bar must not.
134
+ - **Exhaustive status codes & error branches:** explicitly test all HTTP/gRPC response codes:
132
135
  - Success: `200 OK`, `201 Created`, `204 No Content`
133
136
  - Client Errors: `400 Bad Request`, `401 Unauthorized`, `403 Forbidden`, `404 Not Found`, `409 Conflict`, `422 Unprocessable Entity`, `429 Too Many Requests`
134
137
  - Server Failures: `500 Internal Server Error`, `503 Service Unavailable`
package/lib/index.d.ts CHANGED
@@ -1,6 +1,6 @@
1
1
  /**
2
2
  * @module @azcodr/azcodr
3
- * Enterprise Architecture & Agentic Engineering Starter Template.
3
+ * Architecture governance toolkit, with an optional starter.
4
4
  *
5
5
  * Provides problem-first, topology-aligned project scaffolding with strict systemic atomicity,
6
6
  * filesystem scope guards, git worktree initialization, and multi-agent harness parity.
package/lib/index.js CHANGED
@@ -1,6 +1,6 @@
1
1
  /**
2
2
  * @module @azcodr/azcodr
3
- * Enterprise Architecture & Agentic Engineering Starter Template.
3
+ * Architecture governance toolkit, with an optional starter.
4
4
  *
5
5
  * Provides problem-first, topology-aligned project scaffolding with strict systemic atomicity,
6
6
  * filesystem scope guards, git worktree initialization, and multi-agent harness parity.
package/lib/scaffold.js CHANGED
@@ -126,7 +126,7 @@ function starterPackageJson(resolvedTarget) {
126
126
  version: '0.1.0',
127
127
  type: 'module',
128
128
  private: true,
129
- description: 'Scaffolded with azcodr enterprise architecture template',
129
+ description: 'Scaffolded with the azcodr architecture governance toolkit',
130
130
  scripts: {
131
131
  test: 'node --test',
132
132
  'test:coverage': 'jest --coverage',
@@ -1 +1 @@
1
- {"version":3,"file":"scaffold.js","sourceRoot":"","sources":["../src/scaffold.ts"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"scaffold.js","sourceRoot":"","sources":["../src/scaffold.ts"],"names":[],"mappings":"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"}
package/memory.md CHANGED
@@ -35,6 +35,8 @@
35
35
  | [ADR-016](./memory.md#adr-016-standalone-architectural-validator-agent-runtime-hooks-boundary-engine--empirical-benchmark) | Standalone Architectural Validator, Agent Runtime Hooks, Boundary Engine & Empirical Benchmark | 2026-10-08 | ACCEPTED | [`agentic_configuration.md`](./docs/rules/agentic_configuration.md) |
36
36
  | [ADR-017](./memory.md#adr-017-continuous-mutation-and-benchmark-ci-gates-oss-governance-and-reference-example) | Continuous Mutation & Benchmark CI Gates, OSS Governance & Reference Example | 2026-10-08 | ACCEPTED | [`devops_ci_cd.md`](./docs/rules/devops_ci_cd.md) |
37
37
  | [ADR-018](./memory.md#adr-018-first-class-architectural-boundary-and-cycle-inspection-cli-subcommand) | First-Class Architectural Boundary and Cycle Inspection CLI Subcommand | 2026-10-08 | ACCEPTED | [`clean_code.md`](./docs/rules/clean_code.md) |
38
+ | [ADR-019](./memory.md#adr-019-honest-claims-100-percent-all-metrics-gate-and-benchmark-limits-on-the-record) | Honest claims, 100% all-metrics gate, and benchmark limits on the record | 2026-10-08 | ACCEPTED | [`test_driven_development.md`](./docs/rules/test_driven_development.md) |
39
+ | [ADR-020](./memory.md#adr-020-generated-projects-get-deterministic-enforcement) | Generated projects get deterministic enforcement | 2026-10-08 | ACCEPTED | [`clean_code.md`](./docs/rules/clean_code.md) |
38
40
 
39
41
  ---
40
42
 
@@ -96,6 +98,20 @@
96
98
  - **Consequences:** ✅ Every PR and push automatically verifies 100% mutation resistance and benchmark assertions. ✅ Full open-source governance compliance achieved (`SECURITY.md`, `CONTRIBUTING.md`, `CODE_OF_CONDUCT.md`). ✅ Concrete, working reference example proves downstream architectural boundaries and Clean Code limits. ✅ 100.00% lines, functions, statements, and branches coverage maintained across all 40 test suites and 489 tests.
97
99
  - **Enforced In:** `.github/workflows/ci.yml`, `benchmark/mutation-test.js`, `CODE_OF_CONDUCT.md`, `examples/clean-architecture-todo/`, `tests/example-project.test.ts`, `README.md`, `package.json`
98
100
 
101
+ #### ADR-020: Generated Projects Get Deterministic Enforcement
102
+ - **Date:** 2026-10-08 | **Status:** ACCEPTED
103
+ - **Context:** The generated-enforcement analysis (`docs/generated-enforcement-analysis.md`) proved three defects by execution: (1) zero deterministic linter configs in any generated project (starter `lint` is an echo placeholder), (2) LANGUAGE recorded but never generative, (3) the shipped `agent_guard.js` crashed on its missing `../../lib` engine and its catch-all `exit(0)` silently allowed everything — including `rm -rf /` — in scaffolded projects.
104
+ - **Decision:** (1) Vendor the closed guard-engine set (`agent-guard{,-command,-file,-tdd}.js`) into `.agents/lib/` (byte-locked to `lib/` output by test; re-copy after every build per `CONTRIBUTING.md`); the hook resolves vendored-first, repo-layout second, `AZCODR_GUARD_ENGINE` override first. (2) Fail CLOSED (exit 2, naming every path tried) only when the engine itself cannot load — a broken install, not an ambiguous input; unparseable tool payloads still fail open inside `inspectPreTool` per ADR-005. (3) `bootstrap_workspace.sh` emits the pinned per-language gate config (11 profiles; `generic` emits none; create-if-absent so re-runs never clobber); build manifests stay agent-authored (naming decisions), and the agent installs the tool plus proves the gate with a live block in Phase 5. (4) `hooks.json` (+`.example`) wires an `architectural-guard` PreToolUse entry, disabled by default like all hooks — auto-enabling Stop/lint hooks in a dependency-less fresh scaffold would brick agent loops. (5) New validator phase 7 checks gate-config presence from `.azcodr/workspace-profile.env`, skipping cleanly without a profile (this repo unaffected). (6) Benchmark Arm D (`runArmD` + `auditScaffoldEnforcement`) scores a real scaffold before/after bootstrap; agent-layer state (tool installed, lint wired, hooks on) is reported, never gating.
105
+ - **Consequences:** ✅ Same `rm -rf /` payload now BLOCKED from vendored layout; missing engine exits 2 instead of allowing. ✅ Every recorded language produces its gate config; `validate` fails when one is deleted. ✅ 100% coverage holds on the new `scripts/validate/toolchain.js`. ⚠️ Hooks still require harness opt-in; tool installation still requires network at agent time — both recorded openly in `benchmark/RESULTS.md` §5–8.
106
+ - **Enforced In:** `.agents/lib/`, `.agents/scripts/agent_guard.js`, `.agents/hooks.json`, `.agents/skills/lets-build/scripts/bootstrap_workspace.sh`, `scripts/validate/toolchain.js`, `benchmark/evaluate.js`, `benchmark/run-benchmark.js`, `tests/agent-guard.test.ts`, `tests/bootstrap-toolchain.test.ts`, `tests/validate-toolchain.test.ts`, `tests/benchmark.test.ts`
107
+
108
+ #### ADR-019: Honest Claims, 100% All-Metrics Gate, and Benchmark Limits on the Record
109
+ - **Date:** 2026-10-08 | **Status:** ACCEPTED
110
+ - **Context:** An outside consolidated review found the engineering real but several claims ahead of evidence: "Enterprise starter" positioning vs a governance toolkit, coverage badges without a linked report, and a benchmark that proved drift reduction on synthetic fixtures while reading as a live-agent trial. Separately, the Jest gate enforced 100% lines but only 97% functions / 98% branches even though actual coverage measured 100/100/100/100.
111
+ - **Decision:** (1) Reposition wording to "Architecture governance toolkit, with an optional starter" (`package.json`, `jsr.json`, `AGENTS.md`, `README.md`, `src/index.ts`). (2) Raise the Jest gate to 100% lines, functions, branches, AND statements, locked by `tests/coverage-config.test.ts`; badges link to the CI workflow and the `coverage-report` artifact; docs keep the 100% bar AND the mutation floor plus assertion-density rejection so the number cannot be gamed with assertion-free tests. (3) Harden the benchmark honestly instead of inflating it: `evaluate.js` adds a test-quality proxy and marks cost metrics as manual-only, `run-benchmark.js` writes timestamped JSON transcripts to `benchmark/results/` and prints limitations, `RESULTS.md` gains "Where Azcodr Loses" and "Threats to validity" sections.
112
+ - **Consequences:** ✅ Claims match evidence; the gate is stricter than reality required (no new tests needed — 503 already pass at 100%). ✅ Every benchmark citation now ships with a transcript and a limits section. ⚠️ Synthetic single-run limits remain (no multi-model variance, no token/review-minute measurement) — recorded openly rather than fixed.
113
+ - **Enforced In:** `jest.config.js`, `tests/coverage-config.test.ts`, `benchmark/evaluate.js`, `benchmark/run-benchmark.js`, `benchmark/RESULTS.md`, `README.md`, `CONTRIBUTING.md`, `docs/rules/test_driven_development.md`
114
+
99
115
  #### ADR-018: First-Class Architectural Boundary and Cycle Inspection CLI Subcommand
100
116
  - **Date:** 2026-10-08 | **Status:** ACCEPTED
101
117
  - **Context:** Following the implementation of the zero-dependency boundary and cycle engine (`src/boundaries.ts`, ADR-016), inspecting dependency cycles and Clean Architecture layer breaches required either running the empirical benchmark or importing the internal TypeScript engine programmatically. Users and CI pipelines lacked a direct, dedicated CLI entry point (`npx azcodr boundaries [dir]`) to run boundary and circular dependency inspections as a standalone architectural linter.
package/package.json CHANGED
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "name": "azcodr",
3
- "version": "2.4.0",
4
- "description": "Enterprise Architecture & Agentic Engineering Starter Template",
3
+ "version": "2.5.1",
4
+ "description": "Architecture governance toolkit with topology-scoped scaffolding for AI-assisted development (early release)",
5
5
  "type": "module",
6
6
  "bin": {
7
7
  "azcodr": "bin/azcodr.js"
@@ -0,0 +1,60 @@
1
+ import fs from 'node:fs';
2
+ import path from 'node:path';
3
+
4
+ export const TOOLCHAIN_FILES = {
5
+ typescript: ['eslint.config.js'],
6
+ javascript: ['eslint.config.js'],
7
+ deno: ['eslint.config.js'],
8
+ bun: ['eslint.config.js'],
9
+ python: ['ruff.toml'],
10
+ rust: ['clippy.toml'],
11
+ go: ['.golangci.yml'],
12
+ java: ['checkstyle.xml'],
13
+ csharp: ['.editorconfig'],
14
+ cpp: ['.clang-tidy'],
15
+ c: ['.clang-tidy'],
16
+ generic: []
17
+ };
18
+
19
+ export function readProfileLanguage(workspaceRoot) {
20
+ const profile = path.join(workspaceRoot, '.azcodr', 'workspace-profile.env');
21
+ if (!fs.existsSync(profile)) return null;
22
+ const match = /^language=(.+)$/m.exec(fs.readFileSync(profile, 'utf-8'));
23
+ return match ? match[1].trim() : null;
24
+ }
25
+
26
+ export function expectedToolchainFiles(language) {
27
+ if (!language) return [];
28
+ return TOOLCHAIN_FILES[language] || [];
29
+ }
30
+
31
+ function reportMissing(ctx, language, expected) {
32
+ let missing = 0;
33
+ for (const name of expected) {
34
+ if (!fs.existsSync(path.join(ctx.workspaceRoot, name))) {
35
+ ctx.fail(`Missing toolchain gate '${name}' for language '${language}'; re-run bootstrap or restore the config.`);
36
+ missing += 1;
37
+ }
38
+ }
39
+ return missing;
40
+ }
41
+
42
+ export function phaseToolchain(ctx) {
43
+ ctx.log('');
44
+ ctx.heading('7. Checking Toolchain Enforcement...');
45
+ const language = readProfileLanguage(ctx.workspaceRoot);
46
+ if (language === null) {
47
+ ctx.pass('No workspace profile; toolchain check skipped.');
48
+ return;
49
+ }
50
+ const expected = expectedToolchainFiles(language);
51
+ if (expected.length === 0) {
52
+ ctx.pass(`Language '${language}' declares no toolchain configs; nothing to enforce.`);
53
+ return;
54
+ }
55
+ if (reportMissing(ctx, language, expected) === 0) {
56
+ ctx.pass(`Toolchain gates present for language '${language}' (${expected.join(', ')}).`);
57
+ }
58
+ }
59
+
60
+ export default { TOOLCHAIN_FILES, readProfileLanguage, expectedToolchainFiles, phaseToolchain };
@@ -11,6 +11,7 @@ import { phaseRootConfig } from './validate/root.js';
11
11
  import { phaseRules } from './validate/rules.js';
12
12
  import { phaseSkills } from './validate/skills.js';
13
13
  import { phaseLinks } from './validate/links.js';
14
+ import { phaseToolchain, readProfileLanguage, expectedToolchainFiles, TOOLCHAIN_FILES } from './validate/toolchain.js';
14
15
 
15
16
  /**
16
17
  * NOTE: this module is a library. It never self-executes, so importing it from
@@ -105,6 +106,7 @@ function runValidation(workspaceRoot, reporter = createReporter()) {
105
106
  phaseLinks(ctx);
106
107
  phaseMemory(ctx);
107
108
  phaseLedger(ctx);
109
+ phaseToolchain(ctx);
108
110
  reportSummary(counts, reporter);
109
111
  return {
110
112
  errors: counts.errors,
@@ -138,7 +140,11 @@ export {
138
140
  createLowercaseParityLink,
139
141
  stripHtmlComments,
140
142
  stripFencedCode,
141
- walkMarkdown
143
+ walkMarkdown,
144
+ phaseToolchain,
145
+ readProfileLanguage,
146
+ expectedToolchainFiles,
147
+ TOOLCHAIN_FILES
142
148
  };
143
149
 
144
150
  export default {
@@ -154,5 +160,9 @@ export default {
154
160
  createLowercaseParityLink,
155
161
  stripHtmlComments,
156
162
  stripFencedCode,
157
- walkMarkdown
163
+ walkMarkdown,
164
+ phaseToolchain,
165
+ readProfileLanguage,
166
+ expectedToolchainFiles,
167
+ TOOLCHAIN_FILES
158
168
  };
package/src/index.ts CHANGED
@@ -1,6 +1,6 @@
1
1
  /**
2
2
  * @module @azcodr/azcodr
3
- * Enterprise Architecture & Agentic Engineering Starter Template.
3
+ * Architecture governance toolkit, with an optional starter.
4
4
  *
5
5
  * Provides problem-first, topology-aligned project scaffolding with strict systemic atomicity,
6
6
  * filesystem scope guards, git worktree initialization, and multi-agent harness parity.
package/src/scaffold.ts CHANGED
@@ -184,7 +184,7 @@ function starterPackageJson(resolvedTarget: string): Record<string, unknown> {
184
184
  version: '0.1.0',
185
185
  type: 'module',
186
186
  private: true,
187
- description: 'Scaffolded with azcodr enterprise architecture template',
187
+ description: 'Scaffolded with the azcodr architecture governance toolkit',
188
188
  scripts: {
189
189
  test: 'node --test',
190
190
  'test:coverage': 'jest --coverage',