Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
6 changes: 6 additions & 0 deletions .editorconfig
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
root = true

[*]
charset = utf-8
end_of_line = lf
insert_final_newline = true
7 changes: 5 additions & 2 deletions .githooks/pre-commit
Original file line number Diff line number Diff line change
@@ -1,6 +1,9 @@
#!/usr/bin/env sh
set -eu

"$(dirname "$0")/require-continuity.sh"
hook_dir=${0%/*}

exec "$(dirname "$0")/run-validate.sh" all
"$hook_dir/require-continuity.sh"
node "$hook_dir/../scripts/check-text-conventions.mjs"

exec "$hook_dir/run-validate.sh" precommit
4 changes: 3 additions & 1 deletion .githooks/pre-merge-commit
Original file line number Diff line number Diff line change
@@ -1,4 +1,6 @@
#!/usr/bin/env sh
set -eu

exec "$(dirname "$0")/run-validate.sh" full
hook_dir=${0%/*}

exec "$hook_dir/run-validate.sh" full
8 changes: 7 additions & 1 deletion .githooks/pre-push
Original file line number Diff line number Diff line change
@@ -1,4 +1,10 @@
#!/usr/bin/env sh
set -eu

exec "$(dirname "$0")/run-validate.sh" full
hook_dir=${0%/*}

if [ "${RUN_FULL_VALIDATION_ON_PUSH:-0}" = "1" ]; then
exec "$hook_dir/run-validate.sh" full
fi

exec "$hook_dir/run-validate.sh" prepush
1 change: 1 addition & 0 deletions .prettierrc
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
{
"semi": true,
"singleQuote": false,
"endOfLine": "lf",
"trailingComma": "all"
}
2 changes: 1 addition & 1 deletion AGENTS.md
Original file line number Diff line number Diff line change
Expand Up @@ -40,7 +40,7 @@ pnpm test; pnpm run lint

TypeScript 5.9 on Next.js 16 App Router (React 19): Follow standard conventions

- Repository text files use UTF-8 encoding (UTF-8 with or without BOM)
- Repository text files use UTF-8 encoding without BOM and LF (`\n`) line endings

## Recent Changes

Expand Down
26 changes: 16 additions & 10 deletions CONTINUE.md
Original file line number Diff line number Diff line change
@@ -1,32 +1,38 @@
# Continue

<!-- continuity:fingerprint=c60c207709f1635bb984a3f99c674da37d6907d780c2b1e2321a129e907e6d15 -->
<!-- continuity:fingerprint=bce7c5190f15dcacfdb95670101b8335064447a6c5e1d221d6cdb932887410b1 -->

## Current Snapshot

- Updated: 2026-06-20 15:56:22
- Updated: 2026-06-21 20:34:43
- Branch: `main`

## Recent Non-Continuity Commits

- 115543e feat: add exception-aware supply-chain audit
- 5f786d8 chore: refresh specs overview
- 8492b6b feat: add ops health dashboard (#5)
- 8047615 feat: expose runtime build metadata (#4)
- 6c81729 feat: add azure deployment smoke verification (#3)
- 3d52264 fix: move state queue logging to dedicated resource

## Git Status

- Porting rag-agent-style supply-chain audit coverage into this repo.
- Added app/worker dependency-audit Docker targets, exception registry/docs, and dependency audit evidence inside `scripts/supply-chain-audit.ps1`.
- Local verification passed for script smoke, host `pnpm audit` parsing, and host worker `uv audit`; Docker image-context scans are currently blocked because the local Docker daemon is unavailable.
- M .githooks/pre-merge-commit
- M .githooks/pre-push
- M CONTINUE.md
- M CONTINUE_LOG.md
- M README.md
- M eslint.config.mjs
- M package.json
- M scripts/check-text-conventions.mjs
- M specs/OVERVIEW.md
- M validate.ps1

## Active Specs

- None
- No active spec folders detected.

## Next Recommended Actions

1. Re-run `pnpm run supply-chain:audit` or `.\validate.ps1 full` with Docker available.
2. Review and commit the supply-chain audit port.
3. Watch CI validation for the Docker-backed image-context audits.
1. Commit and push CI fixes for PR #6 (`prettier`, `spec-overview`).
2. No unchecked tasks detected in the active specs.
35 changes: 35 additions & 0 deletions CONTINUE_LOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -1579,3 +1579,38 @@
- Validation passed: focused ops unit/integration tests, focused ops Playwright tests, `.\validate.ps1 quality`, `.\validate.ps1 all`, and `.\validate.ps1 full` including Trivy/container scans and full Playwright E2E.
- Active specs: `021-ops-health-dashboard` implemented and validated; PR cleanup remains.
- Next focus: commit, push, open a PR, and confirm GitHub validation.

## 2026-06-21 18:00:22

- Branch snapshot refreshed for `main`.
- Latest non-continuity commit: 115543e feat: add exception-aware supply-chain audit.
- Active specs: none.
- Next focus: no next task.

## 2026-06-21 18:21:00

- Branch snapshot refreshed for `main`.
- Latest non-continuity commit: 115543e feat: add exception-aware supply-chain audit.
- Active specs: none.
- Next focus: no next task.

## 2026-06-21 20:13:32

- Added repository-wide UTF-8/LF guidance in `AGENTS.md`.
- Added `.editorconfig` defaults for UTF-8, LF, and final newlines.
- Set Prettier `endOfLine` to `lf`; existing `.gitattributes` already normalizes text files to LF.
- Verified touched convention files have no BOM and no CRLF line endings.

## 2026-06-21 20:15:38

- Added `scripts/check-text-conventions.mjs` to validate staged text files for UTF-8 without BOM and LF line endings.
- Wired the text convention check into `.githooks/pre-commit` before validation.
- Added `pnpm run check:text` for manual invocation.
- Verification passed: `pnpm run check:text` and `node --check scripts/check-text-conventions.mjs`.

## 2026-06-21 20:34:43

- Checked GitHub CI for PR #6; `Validate / validate` failed on `prettier` and `spec-overview`.
- Ran Prettier on `CONTINUE.md`, `CONTINUE_LOG.md`, and `scripts/check-text-conventions.mjs`.
- Regenerated `specs/OVERVIEW.md` with `pnpm run specs:overview:update`.
- Focused verification passed: `pnpm run check:text` and Prettier check for the affected files.
13 changes: 11 additions & 2 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -64,6 +64,8 @@ Guidelines:
## Validation

```powershell
.\validate.ps1 precommit
.\validate.ps1 prepush
.\validate.ps1 all
.\validate.ps1 e2e
.\validate.ps1 full
Expand All @@ -79,6 +81,11 @@ testing. Set an explicit `DATABASE_URL=file:./e2e.db` only when you intentionall
need the legacy SQLite E2E path. Set `E2E_REUSE_SERVER=1` only when you are not
resetting the database between runs.

`precommit` is the fast local hook phase: TypeScript typecheck,
dependency-cruiser architecture, and jscpd duplication.
`prepush` is the medium local hook phase: ESLint complexity/function-size
ratchets plus Python quality/complexity checks. Set
`RUN_FULL_VALIDATION_ON_PUSH=1` to run `full` before pushing instead.
`all` includes TypeScript, Python, and CLI quality checks plus dependency cooldown
validation for pnpm and uv support.
`full` also runs the Trivy supply-chain audit gate before production dependency
Expand All @@ -92,8 +99,9 @@ pnpm run quality:python
pnpm run quality:cli
```

`quality:ts` runs blocking ESLint complexity, SonarJS cognitive-complexity, and
jscpd duplication thresholds plus dependency-cruiser import-cycle analysis.
`quality:ts` runs blocking ESLint complexity, SonarJS cognitive-complexity,
function-size, and jscpd duplication thresholds plus dependency-cruiser
import-cycle analysis.
`quality:python` runs Ruff plus blocking Xenon and complexipy complexity
thresholds with Radon reporting for the worker package.
`quality:cli` runs Go formatting checks, `go vet`, Staticcheck, a blocking
Expand All @@ -104,6 +112,7 @@ regressions by default:

- TypeScript cyclomatic complexity: 56
- TypeScript cognitive complexity: 24
- TypeScript function size: 520 nonblank, non-comment lines
- Python Xenon: max absolute F, max module C, max average B
- Python Radon cyclomatic complexity: 44
- Python complexipy cognitive complexity: 46
Expand Down
10 changes: 10 additions & 0 deletions eslint.config.mjs
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@ const thresholdSeverity =
process.env.QUALITY_THRESHOLDS_BYPASS === "1" ? "warn" : "error";
const maxCyclomaticComplexity = 56;
const maxCognitiveComplexity = 24;
const maxFunctionLines = 520;

const config = [
{
Expand All @@ -30,6 +31,15 @@ const config = [
},
rules: {
complexity: [thresholdSeverity, { max: maxCyclomaticComplexity }],
"max-lines-per-function": [
thresholdSeverity,
{
max: maxFunctionLines,
skipBlankLines: true,
skipComments: true,
IIFEs: true,
},
],
"sonarjs/cognitive-complexity": [
thresholdSeverity,
maxCognitiveComplexity,
Expand Down
3 changes: 3 additions & 0 deletions package.json
Original file line number Diff line number Diff line change
Expand Up @@ -20,16 +20,19 @@
"quality:ts": "pnpm run lint && pnpm run architecture && pnpm run duplication",
"quality:python": "node scripts/check-python-quality.mjs",
"quality:cli": "node scripts/check-cli-quality.mjs",
"check:text": "node scripts/check-text-conventions.mjs",
"logging:guard": "node scripts/check-logging-guard.mjs",
"smoke:azure": "node scripts/run-azure-deploy-smoke.mjs",
"supply-chain:audit": "pwsh -NoProfile -ExecutionPolicy Bypass -File scripts/supply-chain-audit.ps1",
"validate:runtime-credentials": "pwsh -NoProfile -ExecutionPolicy Bypass -File scripts/validate-runtime-credentials.ps1 -SelfTest",
"validate:precommit": "pwsh -NoProfile -ExecutionPolicy Bypass -File validate.ps1 precommit",
"worker:lint": "cd worker && uv run ruff check src tests",
"worker:complexity": "node scripts/check-python-quality.mjs --complexity-only",
"semgrep": "semgrep scan --error --config auto --config .semgrep.yml",
"continuity:update": "node scripts/update-continuity.mjs",
"specs:overview:update": "node scripts/update-spec-overview.mjs",
"specs:overview:check": "node scripts/update-spec-overview.mjs --check",
"validate:prepush": "pwsh -NoProfile -ExecutionPolicy Bypass -File validate.ps1 prepush",
"validate": "pnpm run validate:runtime-credentials && pnpm run typecheck && pnpm run quality:ts && pnpm run quality:python && pnpm run quality:cli && pnpm run logging:guard && pnpm run semgrep && pnpm run test",
"validate:full": "pnpm run validate && pnpm run test:e2e",
"template:stamp": "node scripts/stamp-template-origin.mjs",
Expand Down
81 changes: 81 additions & 0 deletions scripts/check-text-conventions.mjs
Original file line number Diff line number Diff line change
@@ -0,0 +1,81 @@
#!/usr/bin/env node
import { execFileSync } from "node:child_process";
import { TextDecoder } from "node:util";

const utf8Decoder = new TextDecoder("utf-8", { fatal: true });

function git(args, options = {}) {
return execFileSync("git", args, {
maxBuffer: 100 * 1024 * 1024,
...options,
});
}

function getStagedFiles() {
const output = git(
["diff", "--cached", "--name-only", "-z", "--diff-filter=ACMR"],
{ encoding: "buffer" },
);

return output.toString("utf8").split("\0").filter(Boolean);
}

function getStagedBlob(path) {
return git(["show", `:${path}`], { encoding: "buffer" });
}

function isBinary(buffer) {
return buffer.includes(0);
}

function hasUtf8Bom(buffer) {
return (
buffer.length >= 3 &&
buffer[0] === 0xef &&
buffer[1] === 0xbb &&
buffer[2] === 0xbf
);
}

function validateTextBlob(path, buffer) {
const failures = [];

if (hasUtf8Bom(buffer)) {
failures.push("UTF-8 BOM");
}

let text = "";
try {
text = utf8Decoder.decode(buffer);
} catch {
failures.push("invalid UTF-8");
}

if (text.includes("\r")) {
failures.push("CRLF/CR line endings");
}

return failures.map((failure) => `${path}: ${failure}`);
}

const failures = [];

for (const path of getStagedFiles()) {
const buffer = getStagedBlob(path);

if (isBinary(buffer)) {
continue;
}

failures.push(...validateTextBlob(path, buffer));
}

if (failures.length > 0) {
console.error(
"Text convention check failed. Use UTF-8 without BOM and LF line endings.",
);
for (const failure of failures) {
console.error(`- ${failure}`);
}
process.exit(1);
}
2 changes: 1 addition & 1 deletion specs/OVERVIEW.md
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
# Business App Starter Specs Overview

Last Updated: 2026-06-20
Last Updated: 2026-06-21

Purpose: Track the status of all planned features, their implementation progress, and next steps.

Expand Down
16 changes: 9 additions & 7 deletions validate.ps1
Original file line number Diff line number Diff line change
Expand Up @@ -6,9 +6,11 @@
.DESCRIPTION
Usage: ./validate.ps1 [phase]
Phases:
all - typecheck + TS/Python/CLI quality + semgrep + test (default, pre-commit)
all - typecheck + TS/Python/CLI quality + semgrep + test (default)
full - all quality checks + Trivy supply-chain audit + shipped-deps audit + Playwright E2E tests (recommended before merge; skips continuity freshness)
continuity - check whether CONTINUE.md / CONTINUE_LOG.md need a refresh
precommit - fast local sanity: TS typecheck + architecture + duplication
prepush - medium local gate: ESLint ratchets + Python quality/complexity
quick - typecheck only (use during scaffolding before tests exist)
test - tests only
e2e - Playwright E2E tests only
Expand All @@ -21,7 +23,7 @@
#>

param(
[ValidateSet("all", "full", "continuity", "quick", "test", "e2e", "quality", "commit")]
[ValidateSet("all", "full", "continuity", "precommit", "prepush", "quick", "test", "e2e", "quality", "commit")]
[string]$Phase = "all"
)

Expand Down Expand Up @@ -902,7 +904,7 @@ function Get-AuditPackageStatuses($audit) {

$failures = @()

if ($Phase -in "all", "full", "quick", "commit") {
if ($Phase -in "all", "full", "precommit", "quick", "commit") {
Write-Step "Typecheck (tsc --noEmit)"
try {
$exitCode = Invoke-NativeCommand "pnpm run typecheck"
Expand Down Expand Up @@ -934,7 +936,7 @@ if ($Phase -in "all", "full", "quick", "commit") {
}
}

if ($Phase -in "all", "full", "quality", "commit") {
if ($Phase -in "all", "full", "prepush", "quality", "commit") {
Write-Step "Lint (eslint)"
try {
$result = Invoke-NativeCommandCaptured "pnpm run lint"
Expand Down Expand Up @@ -1005,7 +1007,7 @@ if ($Phase -in "all", "full", "quality", "commit") {
}
}

if ($Phase -in "all", "full", "quality", "commit") {
if ($Phase -in "all", "full", "precommit", "quality", "commit") {
Write-Step "Architecture (dependency-cruiser)"
try {
$result = Invoke-NativeCommandCaptured "pnpm run architecture"
Expand All @@ -1032,7 +1034,7 @@ if ($Phase -in "all", "full", "quality", "commit") {
}
}

if ($Phase -in "all", "full", "quality", "commit") {
if ($Phase -in "all", "full", "precommit", "quality", "commit") {
Write-Step "Duplication (jscpd)"
try {
$threshold = Get-DuplicationThreshold
Expand Down Expand Up @@ -1067,7 +1069,7 @@ if ($Phase -in "all", "full", "quality", "commit") {
}
}

if ($Phase -in "all", "full", "quality", "commit") {
if ($Phase -in "all", "full", "prepush", "quality", "commit") {
Write-Step "Python quality (ruff, xenon, radon, complexipy)"
try {
$result = Invoke-NativeCommandCaptured "pnpm run quality:python"
Expand Down