@onlineapps/conn-orch-validator 12.1.1 → 13.0.0
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 +607 -0
- package/README.md +126 -19
- package/manifests/biz-service.manifest.json +15 -2
- package/manifests/library.manifest.json +4 -4
- package/package.json +11 -3
- package/src/CookbookTestRunner.js +275 -105
- package/src/CookbookTestUtils.js +79 -68
- package/src/ServiceReadinessValidator.js +42 -52
- package/src/ValidationOrchestrator.js +65 -44
- package/src/cli/biz-ci-gate.js +2 -2
- package/src/cli/oa-sync-template.js +97 -47
- package/src/cli/oa-validate.js +44 -10
- package/src/helpers/README.md +6 -6
- package/src/helpers/createServiceReadinessTests.js +87 -33
- package/src/index.js +14 -5
- package/src/lint/scripts/lintScripts.js +11 -4
- package/src/manifest/checks/libraryContext.js +6 -3
- package/src/manifest/checks/libraryDocs.js +174 -4
- package/src/manifest/checks/libraryTests.js +200 -19
- package/src/manifest/checks/scriptHeaders.js +6 -13
- package/src/manifest/checks/serviceConfig.js +36 -16
- package/src/manifest/checks/serviceConnectors.js +180 -2
- package/src/manifest/checks/serviceDb.js +0 -3
- package/src/manifest/checks/serviceScripts.js +3 -20
- package/src/manifest/runManifest.js +90 -13
- package/src/manifest/workspaceRoot.js +133 -4
- package/src/mocks/MockMQClient.js +2 -2
- package/src/sync/docsRegion.js +2 -2
- package/src/sync/readmeFile.js +30 -0
- package/src/sync/readmeLocation.js +2 -12
- package/src/sync/readmePointer.js +10 -4
- package/src/sync/serviceTemplate.js +9 -11
- package/src/sync/sharedEnv.js +59 -3
- package/src/sync/uniformFiles.js +81 -8
- package/src/utils/bizCiGateContract.js +2 -2
- package/src/utils/connectorContract.js +54 -2
- package/src/utils/cookbookFormat.js +25 -115
- package/src/utils/dbAccountGrants.js +5 -3
- package/src/utils/deployContract.js +153 -28
- package/src/utils/envContract.js +2 -2
- package/src/utils/handlerRef.js +8 -10
- package/src/utils/integrationRun.js +1 -1
- package/src/utils/operationsDocumentRules.js +242 -0
- package/src/utils/operationsRules.js +157 -0
- package/src/utils/resolveHeaders.js +12 -1
- package/src/utils/setupDatabase.js +1 -1
- package/src/utils/stepFailure.js +3 -3
- package/src/utils/stepReferences.js +28 -87
- package/src/utils/throwawaySchema.js +1 -1
- package/src/utils/yamlTopLevel.js +105 -0
- package/src/validators/ServiceStructureValidator.js +67 -152
- package/templates/business-service/.gitlab-ci.yml +203 -37
- package/templates/business-service/README.md +7 -4
- package/templates/business-service/config/env-templates/shared.env +1 -0
- package/templates/business-service/docs/80-setup/INSTALL.md +31 -3
- package/templates/business-service/docs/80-setup/PLATFORM_MATRIX.md +5 -2
- package/templates/business-service/src/config/index.js +15 -0
- package/TESTING_STRATEGY.md +0 -92
- package/jest.config.js +0 -37
package/README.md
CHANGED
|
@@ -195,14 +195,17 @@ What Tier-1 adds is the SCOPE, and only the scope
|
|
|
195
195
|
A literal `{{…}}` is the right outcome for a value that is missing at that
|
|
196
196
|
moment — a step that has not run yet, or one that failed. It is the wrong
|
|
197
197
|
outcome for an expression no run could ever resolve, because then a green Tier-1
|
|
198
|
-
certifies a recipe production does not accept.
|
|
199
|
-
BEFORE any step of the cookbook runs, each with its own `Fix
|
|
198
|
+
certifies a recipe production does not accept. These shapes are refused
|
|
199
|
+
BEFORE any step of the cookbook runs, each with its own `Fix:`. The helper call
|
|
200
|
+
is the runner's own refusal; the step references are
|
|
201
|
+
`@onlineapps/cookbook-core` `validateCookbook`'s, which the runner runs first and
|
|
202
|
+
holds no copy of (d.980):
|
|
200
203
|
|
|
201
204
|
| Written in a step's `input` | Tier-1 | Production |
|
|
202
205
|
|---|---|---|
|
|
203
206
|
| `{{webalizeString(…)}}`, `{{string2file(…)}}` — any `name(…)` | refused: `Step <id> input calls the template helper "<name>"` | the orchestrator evaluates it through its helper registry, and throws on a name that registry does not carry |
|
|
204
|
-
| `{{steps.<id>.…}}` naming no step THIS cookbook defines (`{{steps.0.…}}` included — `0` is a name no recipe declares) | refused: `Step <id
|
|
205
|
-
| `depends_on` naming no step this cookbook defines | refused: `Step <id> depends on
|
|
207
|
+
| `{{steps.<id>.…}}` naming no step THIS cookbook defines (`{{steps.0.…}}` included — `0` is a name no recipe declares) | refused (cookbook-core): `Step references that cannot resolve at run time - <id>.input: … - unknown step '<x>'` (positional: `… never by position`) | 400 `Invalid cookbook references` at submission |
|
|
208
|
+
| `depends_on` naming no step this cookbook defines | refused (cookbook-core): `Step '<id>' depends on non-existent step_id '<x>'` | — |
|
|
206
209
|
|
|
207
210
|
The helper registry is absent from the runner on purpose: a helper reaches its
|
|
208
211
|
own runtime (`@onlineapps/content-resolver`, files, storage), which is not what a
|
|
@@ -277,15 +280,18 @@ schema name is refused rather than escaped — no platform name carries one.
|
|
|
277
280
|
|
|
278
281
|
### Running the live-database suites
|
|
279
282
|
|
|
280
|
-
|
|
281
|
-
package builds
|
|
282
|
-
`
|
|
283
|
-
|
|
284
|
-
|
|
285
|
-
`test-validator-db`
|
|
283
|
+
The live-database suites of this package measure what a **real** MariaDB does
|
|
284
|
+
with the SQL the package builds: what `ci:gate:setup` leaves in the schema,
|
|
285
|
+
whether the account `setup-db-account` creates is granted enough — and still not
|
|
286
|
+
too much — and how far the production grant of that account reaches. They are
|
|
287
|
+
the suites that require `tests/helpers/liveDatabase.js`, and the list of them is
|
|
288
|
+
the `script` of the job `test-validator-db` in `api/.gitlab-ci.yml`; this
|
|
289
|
+
sentence does not keep a second copy of it. They are part of
|
|
290
|
+
`npm run test:unit`, and in CI that job gives them a database of its own (owner
|
|
291
|
+
decision
|
|
286
292
|
[`ci-validator-db-job` 001](../../../docs/governance/confirmations/ci-validator-db-job.md)).
|
|
287
293
|
|
|
288
|
-
|
|
294
|
+
No such suite looks for a database. It is **declared**, under the names this
|
|
289
295
|
package's own CLI reads:
|
|
290
296
|
|
|
291
297
|
| Variable | What it is |
|
|
@@ -310,9 +316,14 @@ DB_HOST=gen_mariadb10.5 DB_PORT=3306 \
|
|
|
310
316
|
CI_DB_ROOT_USER=root \
|
|
311
317
|
CI_DB_ROOT_PASSWORD="$(grep '^MARIADB_ROOT_PASSWORD=' ../../../config/env-active/gen-db.env | cut -d= -f2-)" \
|
|
312
318
|
DB_DOCKER_NETWORK=gendb-network \
|
|
313
|
-
npx jest
|
|
319
|
+
npx jest $(grep -rl 'helpers/liveDatabase' tests/unit)
|
|
314
320
|
```
|
|
315
321
|
|
|
322
|
+
Which suites that selects is not typed here either: it is the requirement of the
|
|
323
|
+
helper, so a suite that joins them is run by this block unedited, and
|
|
324
|
+
`npx jest --listTests $(grep -rl 'helpers/liveDatabase' tests/unit)` says which
|
|
325
|
+
files the next run will take before it takes them.
|
|
326
|
+
|
|
316
327
|
The run prints which server it measured, or why it measured none — that line is
|
|
317
328
|
what tells a green suite that looked from a green suite that did not.
|
|
318
329
|
|
|
@@ -735,7 +746,7 @@ the three already had an owner, so no second notation was introduced for them
|
|
|
735
746
|
|
|
736
747
|
| file | row | decided by |
|
|
737
748
|
|---|---|---|
|
|
738
|
-
| `operations.json` | `C-OPS` | `service-validator-core` `validateOperationsSchema` — the mirror of the fifteen rules the Registry applies on registration |
|
|
749
|
+
| `operations.json` | `C-OPS` | two definitions, neither of them in this row. What each OPERATION must be: `service-validator-core` `validateOperationsSchema` — the mirror of the fifteen rules the Registry applies on registration, reached through `src/utils/operationsRules.js`. What the DOCUMENT must be (`schema_version: "3.0"`, at least one operation declared, and — for the two rails that generate a cookbook from it — `input`/`output` declared with `description` warned about): `src/utils/operationsDocumentRules.js`, which is deliberately NOT in the core — the Registry receives `doc.operations` alone, never the file, and generates no cookbook, so it has a rule about none of them. The row asks the first two; boot step 4 and the readiness score ask all three. Until d.465 this row said the first half and did not do it, while three other rails each restated a different subset of the rules from memory; until d.465b an empty operations map had four answers across those rails (error · warning · silence · finding) and a missing `schema_version` had none |
|
|
739
750
|
| `integration-contract.json` | `C-CONTRACT` | `utils/bizCiGateContract.js` — the validator the CI gate already runs over this document, so the gate and the table can never disagree about it |
|
|
740
751
|
| `config.json` | `C-SERVICE` | `src/manifest/checks/serviceConfig.js`, which had no owner before |
|
|
741
752
|
|
|
@@ -771,6 +782,39 @@ once, in `DEAD_KEYS` (`src/manifest/checks/serviceConfig.js`), and the manifest
|
|
|
771
782
|
`why` is held equal to that list by its own test — so this paragraph names the class,
|
|
772
783
|
never the count. The fix is always the same sentence — delete the key.
|
|
773
784
|
|
|
785
|
+
**`C-CI-CONNECTOR-ENV`** asks the other half of the connector question. `C-CONNECTORS`
|
|
786
|
+
above compares two declarations with each other; this row compares them with the ONE
|
|
787
|
+
environment they are exercised in every day. Measured 2026-09-18: three `emailer` tests
|
|
788
|
+
failed in CI on `[RuntimeConfig] Missing environment variable - MINIO_USE_SSL`, a name no
|
|
789
|
+
line of the service reads — `@onlineapps/conn-base-storage` resolves it, `required: true`,
|
|
790
|
+
with no default — so `ci:gate:contract` could not see it (`node_modules` is deliberately
|
|
791
|
+
outside its scan, § Environment contract) and `ci:gate:env` emits six `OA_CI_*` names and
|
|
792
|
+
measures nothing. The same suite passes locally, because the one-shot runner loads
|
|
793
|
+
`config/env-templates/shared.env` through `env_file` and that generated copy carries the
|
|
794
|
+
key; the job's `variables:` is the SECOND delivery of the same set, copied by hand in eight
|
|
795
|
+
repositories, and nothing compared it with the first.
|
|
796
|
+
|
|
797
|
+
The row is keyed by the service's own `requiredConnectors` and by the names the connector's
|
|
798
|
+
library resolves **without a default** — `CONNECTORS` in `src/utils/connectorContract.js`,
|
|
799
|
+
measured against that library's schema, so nothing is copied into the manifest. It is
|
|
800
|
+
deliberately NOT keyed by `required: true` in a library schema: the resolver's priority is
|
|
801
|
+
explicit config → env → default, so that flag is conditional, and four families satisfy it
|
|
802
|
+
while being no gap at all (`REDIS_HOST`/`REDIS_PORT`, which the wrapper passes explicitly;
|
|
803
|
+
`SERVICE_NAME` in `infrastructure-tools`, on the infra path;
|
|
804
|
+
`INFRA_REPORT_SMTP_REQUIRE_TLS`, read only for a fallback transport;
|
|
805
|
+
`LOG_MAX_SIZE_BYTES`/`LOG_MAX_FILES`, delegated to the file sink). A gate on that flag would
|
|
806
|
+
have reported findings nobody could fix on its first day (`automation-gates.md` §3).
|
|
807
|
+
|
|
808
|
+
Like `D-DB-CI-ACCOUNT` it reads only OUTSIDE the `oa-ci v1` block, which is `G-CI`'s, and
|
|
809
|
+
only the `variables:` of the job the row names — the MinIO sidecar's own `variables:`, two
|
|
810
|
+
levels deeper, is that container's environment and not the job's. It asks WHICH names that
|
|
811
|
+
job sets and deliberately not WHETHER a repository runs one, because "add a test job" is
|
|
812
|
+
another fix and one row with two fixes is two mechanisms under one name. It cannot see
|
|
813
|
+
GitLab's project-level variables, which live outside the repository by design, so it
|
|
814
|
+
measures only names with a platform value in `api/config/shared-env.json` — never a secret.
|
|
815
|
+
Owner decision
|
|
816
|
+
[`biz-service-manifest`](../../../docs/governance/confirmations/biz-service-manifest.md) 013.
|
|
817
|
+
|
|
774
818
|
`service.url` is the one entry carrying a **date**: it is dead from wrapper **8.0.0**,
|
|
775
819
|
not today. The published 7.0.0 still throws
|
|
776
820
|
`Missing configuration - service.url is required`, so the key travels WITH the pin, which
|
|
@@ -1003,12 +1047,18 @@ becomes an artefact and therefore never reaches a service.
|
|
|
1003
1047
|
npx oa-validate --library ../../logger-contract # one package
|
|
1004
1048
|
npx oa-validate --library --all # every package the uniform finds
|
|
1005
1049
|
npx oa-validate --library --all --workspace /path/to/workspace --json
|
|
1050
|
+
npx oa-validate --library ../../logger-contract --as-version 1.2.4 # judged as the version being published
|
|
1006
1051
|
```
|
|
1007
1052
|
|
|
1008
1053
|
One table (`id · category · where · what · fix`), the `doc` pointer of every reported
|
|
1009
1054
|
row, exit `0` / `1`; `2` when the run could not start. `--library` with neither a
|
|
1010
1055
|
package directory nor `--all` is a usage error — nothing is guessed.
|
|
1011
1056
|
|
|
1057
|
+
`--as-version <X.Y.Z>` (one package only) is the question a publish dry run asks: the
|
|
1058
|
+
rows that judge a version — `L-CHANGELOG` — judge the version about to be written, not
|
|
1059
|
+
the one `package.json` still carries, and the finding names both. Without it the run
|
|
1060
|
+
audits the tree as it stands (d.1040).
|
|
1061
|
+
|
|
1012
1062
|
**Who wears the uniform** is discovery, not a list: `api/shared/**/package.json` minus
|
|
1013
1063
|
`**/node_modules/**` and `**/tests/fixtures/**`, bound to `api/config/libraries.json`.
|
|
1014
1064
|
A package the SSOT does not know, and a name in the SSOT with no package, are both
|
|
@@ -1048,7 +1098,14 @@ the raw file text, so a module documenting the duty it obeys — "this module re
|
|
|
1048
1098
|
|
|
1049
1099
|
`L-PACK-TESTS` measures the **effect**, not the file: eight packages keep `tests/` out of
|
|
1050
1100
|
the tarball with a `files` allowlist and no `.npmignore` at all, and a row checking for
|
|
1051
|
-
the file would report eight packages that are already right.
|
|
1101
|
+
the file would report eight packages that are already right. An allowlist entry reaches
|
|
1102
|
+
`tests/` when its first segment matches the name — `tests`, `*`, or `**` — so
|
|
1103
|
+
`["**/*.js"]` is a finding too. The row is about the package's own tier at its root: a
|
|
1104
|
+
`tests/` under `templates/**` is template content (this package ships
|
|
1105
|
+
`templates/business-service/tests/**` for `oa-sync-template --new`) and is never a finding.
|
|
1106
|
+
An ignore file is read the way npm walks it, negations included: `/tests/` followed by
|
|
1107
|
+
`!tests/**` ships the tier and is a finding naming the `!` line (d.1006); the reproduction is
|
|
1108
|
+
held against `npm pack --dry-run --json` by `libraryPackTests.npmPack.integration.test.js`.
|
|
1052
1109
|
|
|
1053
1110
|
**What is deliberately NOT a row** is written down as such, in the manifest's `guidance`
|
|
1054
1111
|
block, with the reason and the decision it rests on — a duty nothing can decide is
|
|
@@ -1221,12 +1278,41 @@ Rewrites the files the manifest declares in the classes `identical`, `generated`
|
|
|
1221
1278
|
at — one definition, read twice. With no paths it plans every such row. Files of the `own`
|
|
1222
1279
|
class — `src/**`, `tests/**`, the content of `docs/**` — are never written.
|
|
1223
1280
|
|
|
1281
|
+
**One run is the whole sync of a service.** "Bring this repository into line with
|
|
1282
|
+
everything the uniform generates" is `npx oa-sync-template --target .`, and nothing else:
|
|
1283
|
+
every generated row of the service uniform is a line of that run, `README.md` (row
|
|
1284
|
+
`G-README`) and `config/env-templates/shared.env` (row `G-SHARED-ENV`) included. What is
|
|
1285
|
+
NOT in it is `template` and `docs-region`, because their bearer is not a service —
|
|
1286
|
+
`api/templates/business-service` and the `api/docs/**` tree are other directories with
|
|
1287
|
+
other owners.
|
|
1288
|
+
|
|
1289
|
+
Until d.710 the run's row set was the manifest's `files` section, and `G-SHARED-ENV` is
|
|
1290
|
+
filed under `config`, where the manifest reports about a service's configuration. So
|
|
1291
|
+
`oa-validate` measured `shared.env` and the sync wrote nothing: a repository could finish
|
|
1292
|
+
the sync and be reported `NOT DEPLOYABLE` by the very manifest the sync reads (measured
|
|
1293
|
+
2026-09-20 over a copy of `api_biz/hello` — `NOT DEPLOYABLE — 1 finding(s)` immediately
|
|
1294
|
+
after a full bare run). Instruction 3 of the library cascade asked eight repositories to
|
|
1295
|
+
"sync every row", which was in fact four commands each of them assembled for itself, and
|
|
1296
|
+
BIZ-ingest escalated on 2026-09-18 that the bare run does not carry that row. A row now
|
|
1297
|
+
says what it IS — `"class": "generated"` — wherever the manifest reports it from, and the
|
|
1298
|
+
sync reads that declaration rather than a section's name. A row joins by SAYING so: `own`
|
|
1299
|
+
and `forbidden` cannot drift in, and neither can a future row of any other section.
|
|
1300
|
+
|
|
1301
|
+
`G-SHARED-ENV` renders through `src/sync/sharedEnv.js`, the module that owns the shared
|
|
1302
|
+
key set, in the same expression its own CHECK evaluates — so the bare run, the `shared-env`
|
|
1303
|
+
subcommand and `oa-validate` cannot produce three opinions of one file. The subcommand
|
|
1304
|
+
stays, and not as a convenience: `api/` itself and the business-service template carry
|
|
1305
|
+
`shared.env` too, and neither is a service root the bare run could be pointed at.
|
|
1306
|
+
|
|
1224
1307
|
**No workspace is required of the run itself** — only of the ROWS that read a workspace
|
|
1225
1308
|
file, and since d.229 most of them read a file this package carries. The predicate is the
|
|
1226
1309
|
one the manifest run uses (`rowNeedsWorkspace`), so the `fix` command of `F-INIT`,
|
|
1227
1310
|
`F-JEST` and `F-RUNNER` can be typed where their finding is now raised: inside the service
|
|
1228
1311
|
image. A row that does need one is printed `NOT RUN` by name with the `--workspace` fix,
|
|
1229
|
-
never skipped in silence.
|
|
1312
|
+
never skipped in silence. Inside a service container that is exactly one line, and it names
|
|
1313
|
+
the row and the file: `NOT RUN G-SHARED-ENV config/env-templates/shared.env — the workspace
|
|
1314
|
+
root is not reachable, so api/config/shared-env.json cannot be read. Fix: …` — the shared
|
|
1315
|
+
key set has a platform file for an owner, so no pinned copy can answer for it.
|
|
1230
1316
|
|
|
1231
1317
|
A row the manifest does not make renderable is **not a row of this run**. Today that is
|
|
1232
1318
|
`G-PROD-IMAGE` and `G-SETUP`: they declare no `from:` reference, so nothing says what
|
|
@@ -1241,8 +1327,11 @@ choosing a position among somebody's own install steps; an installation document
|
|
|
1241
1327
|
section, where writing one would mean rewriting somebody's prose — is printed `BLOCKED`
|
|
1242
1328
|
and exits 1.
|
|
1243
1329
|
|
|
1244
|
-
|
|
1245
|
-
|
|
1330
|
+
Where a row needs more than a splice, the module that owns its CHECK renders it, so the
|
|
1331
|
+
generator cannot produce a file its own check rejects (`src/sync/uniformFiles.js` §
|
|
1332
|
+
`RENDERERS` is the whole list; a count written here would be a hand-maintained number,
|
|
1333
|
+
which `doc-code-binding.md` §1 forbids — it was wrong by one before d.710 and by two
|
|
1334
|
+
after):
|
|
1246
1335
|
|
|
1247
1336
|
* **`F-RUNNER`** — the `oa-test-runner v1` block is the template's, except for `build`,
|
|
1248
1337
|
`env_file` and `networks`, which the same row requires to equal the service the runner
|
|
@@ -1279,6 +1368,11 @@ the generator cannot produce a file its own check rejects:
|
|
|
1279
1368
|
one is never rewritten, and a missing section is `BLOCKED` with the heading named. That
|
|
1280
1369
|
a document is absent at all stays `G-SETUP`'s finding, through the installation
|
|
1281
1370
|
contract's `SETUP_DOCS`, so one defect keeps one owner.
|
|
1371
|
+
* **`G-SHARED-ENV`** — `config/env-templates/shared.env`, the whole file, rendered by
|
|
1372
|
+
`src/sync/sharedEnv.js` from the referenced document `api/config/shared-env.json`. The
|
|
1373
|
+
row's `from:` names the owner and this module knows no key, no format and no path to it.
|
|
1374
|
+
It is the one row of the run whose owner is a workspace file, so it is also the one that
|
|
1375
|
+
can report `NOT RUN` in a detached checkout.
|
|
1282
1376
|
|
|
1283
1377
|
`--check` writes nothing and exits 1, naming the first line that differs and what the run
|
|
1284
1378
|
would put there — both sides, because one of them alone lies about half the runs: an
|
|
@@ -1301,7 +1395,7 @@ differs and on a file the packaged template has no source for.
|
|
|
1301
1395
|
|
|
1302
1396
|
### `oa-sync-template shared-env`
|
|
1303
1397
|
|
|
1304
|
-
`config/env-templates/shared.env` is generated, never edited
|
|
1398
|
+
`config/env-templates/shared.env` is generated, never edited. The platform env manifest
|
|
1305
1399
|
`api/config/shared-env.json` owns the shared key set — name, template value, why the
|
|
1306
1400
|
platform shares it — and every bearer's copy is rendered from it, so a service can only
|
|
1307
1401
|
add keys of its own in `service.env`.
|
|
@@ -1310,8 +1404,21 @@ add keys of its own in `service.env`.
|
|
|
1310
1404
|
npx oa-sync-template shared-env --target <bearer dir> [--workspace <root>] [--check]
|
|
1311
1405
|
```
|
|
1312
1406
|
|
|
1407
|
+
Neither path in that sentence is written into this command. Since d.710c both come off
|
|
1408
|
+
the manifest row `G-SHARED-ENV`: `row.from` says which file owns the content, `row.path`
|
|
1409
|
+
says where the bearer keeps it, and the command reads the reference the same way every
|
|
1410
|
+
other row is read. It used to build the SSOT's location itself, from the workspace marker,
|
|
1411
|
+
beside the row that declares the same file to `oa-validate` — two declarations of one
|
|
1412
|
+
location, of which only one could be right the day it moved.
|
|
1413
|
+
|
|
1313
1414
|
`--target` is the bearer: a service root, `api/` itself, or the business-service
|
|
1314
|
-
template
|
|
1415
|
+
template. For a SERVICE this is not the only entrance and has not been since d.710: the
|
|
1416
|
+
bare run writes the same file through row `G-SHARED-ENV`, calling this same renderer on
|
|
1417
|
+
the same referenced document, so a service is synced by one command and the two entrances
|
|
1418
|
+
cannot disagree. The subcommand is what the other two bearers have, because neither `api/`
|
|
1419
|
+
nor the template is a service root.
|
|
1420
|
+
|
|
1421
|
+
`--workspace` is the directory holding `api/` and `api_biz/`, found upwards
|
|
1315
1422
|
from the target when it is not given. `--check` writes nothing and exits 1 with the diff
|
|
1316
1423
|
when the file on disk is not what the manifest renders; a run that cannot start at all
|
|
1317
1424
|
exits 2. There is no flag pointing the run at another manifest — the shared key set has
|
|
@@ -397,7 +397,7 @@
|
|
|
397
397
|
"path": "config/service/operations.json",
|
|
398
398
|
"severity": "boot",
|
|
399
399
|
"owner": "BIZ-general",
|
|
400
|
-
"why": "the v3 dispatch table; the per-operation rules
|
|
400
|
+
"why": "the v3 dispatch table; the per-operation rules are asked of @onlineapps/service-validator-core, the one definition of what the Registry refuses on registration, so this row and boot step 4 can never disagree about them",
|
|
401
401
|
"fix": "declare the service's operations in config/service/operations.json",
|
|
402
402
|
"doc": "api/docs/governance/confirmations/biz-service-manifest.md \u00a72"
|
|
403
403
|
},
|
|
@@ -420,6 +420,18 @@
|
|
|
420
420
|
"fix": "make the two declarations agree: set requiredConnectors.<connector> to what the service really needs, or add the wrapper section that configures it / remove the one nothing requires",
|
|
421
421
|
"doc": "api/docs/governance/confirmations/connector-contract-check.md"
|
|
422
422
|
},
|
|
423
|
+
{
|
|
424
|
+
"id": "C-CI-CONNECTOR-ENV",
|
|
425
|
+
"check": "ci-connector-env",
|
|
426
|
+
"path": ".gitlab-ci.yml",
|
|
427
|
+
"block": "oa-ci v1",
|
|
428
|
+
"job": "test",
|
|
429
|
+
"severity": "deploy",
|
|
430
|
+
"owner": "BIZ-general",
|
|
431
|
+
"why": "the row above measures whether the two declarations agree; this one measures whether the ONE environment they are exercised in every day carries what they need. Measured 2026-09-18: three emailer tests failed in CI on \"[RuntimeConfig] Missing environment variable - MINIO_USE_SSL\", a name no line of the service reads — @onlineapps/conn-base-storage resolves it, required:true, with no default — so ci:gate:contract could not see it (node_modules is deliberately outside its scan) and ci:gate:env emits six OA_CI_* names and measures nothing. The same suite passes locally, because the one-shot runner loads config/env-templates/shared.env through env_file and that generated copy carries the key; the CI job's variables: is the SECOND delivery of the same set, copied by hand in eight repositories, and nothing compared it with the first. The row is keyed by the service's own requiredConnectors declaration and by the names the connector's library resolves without a default (CONNECTORS in utils/connectorContract.js) — never by required:true in a library schema, which is conditional and holds for four families of keys that are no gap at all. It reads the variables: of the test job OUTSIDE the oa-ci v1 block, which is G-CI's, and asks WHICH names that job sets, deliberately not WHETHER a repository runs one. It cannot see GitLab's project-level variables, so it measures only names with a platform value in api/config/shared-env.json, which belong in the file",
|
|
432
|
+
"fix": "add the missing name to the variables: block of the test job in .gitlab-ci.yml, below the oa-ci v1 block — with the value config/env-templates/shared.env declares for that key where the platform owns one, and with this job's own sidecar value where it does not",
|
|
433
|
+
"doc": "api/docs/governance/confirmations/biz-service-manifest.md"
|
|
434
|
+
},
|
|
423
435
|
{
|
|
424
436
|
"id": "C-SERVICE-DEAD",
|
|
425
437
|
"check": "config-dead-keys",
|
|
@@ -441,13 +453,14 @@
|
|
|
441
453
|
},
|
|
442
454
|
{
|
|
443
455
|
"id": "G-SHARED-ENV",
|
|
456
|
+
"class": "generated",
|
|
444
457
|
"check": "shared-env-generated",
|
|
445
458
|
"path": "config/env-templates/shared.env",
|
|
446
459
|
"from": { "path": "api/config/shared-env.json", "text": true },
|
|
447
460
|
"severity": "deploy",
|
|
448
461
|
"owner": "BIZ-general",
|
|
449
462
|
"why": "the shared key set is one fact with one owner; measured on 2026-09-09, none of the nine copies matched the platform file and one key existed in no copy at all. The owner is api/config/shared-env.json and this row renders from it with the renderer the sync command writes with, so a service cannot be synced and reported drifted in the same hour; a run that cannot REACH the workspace says NOT RUN and names the command, because a render published with this package answers about the day it was published, not about the SSOT; a run that does reach it and finds no api/config/shared-env.json in the api checkout stops instead - a missing SSOT in a workspace the run can read is a finding and never a NOT RUN (automation-gates.md §5), and the message names the checkout to update and the api ref a CI job has to move",
|
|
450
|
-
"fix": "npx oa-sync-template
|
|
463
|
+
"fix": "npx oa-sync-template --target .",
|
|
451
464
|
"doc": "api/docs/governance/confirmations/biz-service-manifest.md \u00a718"
|
|
452
465
|
},
|
|
453
466
|
{
|
|
@@ -174,12 +174,12 @@
|
|
|
174
174
|
},
|
|
175
175
|
{
|
|
176
176
|
"id": "L-CHANGELOG",
|
|
177
|
-
"check": "
|
|
177
|
+
"check": "library-changelog-entry",
|
|
178
178
|
"path": "CHANGELOG.md",
|
|
179
179
|
"severity": "publish",
|
|
180
180
|
"owner": "BIZ-general",
|
|
181
181
|
"why": "a published version whose change nobody wrote down is a version nobody can reason about afterwards",
|
|
182
|
-
"fix": "
|
|
182
|
+
"fix": "write the entry for the version being published — the one in package.json, or the one --as-version names on a publish dry run — under \"## [<version>]\" in CHANGELOG.md — a heading with nothing under it does not count; a pin-only release says which pin moved",
|
|
183
183
|
"doc": "api/docs/guides/library-publishing-process.md"
|
|
184
184
|
},
|
|
185
185
|
{
|
|
@@ -187,8 +187,8 @@
|
|
|
187
187
|
"check": "library-readme",
|
|
188
188
|
"severity": "publish",
|
|
189
189
|
"owner": "BIZ-general",
|
|
190
|
-
"why": "a README that cannot say which fact class it owns has no reason to exist,
|
|
191
|
-
"fix": "give README.md the node header - \"> Owns: <the fact class this file is the single owner of>\" and \"> Status: current|draft|archived\"",
|
|
190
|
+
"why": "a README that cannot say which fact class it owns has no reason to exist, nobody can tell a live one from a stale one, and a version copied into it by hand goes stale without anyone noticing",
|
|
191
|
+
"fix": "give README.md the node header - \"> Owns: <the fact class this file is the single owner of>\" and \"> Status: current|draft|archived\" - and delete any hand-written package version from it; package.json owns the version",
|
|
192
192
|
"doc": "api/docs/standards/INFRA-DOC-STANDARD.md"
|
|
193
193
|
},
|
|
194
194
|
{
|
package/package.json
CHANGED
|
@@ -1,11 +1,17 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@onlineapps/conn-orch-validator",
|
|
3
|
-
"version": "
|
|
3
|
+
"version": "13.0.0",
|
|
4
4
|
"description": "Validation orchestrator for OA Drive microservices - coordinates validation across all layers (base, infra, orch, business)",
|
|
5
5
|
"oa": {
|
|
6
6
|
"category": "orchestration"
|
|
7
7
|
},
|
|
8
8
|
"main": "src/index.js",
|
|
9
|
+
"exports": {
|
|
10
|
+
".": "./src/index.js",
|
|
11
|
+
"./manifests/*": "./manifests/*",
|
|
12
|
+
"./templates/*": "./templates/*",
|
|
13
|
+
"./package.json": "./package.json"
|
|
14
|
+
},
|
|
9
15
|
"bin": {
|
|
10
16
|
"oa-biz-ci-gate": "src/cli/biz-ci-gate.js",
|
|
11
17
|
"oa-lint-scripts": "src/cli/oa-lint-scripts.js",
|
|
@@ -28,9 +34,11 @@
|
|
|
28
34
|
"author": "OnlineApps",
|
|
29
35
|
"license": "PROPRIETARY",
|
|
30
36
|
"dependencies": {
|
|
31
|
-
"@onlineapps/cookbook-core": "
|
|
37
|
+
"@onlineapps/cookbook-core": "7.0.0",
|
|
38
|
+
"@onlineapps/error-handler-core": "4.0.0",
|
|
39
|
+
"@onlineapps/handler-contract": "1.0.0",
|
|
32
40
|
"@onlineapps/logger-contract": "2.0.0",
|
|
33
|
-
"@onlineapps/service-validator-core": "2.
|
|
41
|
+
"@onlineapps/service-validator-core": "2.2.0"
|
|
34
42
|
},
|
|
35
43
|
"devDependencies": {
|
|
36
44
|
"jest": "^29.5.0"
|