Skip to content

Commit 70b1ede

Browse files
authored
feat!: add --strict and --output <format> (SARIF), remove --json/--ci/--max-warnings from check (#536)
## Summary - **`--strict`** (new, on `check`, `review-context`, `adr sync`): treats otherwise-advisory diagnostics as failures. On `check` it fails on any rule-severity warning and on `briefingWarnings`/`suppressionWarnings`/`unparsedAdrs`; on `review-context` it fails on `truncatedBriefings` and, with `--run-checks`, on the reused `checkSummary` findings (deliberately not on ordinary rule violations — `check` stays the compliance gate); on `adr sync` it fails on `result.errors`. Resolves CLI flag → `strict` key in `.archgate/config.json` → off. Documented in new ADR **ARCH-026**. - **`--output <format>`** (breaking, `check` only): replaces the `--json`/`--ci` boolean flags with a single typed option — `console` (default) | `json` | `github` (Actions annotations) | `sarif`. Agent-context auto-detect still upgrades the default to compact `json`; `github`/`sarif` are opt-in only. - **`--output sarif`** (new): SARIF 2.1.0 for GitHub Code Scanning/Code Quality — rule violations plus advisory findings as synthetic-rule results. No new dependency (hand-built in `src/engine/sarif.ts`). - **`--max-warnings` removed** (breaking, `check` only): `--strict` is the single escalation switch; the tolerate-up-to-N warning budget is gone. - **Zero-rules path hardened**: `check` now collects corpus-wide advisory diagnostics even when no `rules: true` ADR loads, so a prose-only or fully-unparseable corpus can't silently pass `--strict`. - Docs updated in English + pt-br + nb (GEN-002 parity), including corrected SARIF upload workflows (`if: always()` + `security-events: write`). ## Breaking changes | Removed | Replacement | | --- | --- | | `archgate check --json` | `archgate check --output json` | | `archgate check --ci` | `archgate check --output github` | | `archgate check --max-warnings <n>` | `archgate check --strict` (zero-tolerance only) | No other command's flags are affected. ## Test plan - [x] `bun run validate` (lint, typecheck, format, 1873 tests, `archgate check` 49/49, knip, build check) passes clean - [x] New coverage: `reporter-strict`, `check-strict` (incl. zero-rules + removed-flag rejection), `review-context-strict`, `sync-strict`, `sarif` unit + `check-sarif` integration tests - [x] Domain reviewer sub-agents (Architecture, General/Process, CI, Distribution, Legal): all APPROVED across rounds, 0 violations --------- Signed-off-by: Rhuan Barreto <rhuan.barreto@gmail.com> Signed-off-by: Rhuan Barreto <rhuan@barreto.work> Signed-off-by: github-actions[bot] <41898282+github-actions[bot]@users.noreply.github.com>
1 parent 29daad8 commit 70b1ede

48 files changed

Lines changed: 2955 additions & 659 deletions

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

.archgate/adrs/ARCH-003-output-formatting.md

Lines changed: 33 additions & 20 deletions
Original file line numberDiff line numberDiff line change
@@ -23,23 +23,23 @@ CLI output must be readable for humans and parseable for machines: colored in te
2323

2424
**Key conventions:**
2525

26-
1. **Colors via `styleText` only** — All colored output uses `styleText(format, text)` from `node:util`; no raw ANSI codes or third-party color libraries. `format` takes one style or an array (`["red", "bold"]`).
27-
2. **`--json` flag for machine-readable output** — Commands producing structured results (check, adr list) support `--json`: JSON to stdout, no colors, no decorative formatting.
28-
3. **Auto-compact JSON for agent contexts**When stdout is not a TTY and `CI` is unset the caller is likely an AI agent, so `--json`-capable commands auto-switch to compact (unindented) JSON to minimize tokens. Detection: `src/helpers/output.ts` (`isAgentContext()`, `formatJSON()`). Precedence: `--ci` flag → `--json` flag (pretty) → agent auto-detect (compact) → TTY (human-readable) → CI env (human-readable).
26+
1. **Colors via `styleText` only** — All colored output uses `styleText(format, text)` from `node:util`; no raw ANSI codes or third-party color libraries.
27+
2. **Machine-readable output** — Commands with structured results support `--json` (`adr list`/`sync`/`import`) or, for `check`, `--output <format>` (convention 3). Both use `formatJSON()`: JSON to stdout, no colors, no decorative formatting.
28+
3. **`--output <format>` on `check`**`console` (default) | `json` | `github` (Actions annotations) | `sarif` (SARIF 2.1.0, for Code Scanning/Code Quality). Breaking change from `--json`/`--ci`; other commands unaffected. `--output` wins when given; omitted defaults to console, auto-upgrading to compact json in agent context. `github`/`sarif` are opt-in only, never auto-detected — the canonical pattern for future `check` formats.
2929
4. **No emoji** — Use text symbols and colors; emoji rendering is inconsistent across terminals, fonts, and CI log viewers.
3030
5. **stdout for results, stderr for diagnostics** — Results to stdout; errors, warnings, and debug to stderr (`logError()`, `logWarn()`, `logDebug()`).
3131
6. **Concise and scannable** — Use whitespace and alignment, not walls of text.
32-
7. **Progressive disclosure for agent payloads** — Enumeration commands (`adr list`) MUST emit identity fields only: the minimum needed to identify a record and decide whether to fetch it. Single-record commands (`adr show`) emit it in full; agents drill down. Compaction (convention 3) scales a payload by a constant factor; field selection keeps output inline-readable as record count grows — past a size threshold agent harnesses spill tool results to a file, defeating the purpose of emitting JSON. Default: the fields the human table renders are the right JSON field set. Omission MUST be driven by having nothing to report, never by a pass/fail status: a record that reads as passing can still carry warnings the consumer needs.
32+
7. **Progressive disclosure for agent payloads** — Enumeration commands (`adr list`) MUST emit identity fields only: the minimum needed to identify a record and decide whether to fetch it. Single-record commands (`adr show`) emit it in full; agents drill down. Compaction (`formatJSON()`, convention 2) scales a payload by a constant factor; field selection keeps output inline-readable as record count grows — past a size threshold agent harnesses spill tool results to a file, defeating the purpose of emitting JSON. Default: the fields the human table renders are the right JSON field set. Omission MUST be driven by having nothing to report, never by a pass/fail status: a record that reads as passing can still carry warnings the consumer needs.
3333

3434
## Do's and Don'ts
3535

3636
### Do
3737

3838
- **DO** use `styleText` from `node:util` for colors
39-
- **DO** support a `--json` flag for machine-readable output
39+
- **DO** support `--output <format>` (or `--json` on simpler commands) for machine-readable output
4040
- **DO** use `formatJSON()` from `src/helpers/output.ts` for all JSON serialization in commands — it auto-detects agent context
41-
- **DO** pass `forcePretty: true` to `formatJSON()` when the user explicitly passes `--json` (they expect pretty-printed output)
42-
- **DO** use `isAgentContext()` from `src/helpers/output.ts` to decide whether auto-JSON applies in commands with both human-readable and JSON modes
41+
- **DO** pass `forcePretty: true` to `formatJSON()` when the user explicitly requests pretty JSON
42+
- **DO** use `isAgentContext()` to decide whether auto-JSON applies in commands with both human-readable and JSON modes
4343
- **DO** use `console.log()` for normal output to stdout and `logError()` for errors to stderr
4444
- **DO** project records down to identity fields in enumeration commands — pair a lean `list` with a full-detail `show` so agents can drill down
4545
- **DO** keep output concise and scannable
@@ -48,8 +48,9 @@ CLI output must be readable for humans and parseable for machines: colored in te
4848
### Don't
4949

5050
- **DON'T** use emoji in CLI output
51-
- **DON'T** use raw ANSI escape codes or third-party color libraries (chalk, kleur, picocolors) — `styleText` covers both needs
52-
- **DON'T** include colors in `--json` output
51+
- **DON'T** use raw ANSI escape codes or third-party color libraries (chalk, kleur, picocolors)
52+
- **DON'T** include colors in `json`/`github`/`sarif` output
53+
- **DON'T** auto-detect `github`/`sarif`; only `json` auto-upgrades
5354
- **DON'T** output progress spinners without a TTY check
5455
- **DON'T** use `JSON.stringify()` directly in command files — use `formatJSON()` so agent-context detection stays consistent
5556
- **DON'T** serialize a parsed record verbatim just because it's in hand (`.map((a) => a.frontmatter)`) — project it to the fields the consumer actually needs
@@ -68,17 +69,26 @@ console.log(styleText(["red", "bold"], "error:")); // combined styles
6869
```
6970

7071
```typescript
71-
// Agent-aware JSON output — auto-compact for agents, pretty for humans
72+
// check.ts: --output <format> selector (console/json/github/sarif) —
73+
// wins outright when given; omitted defaults to console, auto-upgrading
74+
// to compact json in agent context. github/sarif are opt-in only.
7275
import { formatJSON, isAgentContext } from "../helpers/output";
7376

74-
const useJson = opts.json || isAgentContext();
75-
if (opts.ci) {
76-
reportCI(results);
77-
} else if (useJson) {
78-
// forcePretty=true when explicit --json, auto-detect otherwise
79-
console.log(formatJSON(results, opts.json ? true : undefined));
77+
const outputFormat = opts.output ?? (isAgentContext() ? "json" : "console");
78+
if (outputFormat === "sarif") {
79+
reportSarif(result, summary);
80+
} else if (outputFormat === "github") {
81+
reportCI(result, summary);
82+
} else if (outputFormat === "json") {
83+
// forcePretty=true only for explicit --output json, auto-detect otherwise
84+
reportJSON(result, opts.output === "json" ? true : undefined, summary);
8085
} else {
81-
reportConsole(results);
86+
reportConsole(result, verbose, summary);
87+
}
88+
89+
// Plain --json flag on simpler commands (adr list/sync/import):
90+
if (opts.json || isAgentContext()) {
91+
console.log(formatJSON(results, opts.json ? true : undefined));
8292
}
8393

8494
// Always-JSON commands (review-context, session-context): just call formatJSON
@@ -134,7 +144,7 @@ console.log(JSON.stringify(results, null, 2));
134144
- **Bun `styleText` compatibility gaps** — Bun implements `node:util` but may lag Node.js on new `styleText` features or options.
135145
- **Mitigation:** The CLI uses basic styles (red, green, yellow, bold, dim) that are stable in both runtimes. Avoid experimental or newly added style formats.
136146
- **TTY detection edge cases**`styleText` disables colors for non-TTY output, but some CI environments (GitHub Actions) report as TTY and then log raw ANSI codes.
137-
- **Mitigation:** `--json` bypasses all color formatting. CI integrations should use `--json` or `--ci` for structured output.
147+
- **Mitigation:** `json`/`github`/`sarif` output bypasses all color formatting. CI integrations should use `--output json`/`github`/`sarif` (or `--json` on simpler commands) for structured output.
138148

139149
## Compliance and Enforcement
140150

@@ -147,15 +157,18 @@ console.log(JSON.stringify(results, null, 2));
147157

148158
Code reviewers MUST verify:
149159

150-
1. New commands support `--json` when they output structured data
160+
1. New commands support `--output <format>` or `--json` when they output structured data
151161
2. No third-party color libraries are imported
152162
3. Error messages go to stderr (via `logError()`), results go to stdout
153-
4. Enumeration commands emit identity fields only, and every emitted field earns its place. Payload size is not statically checkable, so reviewers MUST sanity-check `--json` output against a realistic record count (dozens, not the two-ADR fixture) rather than trusting a small test project
163+
4. Enumeration commands emit identity fields only, and every emitted field earns its place. Payload size is not statically checkable, so reviewers MUST sanity-check `--json`/`--output json` output against a realistic record count (dozens, not the two-ADR fixture) rather than trusting a small test project
164+
5. `check`'s `--json`/`--ci``--output <format>` migration is the reference precedent for any future flag-to-`--output`-style unification — a new machine-readable format on an existing command should extend `--output`'s choices, not add another boolean flag
154165

155166
## References
156167

157168
- [Node.js styleText documentation](https://nodejs.org/api/util.html#utilstyletextformat-text-options)
158169
- [Bun node:util support](https://bun.sh/docs/runtime/nodejs-apis#node-util)
159170
- [NO_COLOR convention](https://no-color.org/)
171+
- [SARIF 2.1.0 specification](https://docs.oasis-open.org/sarif/sarif/v2.1.0/sarif-v2.1.0.html) — schema `--output sarif` implements
172+
- [GitHub Code Scanning SARIF support](https://docs.github.com/en/code-security/code-scanning/integrating-with-code-scanning/sarif-support-for-code-scanning) — consumer of `--output sarif`
160173
- [ARCH-002 — Error Handling](./ARCH-002-error-handling.md) — Defines stderr convention for error output
161174
- [ARCH-006 — Dependency Policy](./ARCH-006-dependency-policy.md) — Justifies avoiding chalk/kleur/picocolors

0 commit comments

Comments
 (0)