Skip to content

feat(verify)!: strict-by-default with --lax escape (ADR-0023 cross-port consistency) (#96)#101

Merged
dmealing merged 1 commit into
mainfrom
feat/verify-strict-default-96
Jun 29, 2026
Merged

feat(verify)!: strict-by-default with --lax escape (ADR-0023 cross-port consistency) (#96)#101
dmealing merged 1 commit into
mainfrom
feat/verify-strict-default-96

Conversation

@dmealing

Copy link
Copy Markdown
Member

What & why

meta verify (TS) and metaobjects verify (Python) now load metadata strict by default. An undeclared or typo'd own @attr is ERR_UNKNOWN_ATTR and verify exits non-zero. This closes the ADR-0023 gap where such an attr silently passed verify in TS/Python but was rejected by Java's Maven metaobjects:verify goal (which already forces strict via LoaderOptions.create(false, false, true)).

A new --lax flag restores the previous open-attr load.

Closes #96.

Breaking change

verify is strict by default. A project whose metadata carries an attr no provider declares — a typo, or a vendor attr that was silently tolerated — now fails verify.

Scope: only verify defaults strict. gen / docs / agent-docs keep loading lax (a possible follow-up: extend strict to gen, deferred here).

Migration (the failure message names all three):

  • register the attr on a metadata provider, or
  • move arbitrary author-supplied properties into an attr.properties bag, or
  • run meta verify --lax to keep the legacy open-attr load.

Before / after

# metadata with a typo'd @ttribute on a field.string

# before
$ meta verify        → exit 0  (silently passed)

# after
$ meta verify        → exit 1  ERR_UNKNOWN_ATTR + actionable hint
$ meta verify --lax  → exit 0  (legacy behavior, opt-in)

Implementation

  • TSLoadMemoryOptions.strict threaded into the loader; verify passes strict: !flags.lax; parseVerifyArgs gains --lax; the ERR_UNKNOWN_ATTR catch prints the three-exit hint.
  • Python_load_root(..., strict=False) + _generate(..., strict=False) threaded; --codegen / --templates verify paths pass strict = not args.lax; --lax added to the verify subparser; same actionable hint. gen / docs keep the default-lax load.
  • Forge layer strict-clean (sdk)loadMemory bundles Meta Forge descriptive types (decision/principle/…) + @forge* provenance attrs so mixed content loads. Under strict these were rejected, so the forge provider now admits its types under metadata.root and registers @forge* as common attrs. Also dropped the retired @dbTable no-op attrs from the trainer-website test fixture (source.rdb @table already holds the physical name).
  • Cross-port fixturefixtures/verify-strict-conformance/ (a registered node carrying one made-up @attr), asserted by both the TS and Python CLI verify-strict tests. The loader-level cross-port ERR_UNKNOWN_ATTR gate already exists at fixtures/conformance/error-unknown-attr/ (all five ports); Java's Maven goal already enforces strict.

Test evidence

RED → GREEN per port:

  • TS verify-strict.test.ts — RED: strict default returned 0 / --lax unknown; GREEN after impl (3 pass). args-verify.test.ts updated for the lax field + a --lax parse test.
  • Python test_cli_verify_strict.py — RED: --codegen/--templates returned 0, --lax unrecognized; GREEN after impl (5 pass).

Full suites:

  • TS bun test — 4826 pass, 2 fail (both pre-existing, confirmed on the clean base: a metamodel-docs byte fixture + a package-manager-detection test; neither touches verify/strict/forge). Whole-workspace typecheck green.
  • Python pytest tests/codegen — 257 pass, 2 fail (both pre-existing: test_cli_staleness_nudge asserts an old "metaobjects agent-docs" string vs the current "npx meta agent-docs" message — unrelated to strict load).
  • Fixed the 2 real verify-subverbs failures my change first surfaced (the forge-layer + stale-fixture findings above).

🤖 Generated with Claude Code

…rt consistency) (#96)

`meta verify` (TS) and `metaobjects verify` (Python) now load metadata strict by
default: an undeclared/typo'd own @attr is ERR_UNKNOWN_ATTR and verify exits
non-zero. This closes the ADR-0023 gap where such an attr silently passed verify
in TS/Python but was rejected by Java's Maven metaobjects:verify goal (which
already forces strict via LoaderOptions.create(false,false,true)).

A new --lax flag restores the legacy open-attr load. Scope is verify only — gen /
docs / agent-docs keep loading lax. The failure message points the author at the
three exits: register the attr on a provider, use the attr.properties bag, or --lax.

Also makes loadMemory's Meta Forge descriptive layer strict-clean: the forge
provider now admits its types (decision/principle/…) under metadata.root and
registers the @forge* provenance attrs as common attrs, so a real memory record
verifies clean instead of ERR_CHILD_NOT_ALLOWED / ERR_UNKNOWN_ATTR. Dropped the
retired @dbTable no-op attrs from the trainer-website test fixture (source.rdb
@table already carries the physical name).

Shared cross-port fixture (fixtures/verify-strict-conformance/) asserted by both
the TS and Python CLI verify-strict tests.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01LuZWKnWzYGVnESijL7uuky
@dmealing
dmealing merged commit b8efc8f into main Jun 29, 2026
27 of 29 checks passed
@dmealing
dmealing deleted the feat/verify-strict-default-96 branch June 29, 2026 15:48
dmealing added a commit that referenced this pull request Jun 29, 2026
…) (#107)

`dotnet meta verify` loaded metadata LAX, so an unregistered or typo'd own
`@attr` silently passed verify in C# while Java's force-strict Maven goal and
the strict TS/Python verify CLIs (#101) reject it — a port-dependent provenance
verdict (ADR-0023). This completes the C# half of #96.

- Thread `strict` through both verify load sites (`VerifyCommand.Run` and the
  `--codegen` gate) via a new `Options.Strict` (default true). The convenience
  `MetaDataLoader.FromDirectory` gains a `strict` param (default false / lax);
  `gen`/`docs`/`agent-docs` keep loading lax.
- Add a `--lax` flag to `verify` arg parsing (sets strict=false) to restore the
  legacy open-attr load.
- On a strict `ERR_UNKNOWN_ATTR` failure, print an actionable three-exit hint
  (register a provider / use an `attr.properties` bag / pass `--lax`). The
  loader error code/text is unchanged.

TDD: VerifyStrictTests — a metadata dir with one made-up `@attr` FAILS verify by
default (ERR_UNKNOWN_ATTR, exit 1) and PASSES with `--lax`. Cli/Conformance/
Codegen/Render suites all green; no repo-own fixture surfaced an unregistered attr.

Part of #96.


Claude-Session: https://claude.ai/code/session_01LuZWKnWzYGVnESijL7uuky

Co-authored-by: Claude Opus 4.8 <noreply@anthropic.com>
dmealing added a commit that referenced this pull request Jun 29, 2026
…als (#96) (#108)

Under 7.5.x sealed strict provenance (ADR-0023) the Maven goals load
force-strict, so an adopter mid-migration who still carries an unregistered
@Attribute (real cases: @isJson, @dataflow*) is blocked from running
metaobjects:generate / :verify — a hard upgrade-blocker. TS + Python verify
already grew a --lax escape (#101); the Maven port had none.

Add a shared `meta.lax` parameter on AbstractMetaDataMojo (inherited by the
generate and verify goals — and the docs goal, which shares the base):

  @parameter(property = "meta.lax", defaultValue = "false")

The flag flows to LoaderOptions.isStrict() on BOTH loader-creation paths — the
LoaderOptions on the manual-loader path, and the `strict` loader argument
(honored by MetaDataLoader.processArguments) on the configured-class path.
Default (lax=false) is strict; -Dmeta.lax=true opts out.

Also closes a latent gap: strict provenance is RECORD-not-throw at the loader
(ADR-0023 records ERR_UNKNOWN_ATTR and continues), but the mojo never drained
loader.getErrors(), so a strict violation passed silently. createLoader — the
shared site for both goals — now fails the build on recorded loader errors and,
for ERR_UNKNOWN_ATTR, appends an actionable hint (register a provider / use the
attr.properties bag / -Dmeta.lax=true). The loader error code/text is unchanged;
the hint is composed at the mojo level.

Tests (TDD, RED→GREEN): MetaLaxStrictOptOutTest drives both mojos with a fixture
carrying an unregistered @isJson — fails by default (naming the attr + the
-Dmeta.lax=true escape), succeeds with lax=true — plus a unit assertion that
lax=true => isStrict()==false and default => strict. The three pre-existing
gen/docs tests share a fixture with a custom @simple::fruitbasket::isKey attr;
they are provenance-agnostic, so their POMs now set <lax>true</lax> (the exact
migration story this feature enables, and integration evidence the @parameter
binds through real Maven config). maven-plugin module: 23 tests, 0 failures.


Claude-Session: https://claude.ai/code/session_01LuZWKnWzYGVnESijL7uuky

Co-authored-by: Claude Opus 4.8 <noreply@anthropic.com>
dmealing added a commit that referenced this pull request Jun 29, 2026
…t (4 ports), formFile (#109)

The squash-merges didn't carry per-PR CHANGELOG entries to [Unreleased]. Consolidate:
- Correct + complete the verify strict-by-default entry to cover all four CLI ports
  and the #108 finding that Java was record-not-draining (silently passing), now a
  real fail-on-recorded-error gate + -Dmeta.lax (#101/#107/#108).
- Add the jsonb open-bag → parsed-JSON-value contract change across all five ports (#98).
- Add the formFile nested value-object sub-forms feature (#95).


Claude-Session: https://claude.ai/code/session_01LuZWKnWzYGVnESijL7uuky

Co-authored-by: Claude Opus 4.8 <noreply@anthropic.com>
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

verify: strict-by-default (ADR-0023) enforced in Java but NOT in the TS/Python verify CLIs — port-dependent provenance verdict

1 participant