Files
accounted/.github/workflows/core-build.yml
T
Jakob Wennberg 4e20c9dec4 fix(import): bulk-confirm the VAT-treatment review gate in account mapping (#1723)
* fix(import): bulk-confirm the VAT-treatment review gate in account mapping

A Fortnox chart routinely puts 70+ class 3/4 accounts behind the
vat-treatment review gate, and the only way through was one Bekräfta
click per row across paginated 50-row pages. A live migration
(2026-08-18) died exactly there, stuck at 50 kvar with Continue
disabled and no way to see why.

One outline button next to Continue now accepts the suggested default
for every remaining row, with the exact semantics of the per-row
button batched (defaults kept, rows marked reviewed). Wired in both
the import wizard and the Arcim migration workspace. Strings in sv+en.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>

* fix(guards): two naive-ore-rounds that stacked past the ratchet baseline

#1700 and #1705 each added one Math.round(x*100)/100 and each passed
CI alone against baseline 630; the first branch containing both trips
the ratchet at 631. Convert both to roundOre (629, below baseline).

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>

* fix: place the roundOre import on its own line

The previous commit inserted it inside a multi-line import block,
breaking parsing in pdf-template.tsx.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>

* ci: give next build an explicit 8 GB heap

The build worker OOMs on the runner's default Node heap since the
bundle crossed the default old-space ceiling (first branch containing
all of 2026-08-19's merges). Public-repo runners have 16 GB.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>

---------

Co-authored-by: Jakob Wennberg <311770904+jakobwennberg-oss@users.noreply.github.com>
Co-authored-by: Claude Fable 5 <noreply@anthropic.com>
2026-08-19 21:26:04 +02:00

172 lines
7.8 KiB
YAML

name: Core Build (no extensions)
# Split out of a single serial job that took 7m43s wall-clock: npm ci 24s, lint
# ratchet 1m29s, build 2m00s, unit tests 3m31s, ratchets ~10s. None of those
# stages needed the previous one's output, so they were serial only by
# accident. Running them as independent jobs (and sharding the 897-file unit
# suite four ways) puts the critical path on `build` at roughly 2m30s.
#
# The prologue each job needs is in .github/actions/setup-core.
on: [pull_request]
# Six concurrent jobs per push makes stale runs far more expensive than they
# were when this was one job, and a superseded push has nothing worth finishing.
concurrency:
group: core-build-${{ github.ref }}
cancel-in-progress: true
permissions:
contents: read
jobs:
checks:
name: Checks
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # v7
with:
# Nothing here pushes, so leaving the token in .git/config only widens
# what a compromised dependency in the build could reach.
persist-credentials: false
- uses: ./.github/actions/setup-core
- name: Verify skill bodies are in sync with the seed migration
# Fails if a .claude/skills/**/SKILL.md changed without regenerating the
# seed migration (npm run skills:generate). Keeps prod skill content from
# silently drifting out of sync. No DB needed: reads files + manifest.
run: npm run skills:check
- name: Verify taxonomy registry is in sync with the element lists
# Fails if dev_docs/bokslut/taxonomi/** changed without regenerating
# lib/bokslut/ixbrl/taxonomy/generated/ (npm run taxonomy:generate).
# The iXBRL generator emits facts strictly from the generated registry,
# so drift here means filings tagged against a stale concept set.
run: npm run taxonomy:check
- name: Verify the accounted-api agent skill is in sync with the registry
# Fails if a v1 endpoint / registry schema / overlay changed without
# regenerating skills/accounted-api (npm run apiskill:generate). The
# skill is the installable API reference for external coding agents;
# drift here means agents integrate against stale endpoint contracts.
run: npm run apiskill:check
- name: Lint ratchet (no new ESLint errors)
# `npm run lint` was never wired into CI, so ~60 legacy errors
# accumulated. This ratchet (sibling of check:guards) fails only when
# a PR ADDS an error beyond scripts/checks/eslint-baseline.json; the
# baseline ratchets down as legacy errors get fixed.
run: npm run check:lint
- name: Antipattern ratchet (no new MFA-bypassing routes / naive öre-rounding)
# Fails only if a PR ADDS a route that hand-rolls supabase.auth.getUser()
# instead of the MFA-enforcing guard, or a new Math.round(x*100)/100.
# Baseline lives in scripts/checks/antipatterns-baseline.json and ratchets
# down as the A1 (route auth) and D1 (rounding) migrations land.
run: npm run check:guards
- name: Validate konteringspaket catalogue
# The system booking templates are data files under packs/ rather than
# rows frozen inside a migration. This gate is what makes that safe: it
# checks the schema, that every BAS account actually exists in the 2026
# chart, and that each pack BALANCES when applied through the real
# applyTemplate(). PR #1321 shipped seeded reference data that
# contradicted the engine; that class of bug is structurally valid and
# only a semantic check catches it.
run: npm run validate:packs
- name: Validate community registry
# registry/ is the public source of truth for gnubok.se/community/registry
# and takes entries by PR from outside the team. The gate checks the
# frontmatter the website build consumes, and rejects JSX/import/export
# in entry bodies: the site renders bodies through MDX, which would
# execute those at build time.
run: npm run validate:registry
- name: Check no core imports from extensions
run: |
VIOLATIONS=$(grep -r "from '@/extensions/" lib/ app/api/ components/ --include="*.ts" --include="*.tsx" \
| grep -v "app/api/extensions/" \
| grep -v "components/extensions/" \
| grep -v "lib/extensions/_generated/" \
| grep -v "lib/extensions/loader.ts" || true)
if [ -n "$VIOLATIONS" ]; then
echo "ERROR: Core code imports from @/extensions/:"
echo "$VIOLATIONS"
exit 1
fi
build:
name: Build (zero extensions)
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # v7
with:
# Nothing here pushes, so leaving the token in .git/config only widens
# what a compromised dependency in the build could reach.
persist-credentials: false
- uses: ./.github/actions/setup-core
- run: npm run build
env:
# The Next.js build worker OOMs on the runner's default Node heap
# since 2026-08-19 (bundle growth crossed the default old-space
# ceiling; the first branch containing the whole day's merges was the
# first to hit it). Public-repo runners have 16 GB, give the build 8.
NODE_OPTIONS: --max-old-space-size=8192
test:
# 897 unit test files (11,341 tests) take 3m31s in one process. Measured
# locally, four shards split them 225/224/224/224 with the slowest at 64s,
# which puts this comfortably under the build job so it stops being the
# critical path. Vitest hard-errors when the shard count exceeds the
# resolved file count, which is nowhere near a concern at this size.
name: Unit tests (${{ matrix.shard }}/4)
runs-on: ubuntu-latest
strategy:
# One shard failing should not hide failures in the other three: a red PR
# is more useful when it lists every broken test, not just the first.
fail-fast: false
matrix:
shard: [1, 2, 3, 4]
steps:
- uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # v7
with:
# Nothing here pushes, so leaving the token in .git/config only widens
# what a compromised dependency in the build could reach.
persist-credentials: false
- uses: ./.github/actions/setup-core
# Via env rather than interpolated straight into the shell body: the value
# is a static matrix integer and harmless, but keeping every `run:` free of
# ${{ }} is the rule that makes the template-injection audit meaningful.
- run: npm test -- --shard="$SHARD/4"
env:
SHARD: ${{ matrix.shard }}
core-build:
# One stable check name covering all six jobs above, so the PR checks list
# (and any future required-status-check rule) has a single thing to read
# rather than a shard-numbered matrix. `needs` alone would not be enough:
# a needed job that is skipped or cancelled does not fail its dependents,
# so the results are asserted explicitly.
name: Core Build
if: always()
needs: [checks, build, test]
runs-on: ubuntu-latest
steps:
- name: Assert every core job succeeded
env:
CHECKS: ${{ needs.checks.result }}
BUILD: ${{ needs.build.result }}
TEST: ${{ needs.test.result }}
run: |
set -euo pipefail
echo "checks=$CHECKS build=$BUILD test=$TEST"
failed=0
for r in "$CHECKS" "$BUILD" "$TEST"; do
[ "$r" = "success" ] || failed=1
done
if [ "$failed" -ne 0 ]; then
echo "::error::One or more core-build jobs did not succeed"
exit 1
fi