Working with Generated Files¶
This guide explains how to work with generated files in the SyRF monorepo, including the verification system that ensures generated files stay in sync with their sources.
Overview¶
The SyRF monorepo contains 30 checksummed generated files produced by 6 generators (the
GENERATOR_COMMANDS list in scripts/generated-manifest-guard.ts). pnpm generate runs all of them in this order:
| Generator | Source | Output Files |
|---|---|---|
generate-env-blocks.ts |
env-mapping.yaml |
8 files (Helm template, config TS/JSON, config-keys.generated.json) |
generate-feature-flags.ts |
env-mapping.yaml |
4 files (feature flag TS files) |
generate-runtime-flag-catalog.ts |
env-mapping.yaml |
2 files (C# runtime flag catalog and key constants) |
generate-feature-definitions.ts |
feature-definitions.yaml, docs/content/whats-new.yaml |
6 files (C# and TS feature definitions, C# flag groups and deployment-managed pins, the What's New feed whats-new.json, the inventory page) |
generate-dockerfiles.py |
dependency-map.yaml |
9 Dockerfiles |
| NSwag | swagger.json |
1 file (TypeScript API client); pnpm generate runs it only when swagger.json changed |
Two reviewed YAML sources have no checksummed output: docs/content/release-content.yaml is read only by
the offline content compiler (pnpm run compile:release-content), and env-mapping.schema.json is a schema.
The feature-registry validator checks both (see below).
How Verification Works¶
The system uses a hash-manifest approach stored in .generated-checksums.json:
- sourceHash - SHA-256 of source file(s), detects when sources change
- outputHash - SHA-256 of each generated file, detects manual edits
- generatorHash - SHA-256 of generator script (warning only)
When you commit, the precommit hook validates:
- Source files haven't changed without regenerating outputs
- Generated files haven't been manually edited
- The feature registry's cross-links hold (
scripts/feature-registry.ts): flag keys in the runtime catalog, Required guidance has content and its user-guide pages exist, release-contentfeatureId/topicIdand What's NewuserGuidePath/featureIdresolve,flagGroupskeep their members (againstHEADlocally and the merge ref's base in CI), Settled and Withdrawn features have no live flag,env-mapping.yamlandwhats-new.jsonmatch their schemas, and every source it reads is covered by the CI and pre-commit trigger patterns - The C# feature-flag consumer inventory is complete (
scripts/feature-flag-consumers.ts)
Quick Reference¶
One command¶
# Every generator in dependency order (NSwag only when swagger.json changed), then the registry validator.
# On a clean tree it changes nothing.
pnpm generate
# Only some generators, still in order
pnpm generate generate-env-blocks generate-feature-flags
# Add a feature and its flag, or settle a released one (see Managing Feature Flags)
pnpm feature:new <feature-id> --type <type> --owner "<team>" [--permission <SignedIn|Project…Policy|Application…Policy>]
# --permission is required for --type Release
pnpm feature:settle <feature-id>
scripts/generate-all.test.ts (in validate:generated) fails if a generator is added to GENERATOR_COMMANDS without
an order slot in scripts/generate-all.ts. The slow checks that run the real generators and feature commands in a
temporary copy of the repository files (pnpm generate is a no-op on a clean tree; feature:new and
feature:settle end to end) are scripts/tooling-e2e.test.ts: pnpm run test:tooling-e2e. CI runs them after
validate:generated in both Validate Generated Code jobs; the pre-commit hook runs them only when
scripts/feature-commands*, scripts/generate-all*, scripts/tooling-e2e.test.ts or scripts/temp-repo-copy.ts
change. nswag:spec stays
separate, because it needs a .NET Release build.
Validation Commands¶
# Validate all generated files
pnpm run validate:generated
# Registry cross-links and schemas only (fast; names the file and entry)
pnpm run validate:registry
# Run individual generator validators
cd src/charts/syrf-common && pnpm run validate:env-blocks
cd src/services/web && pnpm run validate:flags
python3 scripts/generate-dockerfiles.py --validate
Regeneration Commands¶
# Regenerate config files (8 files)
cd src/charts/syrf-common && pnpm run generate:env-blocks
# Regenerate feature flags (4 files)
cd src/services/web && pnpm run generate:flags
# Regenerate the C# runtime flag catalog and key constants (2 files)
cd src/charts/syrf-common && pnpm run generate:runtime-catalog
# Regenerate feature definitions, flag groups, pins and the What's New feed (5 files)
cd src/charts/syrf-common && pnpm run generate:feature-definitions
# Regenerate Dockerfiles (9 files)
python3 scripts/generate-dockerfiles.py
# Regenerate API client (1 file) - requires swagger.json
cd src/services/web && pnpm run nswag:generate
# Regenerate swagger.json from API assembly (requires API build first)
dotnet build src/services/api/SyRF.API.Endpoint -c Release
cd src/services/web && pnpm run nswag:spec
Developer Workflows¶
Valid configuration keys (config-keys.generated.json)¶
generate:env-blocks also writes src/charts/syrf-common/config-keys.generated.json: for each service
(api, project-management, quartz, identity, web) the Helm valuePaths and the raw envNames
(SYRF__...) that env-mapping.yaml defines, plus schemaVersion and a content digest. It is
deterministic (sorted, no timestamps) and ships inside the packaged syrf-common chart, so it is also inside
every service chart that depends on it (charts/syrf-common/config-keys.generated.json) and at that path in
the git ref a service chart is pinned to. No workflow change is needed.
It is the published list of keys a chart version reads. Environment maintenance belongs to cluster-gitops
(decision D22), so the check lives there and SyRF never reads that repository: cluster-gitops compares the
keys in its own values files with services.<service>.valuePaths of the chart version it pins, and reports
unknown keys (dead or misspelt) as clean-up work. Compare full dotted key paths. valuePaths lists the leaf
paths a chart reads, and a parent path only where the chart reads the parent itself (for example emailTransport,
a section condition). So treat a values key as known when it equals a listed path, or when it is a dotted-segment
prefix of one (emailTransport matches emailTransport.smtp.host, but email does not): a parent object
that contains listed leaves.
Keys read only inside hand-written helper templates are not listed (see the file's coverage note), so
report unknowns for review rather than failing on them blindly.
Modifying env-mapping.yaml¶
To add a feature flag, use pnpm feature:new (it edits the YAML and regenerates). For any other change to
environment variables or flags:
# 1. Edit the source
vim src/charts/syrf-common/env-mapping.yaml
# 2. Regenerate (env blocks, web flags, runtime catalog and key constants, feature definitions all read it)
pnpm generate
# 3. Review and commit all changes
git add -A
git commit -m "feat: add new config option"
Modifying the What's New feed or release content¶
Both are reviewed YAML under docs/content/:
whats-new.yaml→pnpm --filter syrf-common-chart generate:feature-definitionsregeneratessrc/services/web/src/assets/data/whats-new.json(the file the web app fetches). See Update the What's New feed.release-content.yamlhas no generated output;pnpm run validate:generatedchecks its references andpnpm run compile:release-content docs/content/release-content.yaml user-guide <server-dir> <public-dir>compiles it. See Managing Feature Flags.
Then run pnpm run validate:generated and commit the source with its regenerated outputs and checksums.
Modifying dependency-map.yaml¶
When changing service dependencies:
# 1. Edit the source
vim docs/architecture/dependency-map.yaml
# 2. Regenerate Dockerfiles
python3 scripts/generate-dockerfiles.py
# 3. Review and commit
git add -A
git commit -m "chore: update service dependencies"
Modifying API Endpoints or DTOs¶
When changing API controllers, DTOs, or endpoints, building the API automatically regenerates both swagger.json and the TypeScript client:
# 1. Make API changes
vim src/services/api/SyRF.API.Endpoint/Controllers/...
# 2. Build API in Release mode — swagger.json, TypeScript client, and checksums are regenerated automatically
dotnet build src/services/api/SyRF.API.Endpoint -c Release
# 3. Review and commit
git add -A
git commit -m "feat(api): add new endpoint"
Automatic generation details:
- The API
.csprojhas anAfterBuildtarget that runs NSwag spec generation followed by TypeScript client generation - Only runs on Release builds (
-c Release) — Debug builds skip generation for faster iteration - TypeScript client generation requires
pnpm installinsrc/services/web/(warns and skips if missing) - Disable with
dotnet build -c Release /p:GenerateOpenApi=falseif you want a Release build without regeneration
Manual generation (if you need to run steps individually):
# Generate swagger.json only (from compiled API assembly)
cd src/services/web && pnpm run nswag:spec
# Generate TypeScript client only (from existing swagger.json)
cd src/services/web && pnpm run nswag:generate
# Generate both spec + client + checksums in one command
cd src/services/web && pnpm run nswag:all
Note: The swagger.json file is committed to the repository as the source of truth for the API client generation. This allows the TypeScript client to be regenerated without running the API.
If Precommit Fails¶
If you see a precommit failure like:
❌ Generated file validation failed!
Error: Source changed for "generate-env-blocks"
Sources: src/charts/syrf-common/env-mapping.yaml
Fix: cd src/charts/syrf-common && pnpm run generate:env-blocks
Follow the fix command shown (or run pnpm generate), then stage and commit again:
# Run the suggested command
cd src/charts/syrf-common && pnpm run generate:env-blocks
# Stage the regenerated files
git add -A
# Commit again
git commit -m "your message"
Generated Files Reference¶
From env-mapping.yaml (generate-env-blocks)¶
| File | Purpose |
|---|---|
src/charts/syrf-common/templates/_env-blocks.tpl |
Helm template for env vars |
src/services/web/src/assets/data/env.template.generated.json |
Runtime env template |
src/services/web/src/assets/data/appConfig.default.generated.json |
Default config values |
src/services/web/src/app/core/services/config/external-config.generated.ts |
External config interface |
src/services/web/src/app/core/services/config/app-config.generated.ts |
App config interface |
src/services/web/src/app/core/services/config/feature-flags.generated.ts |
Feature flags interface |
src/services/web/src/app/core/services/config/load-config.generated.ts |
Config loader function |
src/charts/syrf-common/config-keys.generated.json |
Valid configuration keys per service (see Valid configuration keys) |
From env-mapping.yaml (generate-feature-flags)¶
| File | Purpose |
|---|---|
src/services/web/src/app/generated/feature-flags.constants.ts |
Flag defaults and mappings |
src/services/web/src/app/generated/feature-flags.types.ts |
TypeScript types |
src/services/web/src/app/generated/feature-flags.parser.ts |
Config parser |
src/services/web/src/app/generated/feature-flags.selectors.ts |
ngrx selectors |
From dependency-map.yaml (generate-dockerfiles)¶
| File | Purpose |
|---|---|
src/services/api/SyRF.API.Endpoint/Dockerfile |
API service Docker build |
src/services/identity/SyRF.Identity.Endpoint/Dockerfile |
Identity service Docker build |
src/services/project-management/SyRF.ProjectManagement.Endpoint/Dockerfile |
PM service Docker build |
src/services/quartz/SyRF.Quartz/Dockerfile |
Quartz service Docker build |
src/services/s3-notifier/SyRF.S3FileSavedNotifier.Endpoint/Dockerfile |
S3 Notifier Docker build |
src/services/web/Dockerfile |
Web frontend Docker build |
src/services/web/Dockerfile.full |
Web frontend full Docker build |
user-guide/Dockerfile |
User guide Docker build |
docs/Dockerfile |
MkDocs site Docker build |
From env-mapping.yaml (generate-runtime-flag-catalog)¶
| File | Purpose |
|---|---|
src/libs/mongo/SyRF.Mongo.Common/RuntimeFeatureFlags/RuntimeFeatureFlagCatalog.generated.cs |
Shared C# runtime flag catalog |
src/libs/mongo/SyRF.Mongo.Common/RuntimeFeatureFlags/RuntimeFeatureFlagKeys.generated.cs |
RuntimeFeatureFlagKeys: one constant per catalogued key (name = the key in PascalCase), and RemovedFlags, the removed flags from removedFlags in env-mapping.yaml |
From feature-definitions.yaml and docs/content/whats-new.yaml (generate-feature-definitions)¶
| File | Purpose |
|---|---|
src/libs/mongo/SyRF.Mongo.Common/RuntimeFeatureReleases/FeatureDefinitions.generated.cs |
C# feature definitions |
src/services/web/src/app/generated/feature-definitions.generated.ts |
TypeScript feature definitions |
src/libs/mongo/SyRF.Mongo.Common/RuntimeFeatureFlags/RuntimeFeatureFlagGroups.generated.cs |
Preset flag groups (flagGroups): advertised groups in file order, plus retained IDs only Find resolves |
src/libs/mongo/SyRF.Mongo.Common/RuntimeFeatureFlags/RuntimeFeatureFlagPins.generated.cs |
Deployment-managed pins (deploymentManaged) with their constraint and refusal texts |
src/services/web/src/assets/data/whats-new.json |
Home-page What's New feed (runtime web asset; featureId stripped, $schema first) |
docs/features/feature-inventory.md |
Feature inventory: summary, complexity metrics, features table, unclaimed and removed flags. Also reads the consumer manifest, GENERATOR_COMMANDS; deterministic, no dates |
The feature definitions carry values resolved from each feature's type (communication defaults and settle period),
so no reader applies a default. Groups and pins replace the hand-written C# that RuntimeFeatureFlagGroups.cs and
ProjectStatisticsRuntimeActivation.PinnedKeys held; the hand-written classes are now thin facades over the generated
data. Fields and defaults: Feature registry (schema 2).
From swagger.json (NSwag)¶
| File | Purpose |
|---|---|
src/services/web/src/app/core/services/api-client.generated.ts |
TypeScript API client |
Source files:
src/services/web/swagger.json- OpenAPI specification (generated from API assembly, committed to repo)src/services/web/syrf-local.nswag- NSwag client generation configsrc/services/web/syrf-generate-spec.nswag- NSwag spec generation from assembly
Troubleshooting¶
"Generator script changed" Warning¶
This is informational only. It means the generator script was modified but outputs haven't been regenerated. You can safely ignore this or regenerate to update the checksums.
Manual Edit Detected¶
If you see "Output file manually edited", it means someone edited a generated file directly. Run the appropriate generator to restore the correct content.
Missing Checksums Manifest¶
If .generated-checksums.json is missing:
This initializes the manifest with current file hashes.
CI Integration¶
The validation runs automatically on PRs when generated files or their sources are modified. The job is defined in .github/workflows/pr-tests.yml as validate-generated-code; its trigger is the env_mapping regex in the detect-changes job. The registry validator's check 6 fails if a source it reads (the docs/content/*.yaml files, the What's New feed and schema, env-mapping.schema.json, user-guide/ pages) stops matching that regex or the pre-commit GENERATED_PATTERN.
Architecture¶
┌──────────────────────┐
│ Source Files │
│ - env-mapping.yaml │
│ - dependency-map │
│ - swagger.json │
└─────────┬────────────┘
│
▼
┌──────────────────────┐ ┌──────────────────────┐
│ Generator Scripts │────▶│ Generated Files │
│ - generate-*.ts │ │ - *.generated.ts │
│ - generate-*.py │ │ - Dockerfiles │
│ - NSwag │ │ - api-client.ts │
└─────────┬────────────┘ └──────────────────────┘
│
▼
┌─────────────────────────────────────────┐
│ .generated-checksums.json │
│ - sourceHash (detects source changes) │
│ - outputHash (detects manual edits) │
│ - generatorHash (informational) │
└─────────────────────────────────────────┘
│
▼
┌─────────────────────┐
│ Validation │
│ - Precommit hook │
│ - CI workflow │
└─────────────────────┘
See Also¶
- env-mapping.yaml - Environment variable definitions
- dependency-map.yaml - Service dependencies
- validate-generated.ts - Validation script
- feature-registry.ts - Feature registry cross-link validator