@starci/hfs 4.7.27 → 4.7.29
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/CHANGELOG.md +17 -0
- package/README.md +9 -3
- package/package.json +7 -1
- package/release/candidate-ci.mjs +3 -21
- package/runtime/engine/yaml.mjs +1 -1
- package/runtime/knowledge/hfs/canon-pins.yaml +6 -6
- package/runtime/knowledge/hfs/rules.yaml +913 -637
- package/runtime/knowledge/hfs/slots.yaml +21 -14
- package/runtime/modules/kernel/failure-codes.yaml +10 -0
- package/runtime/packages/cli/src/catalog.generated.mjs +146 -58
- package/runtime/scripts/api/git/check-ignore.mjs +5 -0
- package/runtime/scripts/gates/runtime-host.mjs +83 -0
- package/runtime/scripts/gates/sonar-gate.mjs +251 -0
- package/runtime/scripts/gates/starcistacks-ci.mjs +55 -0
- package/runtime/scripts/gates/starcistacks-form.mjs +26 -0
- package/runtime/scripts/gates/starcistacks-runtime.mjs +2 -0
- package/runtime/scripts/gates/starcistacks-value-file.mjs +17 -0
- package/runtime/scripts/gates/starcistacks.mjs +499 -0
- package/runtime/scripts/hfs/app-wiring.mjs +2 -2
- package/runtime/scripts/hfs/architecture/supabase.mjs +1 -1
- package/runtime/scripts/hfs/check.mjs +4 -1
- package/runtime/scripts/hfs/coverage-from.mjs +1 -1
- package/runtime/scripts/hfs/manifest-shape.mjs +1 -3
- package/runtime/scripts/hfs/rule-catalog.mjs +7 -10
- package/runtime/scripts/hfs/rules/a15-findings.mjs +1 -1
- package/runtime/scripts/hfs/rules/assets.mjs +1 -1
- package/runtime/scripts/hfs/rules/bypass-markers.mjs +24 -0
- package/runtime/scripts/hfs/rules/frontend-tree.mjs +2 -2
- package/runtime/scripts/hfs/rules/supabase-secrets.mjs +1 -1
- package/runtime/scripts/lib/bypass-markers.mjs +116 -0
- package/runtime/scripts/lib/check-code-loosening.mjs +128 -0
- package/runtime/scripts/lib/example-refs.mjs +205 -0
- package/runtime/scripts/lib/failure-code-reads.mjs +100 -0
- package/runtime/scripts/lib/gate-loosening.mjs +52 -8
- package/runtime/scripts/lib/json-formats.mjs +34 -0
- package/runtime/scripts/lib/package-at.mjs +1 -1
- package/runtime/scripts/lib/properties.mjs +16 -0
- package/runtime/scripts/lib/provision-control-failure.mjs +32 -0
- package/runtime/scripts/lib/sonar-new-code.mjs +58 -0
- package/runtime/scripts/lib/starciwork-boundary.mjs +164 -0
- package/runtime/scripts/lib/work-edition.mjs +40 -0
- package/scaffold/app.mjs +3 -0
- package/scaffold/service.mjs +1 -1
- package/scaffold/test-world.mjs +125 -0
- package/src/main.mjs +1 -1
- package/sync/format.mjs +1 -1
- package/sync/hygiene.mjs +16 -4
- package/templates/app/hooks/husky/pre-commit +8 -7
- package/templates/be/test-world/e2e/serves-once-migrated.e2e-spec.ts.tpl +32 -0
- package/templates/be/test-world/fixtures/migrations.sql.ts.tpl +14 -0
- package/templates/be/test-world/integration/readiness.integration-spec.ts.tpl +28 -0
- package/templates/be/test-world/world/global-setup.ts.tpl +1 -0
- package/templates/be/test-world/world/global-teardown.ts.tpl +1 -0
- package/templates/be/test-world/world/test-apps.options.ts.tpl +62 -0
- package/templates/be/test-world/world/test-world.config.ts.tpl +20 -0
- package/templates/be/test-world/world/use-test-world.ts.tpl +2 -0
- package/upgrade/index.mjs +48 -9
package/CHANGELOG.md
CHANGED
|
@@ -1,5 +1,22 @@
|
|
|
1
1
|
# Changelog
|
|
2
2
|
|
|
3
|
+
## 4.7.29 - 2026-10-24
|
|
4
|
+
- Added: a new full app ships its test world (`scaffold/test-world.mjs`, `templates/be/test-world/`): the `@starci/test-world` declaration under `be/src/tests/world/`, an integration spec of readiness over the real database and one e2e spec per api app, so the integration, e2e and contract rows of the release gate run real specs.
|
|
5
|
+
- Added: `starci app upgrade [--plan]` on a full app without `be/src/tests/world/global-setup.ts` adds that world and the test devDependencies it lacks at canon pins, never overwriting a file (`HFS_UPGRADE_FILE_CONFLICT`); proven by `src/main.spec.mjs`.
|
|
6
|
+
- Changed: the bundled canon pins select zod 4.6.7 (GHSA-mrhx-c7xc-m3w5 is fixed in 4.6.6), @starci/cli 1.7.29, @starci/eslint-canon-be 3.4.37 and @starci/eslint-canon-fe 8.4.36.
|
|
7
|
+
|
|
8
|
+
## 4.7.28 - 2026-10-23
|
|
9
|
+
- Added: `scripts/lib/sonar-new-code.mjs` joins the bundled runtime copy (the New Code definition `starci sonar project ensure` sets), proven by `src/sonar-new-code.spec.mjs`.
|
|
10
|
+
- Fixed: the bundled gate-loosening detector no longer reads a quoted operand of a printed message as a ban-list row, nor the upkeep of an exception list the check stops reading as enforcement lost (`src/bypass-detector.spec.mjs`).
|
|
11
|
+
- Added: `scripts/lib/provision-control-failure.mjs` joins the bundled runtime copy, proven by `src/provision-control-failure.spec.mjs`.
|
|
12
|
+
- Changed: the bundled canon pins select @starci/cli 1.7.28, @starci/eslint-canon-be 3.4.36 and @starci/eslint-canon-fe 8.4.35.
|
|
13
|
+
- Changed: no check keeps a list of exceptions. The JSON a tool requires is declared once by format (`scripts/lib/json-formats.mjs`, bundled), the failure-code scanner no longer counts a literal the code only reads (`scripts/lib/failure-code-reads.mjs`, bundled), and a rule is proven by a package spec unless every enforcer it has runs only inside the runtime (`RUNTIME_ONLY_ENFORCERS`); the catalog keys `specNa`, `exampleNa` and the unreachable witness are gone.
|
|
14
|
+
- Added: the specs of the deleted runtime tests that prove bundled checkers, restored as package specs (`src/*.spec.mjs`, helpers in `src/helpers`, fixtures in `src/fixtures`), and fresh specs for R296-R301, the tree codes of R01/R03, R112 and R216.
|
|
15
|
+
- Changed: `scripts/gates/sonar-gate.mjs` and `scripts/gates/starcistacks.mjs` joined the bundled runtime copy, and a few exports the specs read are exported again.
|
|
16
|
+
- Changed: a red candidate CI never passes: `packages/hfs/release/candidate-ci.mjs` has no ci-override record any more (owner ruling 2026-10-22, a loosening is always red).
|
|
17
|
+
- Added: R303 `HFS_BYPASS_MARKER` in `starci app check` and the bypass guard of `starci app hygiene` (staged files read from the index): an inline disable of any tool, a type-check escape, a Sonar or coverage ignore, a skipped or focused test and a failure swallowed in a hook or workflow are refused in a product repository, the front end included.
|
|
18
|
+
- Changed: the managed `.husky/pre-commit` runs `starci app sync --check` and ends the hook when any step fails; the stylelint step can no longer be skipped by a failing run.
|
|
19
|
+
|
|
3
20
|
## 4.7.27 - 2026-10-23
|
|
4
21
|
- Fixed: the bundled `scripts/lib/managed-json.mjs` passes each slot path to `braceVariants` through an arrow, so `flatMap` never hands it an index (Sonar S7727).
|
|
5
22
|
- Changed: the bundled canon pins select @starci/cli 1.7.27, @starci/eslint-canon-be 3.4.34 and @starci/eslint-canon-fe 8.4.33.
|
package/README.md
CHANGED
|
@@ -61,6 +61,13 @@ unchanged lite tree through the full-edition view. The check is read-only; `--db
|
|
|
61
61
|
comparison when the local stack is available. Applying `starci app upgrade --edition full` adds the full-only managed configuration,
|
|
62
62
|
test layers and cli requirements without rewriting product code. Downgrade to lite is not supported.
|
|
63
63
|
|
|
64
|
+
A new full app ships its test world (`scaffold/test-world.mjs`): the `@starci/test-world` declaration under `be/src/tests/world/`
|
|
65
|
+
(the dev stack's Postgres per connection, the api apps, the cli app's migration runner as the migrate step), an integration spec of
|
|
66
|
+
readiness over the real database and one e2e spec per api app booted over the migrated database, beside the contract spec of the
|
|
67
|
+
be skeleton, so `test:integration`, `test:e2e` and `test:contract` of the release gate run real specs. On a full app that has no
|
|
68
|
+
`be/src/tests/world/global-setup.ts`, `starci app upgrade [--plan]` adds those files and the test devDependencies it lacks; a world
|
|
69
|
+
file that exists and differs refuses (`HFS_UPGRADE_FILE_CONFLICT`) and nothing is overwritten.
|
|
70
|
+
|
|
64
71
|
## Creating a service
|
|
65
72
|
|
|
66
73
|
Every file of a spec-required role of `ruleParams.be.unitRoles` — a `*.service.ts`, a `*.cli.ts` of the cli feature root — owes exactly one colocated `<name>.<role>.spec.ts` (unit test standard), and any other file of a `ruleParams.be.logicRoles` role inside a `coverage: required` slot may carry one beside it. `starci app new` is the one way a service and its spec come into being together:
|
|
@@ -187,10 +194,9 @@ derived from the machine's rule id lists). After changing any of those files, `k
|
|
|
187
194
|
`knowledge/hfs/canon-pins.yaml`, `knowledge/patterns/fe/folder.yaml` or the catalog entries of those codes, run `starci release sync-runtime`;
|
|
188
195
|
`starci release sync-runtime --check` fails on a stale copy. Bump `version` here and in the pin when the behaviour changes.
|
|
189
196
|
|
|
190
|
-
The examples
|
|
197
|
+
The examples workflow (`.github/workflows/examples.yml`) runs `starci app lint` of this CLI at the root of every `examples/*`
|
|
191
198
|
app with an `hfs.json` (each `examples/<app>` root) and fails on any finding or any tool that could not run;
|
|
192
|
-
`starci app check` alone would miss the machine's source rules, which the canons judge.
|
|
193
|
-
in each app.
|
|
199
|
+
`starci app check` alone would miss the machine's source rules, which the canons judge.
|
|
194
200
|
|
|
195
201
|
## Serving knowledge to other packages
|
|
196
202
|
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@starci/hfs",
|
|
3
|
-
"version": "4.7.
|
|
3
|
+
"version": "4.7.29",
|
|
4
4
|
"description": "The StarCi app command implementation for scaffolding, linting, checking and synchronizing one product repository.",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"license": "MIT",
|
|
@@ -15,6 +15,12 @@
|
|
|
15
15
|
"smol-toml": "1.9.0"
|
|
16
16
|
},
|
|
17
17
|
"devDependencies": {
|
|
18
|
+
"@nestjs/common": "11.2.5",
|
|
19
|
+
"@nestjs/core": "11.2.5",
|
|
20
|
+
"@nestjs/testing": "11.2.5",
|
|
21
|
+
"prettier": "3.9.6",
|
|
22
|
+
"reflect-metadata": "0.2.2",
|
|
23
|
+
"rxjs": "7.8.2",
|
|
18
24
|
"typescript": "5.9.3"
|
|
19
25
|
},
|
|
20
26
|
"files": [
|
package/release/candidate-ci.mjs
CHANGED
|
@@ -5,11 +5,8 @@
|
|
|
5
5
|
// red RELEASE_CANDIDATE_CI_RED (a run or a job that concluded skipped is red, never a pass: owner ruling 2026-10-22, a skip is a loosening) with the run URL and the failing jobs and steps; nothing reaches the default branch. The candidate ref stays for diagnosis
|
|
6
6
|
// timeout RELEASE_CANDIDATE_CI_TIMEOUT: no run listed within the grace (a queued run is listed), or it did not end within the wait
|
|
7
7
|
// unknown RELEASE_CI_UNKNOWN: GitHub could not be read to the end; a release never proceeds blind
|
|
8
|
-
//
|
|
9
|
-
// (<git common dir>/starci-release/<sha>.ci-override.json, schema starci/ci-override@1) lets a red candidate through, and the push says so.
|
|
8
|
+
// There is no override: a red candidate never passes (owner ruling 2026-10-22: a loosening is always red).
|
|
10
9
|
// Every process goes through ctx.spawn (git, gh); the wait through ctx.sleep and ctx.now.
|
|
11
|
-
import fs from 'node:fs';
|
|
12
|
-
import path from 'node:path';
|
|
13
10
|
|
|
14
11
|
const CANDIDATE_PREFIX = 'refs/heads/release/candidate-';
|
|
15
12
|
/** The wait of the candidate run: poll interval, the grace for a run to appear, the wait for it to end (an app's ci.yml jobs time out within 45 minutes). */
|
|
@@ -67,19 +64,6 @@ export function failingJobs(ctx, runRow) {
|
|
|
67
64
|
});
|
|
68
65
|
}
|
|
69
66
|
|
|
70
|
-
/** Only a complete starci/ci-override@1 record for this exact commit can excuse a red candidate. */
|
|
71
|
-
export function overrideOf(ctx, sha) {
|
|
72
|
-
if (!SHA.test(String(sha))) return null;
|
|
73
|
-
const common = run(ctx, 'git', ['rev-parse', '--git-common-dir']);
|
|
74
|
-
if (common.error || common.status !== 0 || !String(common.stdout ?? '').trim()) return null;
|
|
75
|
-
const file = path.join(path.resolve(ctx.cwd, String(common.stdout).trim()), 'starci-release', `${sha}.ci-override.json`);
|
|
76
|
-
try {
|
|
77
|
-
const record = JSON.parse(fs.readFileSync(file, 'utf8'));
|
|
78
|
-
if (record.schema !== 'starci/ci-override@1' || record.sha !== sha || typeof record.reason !== 'string' || !record.reason.trim() || typeof record.by !== 'string' || !record.by.trim() || typeof record.at !== 'string' || !Number.isFinite(Date.parse(record.at))) return null;
|
|
79
|
-
return record;
|
|
80
|
-
} catch { return null; }
|
|
81
|
-
}
|
|
82
|
-
|
|
83
67
|
/** Poll the candidate run of `sha` until green or red, or the grace (no run) or the wait passes: {state: green|red|timeout|unstarted|unknown, run}. */
|
|
84
68
|
export async function waitForCandidate(ctx, sha, wait = CANDIDATE_WAIT) {
|
|
85
69
|
const started = ctx.now();
|
|
@@ -96,8 +80,8 @@ export async function waitForCandidate(ctx, sha, wait = CANDIDATE_WAIT) {
|
|
|
96
80
|
}
|
|
97
81
|
|
|
98
82
|
/**
|
|
99
|
-
* The candidate step of the push: push HEAD to the candidate ref (through the pre-push hook), wait for its CI. {ok, lines, data: {ref, state, run, failing
|
|
100
|
-
* ok only on green
|
|
83
|
+
* The candidate step of the push: push HEAD to the candidate ref (through the pre-push hook), wait for its CI. {ok, lines, data: {ref, state, run, failing}}.
|
|
84
|
+
* ok only on green.
|
|
101
85
|
*/
|
|
102
86
|
export async function candidateStep(ctx, { head, tag, prefix, remote, wait = CANDIDATE_WAIT }) {
|
|
103
87
|
const ref = candidateRef(tag, prefix);
|
|
@@ -110,9 +94,7 @@ export async function candidateStep(ctx, { head, tag, prefix, remote, wait = CAN
|
|
|
110
94
|
if (seen.state === 'green') return { ok: true, lines: [...lines, `candidate CI green${url}`], data: { ref, state: 'green', run: seen.run } };
|
|
111
95
|
if (seen.state === 'red') {
|
|
112
96
|
const failing = failingJobs(ctx, seen.run);
|
|
113
|
-
const record = overrideOf(ctx, head);
|
|
114
97
|
const detail = failing.length ? failing.join('; ') : 'the failing jobs could not be read';
|
|
115
|
-
if (record) return { ok: true, lines: [...lines, `candidate CI RED${url}; failing: ${detail}`, `RELEASE_CANDIDATE_CI_RED overridden by the owner (${record.by}): ${record.reason}`], data: { ref, state: 'red', run: seen.run, failing, override: { by: record.by, reason: record.reason, at: record.at } } };
|
|
116
98
|
return { ok: false, lines: [...lines, `RELEASE_CANDIDATE_CI_RED: the ci.yml run of ${head.slice(0, 10)} on ${ref} is red${url}; failing: ${detail}. Nothing reached the default branch; the candidate ref stays for diagnosis`], data: { ref, state: 'red', run: seen.run, failing } };
|
|
117
99
|
}
|
|
118
100
|
if (seen.state === 'unstarted') return { ok: false, lines: [...lines, `RELEASE_CANDIDATE_CI_TIMEOUT: no ci.yml run started for ${head.slice(0, 10)} on ${ref} within ${wait.graceMinutes} minutes (does .github/workflows/ci.yml trigger on release/candidate-*? run starci app sync)`], data: { ref, state: 'unstarted' } };
|
package/runtime/engine/yaml.mjs
CHANGED
|
@@ -4,7 +4,7 @@
|
|
|
4
4
|
// rather than importing node_modules; yaml is a devDependency and a direct import breaks that
|
|
5
5
|
// install. tests/engine/yaml-vendored-parity.spec.mjs proves the vendored parseYaml/stringifyYaml behave
|
|
6
6
|
// exactly like yaml@2.9.0 with these options for every tracked *.yaml/*.yml file (parsed values
|
|
7
|
-
// deep-equal, stringify output byte-identical). License: engine/yaml-license.
|
|
7
|
+
// deep-equal, stringify output byte-identical). License: engine/yaml-license.yaml.
|
|
8
8
|
// Rebuild only when deliberately upgrading yaml. The entry source is:
|
|
9
9
|
// import * as YAML from 'yaml';
|
|
10
10
|
// export function parseYaml(source) {
|
|
@@ -29,14 +29,14 @@ pins:
|
|
|
29
29
|
source: packages/grammar/package.json
|
|
30
30
|
why: 'the grammar front ends read: the brand layer sets `--font-sans` and `--font-mono` and the grammar reads them; it carries the Input tel kind, the copyable and read-only Input, the IconButton disclosure props and count badge, ChatBubble, FillViewport, Textarea mentions and Enter-to-send, the leading PrimaryRailLayout rail, the plate-less Image, ListRow, the soft Alert, Progress steps, the floating primary IconButton, FlowGraph, the STATE-8 loading views and the bordered selectable TagGroup chips. The runtime source version wins for a @starci package.'
|
|
31
31
|
'@starci/eslint-canon-be':
|
|
32
|
-
version: 3.4.
|
|
32
|
+
version: 3.4.37
|
|
33
33
|
group: starci
|
|
34
34
|
install: registry
|
|
35
35
|
side: be
|
|
36
36
|
source: packages/eslint/be/package.json
|
|
37
37
|
why: 'the back-end ESLint canon: `loadHfs(import.meta.url)` of be/eslint.config.mjs finds the app-root hfs.json (kind app) and gives every linted file the view of the be side, and the project graph is built per side; its bundled runtime copies (slots, canon-pins, failure codes, the architecture machine) put .starcistacks and .sops.yaml at the app root; `starciBeConfig({ hfs: loadHfs(import.meta.url) })` is the typed factory and the BE-CONVENTION laws are its rules.'
|
|
38
38
|
'@starci/eslint-canon-fe':
|
|
39
|
-
version: 8.4.
|
|
39
|
+
version: 8.4.36
|
|
40
40
|
group: starci
|
|
41
41
|
install: registry
|
|
42
42
|
side: fe
|
|
@@ -76,14 +76,14 @@ pins:
|
|
|
76
76
|
source: packages/test-world/package.json
|
|
77
77
|
why: 'the shared e2e library of every back end (R47, R48), a devDependency of every back end: the warm stack behind toxiproxy, the network-edge fakes, the Nest boot, the typed useTestWorld handle, useSandbox for contract specs and the outage lock. Kafka is real own infra (the one digest-pinned apache/kafka KRaft image, a broker listener and proxy per slot, slot-prefixed topics, consumer groups and client ids) and Postgres is schema-per-context (a schema and a login role per context in a shared database). Each worker has its own data slot (<ns>_w<k>) with its own databases, Keycloak realm, leased Redis DB, bucket/collection/topic prefixes, fakes host, toxiproxy proxies and outage lock; a run provisions min(jest workers, workers cap, default 2) slots, and state file protocol 2 pairs exactly with @starci/jest-preset (TEST_WORLD_PAIR_MISMATCH otherwise). A modules world boots real peer apps beside its modules, world.apps.<name>.during(fn) is the outage of a peer app, w.keycloak.clientSecret(client) answers the run-generated secret of a confidential realm client, world.keycloak.events/sessions read the realm user events and live sessions, world.infra.postgresql.connection(name) takes one database connection down while the others serve, and world.resolve and scope.resolve take any Nest token. Every path a declaration names (`stack`, seeds, the realm, Dockerfiles) resolves from the app root (the directory of hfs.json); the globalSetup registers the path aliases as TypeScript resolves them. Its CLI main is exported at ./cli for starci app stack.'
|
|
78
78
|
'@starci/cli':
|
|
79
|
-
version: 1.7.
|
|
79
|
+
version: 1.7.29
|
|
80
80
|
group: starci
|
|
81
81
|
install: registry
|
|
82
82
|
side: both
|
|
83
83
|
source: packages/cli/package.json
|
|
84
84
|
why: 'the only StarCi command package; product repositories install it for starci app, while @starci/hfs remains its pinned transitive implementation.'
|
|
85
85
|
'@starci/hfs':
|
|
86
|
-
version: 4.7.
|
|
86
|
+
version: 4.7.29
|
|
87
87
|
group: starci
|
|
88
88
|
install: registry
|
|
89
89
|
side: both
|
|
@@ -336,10 +336,10 @@ pins:
|
|
|
336
336
|
side: fe
|
|
337
337
|
why: 'the zod resolver of react-hook-form (fe-stack forms); version read from the starci-academy package-lock on 2026-10-13.'
|
|
338
338
|
'zod':
|
|
339
|
-
version: 4.
|
|
339
|
+
version: 4.6.7
|
|
340
340
|
group: framework
|
|
341
341
|
side: fe
|
|
342
|
-
why: 'the schema library of front-end forms and boundary parsing (fe-stack forms)
|
|
342
|
+
why: 'the schema library of front-end forms and boundary parsing (fe-stack forms), also an npm override of every app root; 4.6.7 (the registry latest on 2026-10-24) closes GHSA-mrhx-c7xc-m3w5 (high, fixed in 4.6.6), which npm audit --audit-level=high reported against 4.4.3.'
|
|
343
343
|
'@reduxjs/toolkit':
|
|
344
344
|
version: 2.11.2
|
|
345
345
|
group: framework
|