Skip to content

feat(devtools): frigg validate --module and api-module schema fields - #702

Merged
seanspeaks merged 9 commits into
cursor/api-module-schema-fields-1721from
cursor/frigg-validate-module-1721
Oct 24, 2026
Merged

seanspeaks merged 9 commits into
cursor/api-module-schema-fields-1721from
cursor/frigg-validate-module-1721

Conversation

@seanspeaks

@seanspeaks seanspeaks commented Oct 20, 2026 •

Copy link
Copy Markdown
Contributor

Summary

Adds frigg validate --module for API module definitions, stacked on #701’s schema field allowances.

Canary fixes

Verified canary

2.0.0--canary.702.3f342da.0 — npx -p @friggframework/devtools@2.0.0--canary.702.3f342da.0 frigg validate --module . exits 0 against api-module-library packages/v1-ready/fathom.

Test plan

Open in Web Open in Cursor 
📦 Published PR as canary version: 2.0.0--canary.702.d5e6de1.0

✨ Test out this PR locally via:

npm install @friggframework/admin-scripts@2.0.0--canary.702.d5e6de1.0
npm install @friggframework/core@2.0.0--canary.702.d5e6de1.0
npm install @friggframework/devtools@2.0.0--canary.702.d5e6de1.0
npm install @friggframework/eslint-config@2.0.0--canary.702.d5e6de1.0
npm install @friggframework/prettier-config@2.0.0--canary.702.d5e6de1.0
npm install @friggframework/schemas@2.0.0--canary.702.d5e6de1.0
npm install @friggframework/serverless-plugin@2.0.0--canary.702.d5e6de1.0
npm install @friggframework/test@2.0.0--canary.702.d5e6de1.0
npm install @friggframework/ui@2.0.0--canary.702.d5e6de1.0
# or 
yarn add @friggframework/admin-scripts@2.0.0--canary.702.d5e6de1.0
yarn add @friggframework/core@2.0.0--canary.702.d5e6de1.0
yarn add @friggframework/devtools@2.0.0--canary.702.d5e6de1.0
yarn add @friggframework/eslint-config@2.0.0--canary.702.d5e6de1.0
yarn add @friggframework/prettier-config@2.0.0--canary.702.d5e6de1.0
yarn add @friggframework/schemas@2.0.0--canary.702.d5e6de1.0
yarn add @friggframework/serverless-plugin@2.0.0--canary.702.d5e6de1.0
yarn add @friggframework/test@2.0.0--canary.702.d5e6de1.0
yarn add @friggframework/ui@2.0.0--canary.702.d5e6de1.0

Note

High Risk
Changes default user/auth behavior at runtime, blocks build/deploy on previously tolerated definition mistakes, and adds a core→schemas dependency—organization-only login may need explicit individualUserRequired: false.

Reviewed by Cursor Bugbot for commit ef0dc8c. Bugbot is set up for automated code reviews on this repo. Configure here.

@seanspeaks seanspeaks added the release Create a release when this pr is merged label Oct 20, 2026 — with Cursor
@cursor
cursor Bot force-pushed the cursor/frigg-validate-module-1721 branch from 047d3c4 to 853ee3e Compare October 20, 2026 12:04
@cursor
cursor Bot changed the base branch from feat/frigg-validate to cursor/api-module-schema-fields-1721 October 20, 2026 12:04
seanspeaks and others added 7 commits October 20, 2026 12:39
…e reads

- integrations (and adminScripts, reports) are validated as a serialised
  view in which each class is { Definition }: apps list classes, which
  `type: object` rejected, so every app with an integration failed.
- enums are the values the builders accept: postgres.management
  discover|managed|use-existing, vpc.management discover|create-new|
  use-existing, managementMode adds 'existing'; subnet/NAT management add
  the values the VPC builder acts on.
- adds the keys builders and core read but the schema rejected
  (ownership/external blocks, usePrismaLambdaLayer, scheduler, aws.discovery,
  telemetry, admin, adminScripts, reports, deployment, encryption.disable,
  kmsKeyAlias, keyAlias, lambda.keepNestedNodeModules, ...).
- keys nothing reads are marked deprecated and lose their defaults.
- every remaining default equals what the code does when the key is
  absent; defaults the code does not share are removed
  (fieldLevelEncryptionMethod, managementMode, vpcIsolation, ...).
- applyAppDefinitionDefaults(): the one schema-driven defaults step, loaded
  without Ajv, for core's loader and devtools (ADR-051).

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>

Co-authored-by: Sean Matthews <sean.matthews@lefthook.co>
loadAppDefinition passed `user` through unchanged, so the documented
defaults never applied: a user block without individualUserRequired made
POST /user/login throw, and an app without one got userConfig = null and a
TypeError on every authenticated request. The loader now applies the
schema defaults (applyAppDefinitionDefaults from @friggframework/schemas)
before reading the definition, and maps the deprecated user.password to
usePassword (ADR-051).

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
…and start

`frigg validate [--stage] [--json]` loads index.js the way build does,
validates it against the app-definition schema and runs the checks the
schema cannot express (integration classes and their module definitions,
an enabled database, management settings, encryption, a user config that
can log in, deprecated keys), with JSON pointers and fix hints; it exits 1
on errors.

`frigg build` and `frigg deploy` run the same validation first and stop on
errors (--skip-validate bypasses it, loudly); `frigg start` only warns;
`frigg init` validates the generated index.js instead of a stand-in object.

createFriggInfrastructure applies the schema defaults through the same
step as core. A contract test composes the infrastructure for a matrix of
definitions, records every key the builders read and checks it against the
schema in both directions, and checks that the schema defaults change
nothing in the composed output (ADR-051).

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Records the decision (the schema describes what the runtime reads, its
defaults are applied by one loader step, frigg validate gates build and
deploy, a contract test stops the drift), adds `frigg validate` to the CLI
README, CLAUDE.md and the frigg skill, and corrects the PostgreSQL docs,
which used management values and keys the Aurora builder does not read.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Add frigg validate --module (also frigg validate module) to load Definition
from ./index.js, run validateApiModuleDefinition and checkModuleDefinition,
and exit non-zero with JSON field paths. Supports --json and -v.

Stacked on #701 (api-module schema fields) and includes #666 (ADR-051
frigg validate app mode) so the CLI canary has both.

Co-authored-by: Sean Matthews <sean.matthews@lefthook.co>
Co-authored-by: Sean Matthews <sean.matthews@lefthook.co>
devtools depends on @friggframework/test at the canary version. A
packages/test change ensures lerna/auto includes it when cutting the
#702 canary (same pattern as the core package.json bump).

Co-authored-by: Sean Matthews <sean.matthews@lefthook.co>
@cursor
cursor Bot force-pushed the cursor/frigg-validate-module-1721 branch from 0a3e1ef to 0c74b9c Compare October 20, 2026 12:39
Retriggers a solo #702 canary after a concurrent #701/#702 release race
left @friggframework/core and @friggframework/test unpublished for
2.0.0--canary.702.0c74b9c.0 while devtools still depended on them.

Co-authored-by: Sean Matthews <sean.matthews@lefthook.co>
@cursor

cursor Bot commented Oct 24, 2026

Copy link
Copy Markdown

Frigg 2.0.1 review (Group 2) — COMMENT only

Checklist

  • frigg validate --module + api-module schema fields: pass for the module path
  • Consistent with #666: fail — this branch still carries #666’s app-definition enum gaps

Verdict (would): changes needed (same blockers as #666)

Findings

  1. blocking — packages/schemas/schemas/app-definition.schema.json (postgres management enum)

    • Still ["discover","managed","use-existing"] — no 'external'.
    • Scenario: Same as #666: post-#639 scaffold fails frigg validate / build preflight.
  2. blocking — fieldLevelEncryptionMethod enum still lacks 'none'.

    • Scenario: Explicit #663 opt-out rejected by schema on this stacked validate CLI.
  3. should-fix — same missing stacked keys as #666 (entities, managementApi.proxy.*, provider: netlify, extensions) if this PR is meant to be the validate train for 2.0.1.

Module command (validate-module-definition.js, fixtures, wiring) looks good and matches ADR-051’s module checks. Fix the app-definition enums here or rebase onto a fixed #666.

"enum": ["kms", "aes"],
"default": "aes"
"description": "Field-level encryption key. 'kms': Frigg creates or discovers a KMS key and sets KMS_KEY_ARN. 'aes': the app supplies AES_KEY_ID and AES_KEY (list both in `environment`). Omitted: no key is provisioned and deployed stages store sensitive fields unencrypted (core logs a warning). Stages dev, test and local never encrypt.",
"enum": ["kms", "aes"]

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

blocking (same as #666): add 'none' for #663’s explicit opt-out. Keep no default: "aes".

"enum": ["discover", "create-new", "existing"],
"default": "discover"
"description": "How Frigg gets the Aurora cluster (ignored when managementMode is 'managed' or 'existing'). 'discover' (also when omitted): find one, else create one in the stack. 'managed': create it in the stack. 'use-existing': connect to `endpoint` without creating anything.",
"enum": ["discover", "managed", "use-existing"]

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

blocking (same as #666): add 'external' — #639 scaffold already uses database.postgres.management: 'external', and semantic checks special-case it. Without the enum value, frigg validate / build preflight reject a valid init app.

@cursor

cursor Bot commented Oct 24, 2026

Copy link
Copy Markdown

Follow-up finding (COMMENT)

blocking — packages/schemas/schemas/app-definition.schema.json has duplicate top-level keys: adminScripts / reports / admin at ~L98–130 and again at ~L1041–1079 (ADR-051 shapes).

JSON.parse / Ajv keep the last occurrence; the first block is dead weight and makes merges with #666 unsafe.

Scenario: Reviewers/tools that don’t last-key-win see contradictory schemas; a rebase can keep the wrong block. Delete the first copies; keep only the ADR-051 definitions.

app-definition.schema.json defined adminScripts, reports and admin twice:
once from next (#675) and once from the ADR-051 rewrite. JSON.parse keeps
the last, so the ADR-051 definitions were already the ones in force; the
earlier block is removed and the parsed schema is unchanged.

A new test parses every schema file with a duplicate-key check, so a key
written twice fails CI instead of silently replacing the first.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_013b2UUFaQ5Lk6TFPqzRr1j7
@seanspeaks

Copy link
Copy Markdown
Contributor Author

Re the duplicate-keys finding in #702 (comment)

Verdict: confirmed. Fixed in ef0dc8c. A Python json.load with an object_pairs_hook that raises on duplicates flags schemas/app-definition.schema.json for adminScripts, reports and admin, and no other schema file. The first block (L98–130) came in from next (#675, "allow admin keys in the app schema"). The second (L1041–1079) is this PR's ADR-051 rewrite. JSON.parse keeps the last occurrence, so the ADR-051 shapes were already the ones in force.

Choice: I kept the ADR-051 block and deleted the earlier one. Before/after json.loads compare equal, so the effective schema doesn't change at all. The ADR-051 shapes are correct as written:

  • items: { type: object, required: [Definition] } matches what validateAppDefinition actually checks. It validates toAppDefinitionSchemaView(...), which maps each class to { Definition } (CLASS_LIST_KEYS includes adminScripts and reports). fix(admin-scripts): allow admin keys in the app schema and create admin queues offline #675's test app-definition-admin.test.js still passes against it.
  • The only thing the dropped block had that ADR-051 lacks is admin.enableScheduling: default false. It was never in effect, because last-key-wins already discarded it. An omitted enableScheduling is falsy where it's read, so I didn't add it back to keep the diff minimal.

The change is deletion only (33 lines), with no $id edits, to stay clear of #705 and #666.

Test: packages/schemas/tests/schema-files-no-duplicate-keys.test.js walks every schemas/**/*.json and runs a duplicate-key scan that reports a JSON pointer per repeat. It failed before the fix on /properties/admin, /properties/adminScripts and /properties/reports. npx jest in packages/schemas: 10 suites, 183 tests passed.

🤖 Generated with Claude Code

@sonarqubecloud

Copy link
Copy Markdown

@seanspeaks
seanspeaks marked this pull request as ready for review October 24, 2026 04:35

@claude claude Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

⚠️ Code review skipped — your organization has no extra usage available to pay for this review.

If your organization's extra usage balance is empty, an organization admin can add extra usage credits at claude.ai/admin-settings/usage. If its monthly spend limit was reached, an admin can raise it on the same page. If neither applies, contact Anthropic support.

Once extra usage is available, someone with write access to this repository can comment @claude review on this pull request to trigger a review.

@seanspeaks
seanspeaks merged commit d5e6de1 into cursor/api-module-schema-fields-1721 Oct 24, 2026
6 of 7 checks passed

@cursor cursor Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Cursor Bugbot has reviewed your changes using high effort and found 2 potential issues.

Fix All in Cursor

❌ Bugbot Autofix is OFF. To automatically fix reported issues with cloud agents, enable autofix in the Cursor dashboard.

Reviewed by Cursor Bugbot for commit ef0dc8c. Configure here.

'Frigg provisions or discovers a private Aurora cluster, but the Lambda functions run outside a VPC and cannot reach it.',
"Set vpc.enable: true, or use database.postgres.management: 'use-existing' with a reachable endpoint."
)
);

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Aurora reachability check ignores managementMode

Medium Severity

checkManagement treats database.postgres.management as unused when managementMode is managed or existing, but provisionsAurora still honors that same key. A managed app with postgres.management: 'use-existing' and vpc.enable off therefore gets the no-effect warning and skips unreachable-database, even though the ignored key is the only reason the reachability check stays quiet. The init-style scaffold is this combination.

Additional Locations (1)
Fix in Cursor Fix in Web

Reviewed by Cursor Bugbot for commit ef0dc8c. Configure here.

const structural =
definition && typeof definition === 'object'
? checkModuleDefinition(definition, '')
: [];

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Module mode skips rateLimit warning

Medium Severity

frigg validate --module never runs the module-rate-limit-ignored check that app-mode validation adds. config.rateLimit therefore passes silently even though nothing applies it. A top-level rateLimit is rejected as an unknown key instead of the warning ADR-051 describes.

Additional Locations (1)
Fix in Cursor Fix in Web

Reviewed by Cursor Bugbot for commit ef0dc8c. Configure here.

seanspeaks added a commit that referenced this pull request Oct 24, 2026
devtools depends on @friggframework/test at the canary version. A
packages/test change ensures lerna/auto includes it when cutting the
#702 canary (same pattern as the core package.json bump).

Co-authored-by: Sean Matthews <sean.matthews@lefthook.co>
seanspeaks added a commit that referenced this pull request Oct 24, 2026
Retriggers a solo #702 canary after a concurrent #701/#702 release race
left @friggframework/core and @friggframework/test unpublished for
2.0.0--canary.702.0c74b9c.0 while devtools still depended on them.

Co-authored-by: Sean Matthews <sean.matthews@lefthook.co>
seanspeaks added a commit that referenced this pull request Oct 24, 2026
devtools depends on @friggframework/test at the canary version. A
packages/test change ensures lerna/auto includes it when cutting the
#702 canary (same pattern as the core package.json bump).

Co-authored-by: Sean Matthews <sean.matthews@lefthook.co>
seanspeaks added a commit that referenced this pull request Oct 24, 2026
Retriggers a solo #702 canary after a concurrent #701/#702 release race
left @friggframework/core and @friggframework/test unpublished for
2.0.0--canary.702.0c74b9c.0 while devtools still depended on them.

Co-authored-by: Sean Matthews <sean.matthews@lefthook.co>
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

release Create a release when this pr is merged

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants