Repository navigation
Commit fff01da
authored
feat(requirements): requirement checks and test generators in every port (ADR-0057) (#410)
* docs(plan): requirements slice 1 — a uniform requirement-test filter in all five ports
The owner's answer to the plan's open question 8: the filter that selects
which requirements get a generated test offers the same options in every
port. Table I gains the filter and uncovered-warning rows, Table J gains
seven filter cases run through each port's predicate seam, and a separate
worked-example case replaces the double duty the plan gave concern-fanout.
Refs the plan and ADR-0057.
* docs(plan): requirements slice 1 — the requirement-tests generator ejects in every port
The owner's added requirement: whatever ships for requirements and testing
must eject and be owned by the application; the stock generator and the
witness model are a recommended approach. Table L records how each port's
existing eject mechanism takes the new generator and the byte-identity test
that proves an unedited copy, and the port tasks gain the wiring. The open
questions section becomes the record of the answers.
Refs the plan and ADR-0057.
* feat(verify): --require-implementers, and ADR-0057 reversing TypeScript-only requirement checks
Refs docs/superpowers/plans/2026-10-05-requirements-slice-1-checks-and-test-generators.md and ADR-0057.
* feat(codegen-ts): requirement test identities, the requirement digest and a per-member grain
The requirement walk gains the record every port's test generator agrees on (package, path, unit, id, witnessKey, status, skip, digest), the requirement-digest/v1 fingerprint of a claim, and a grain option that fans a requirement out per resolving reference instead of per concern. The default grain keeps its paths, test names and bytes; the renderer hook now receives the identity.
Refs docs/superpowers/plans/2026-10-05-requirements-slice-1-checks-and-test-generators.md and ADR-0057.
* feat(codegen-ts): a reference template for requirement-tests, so meta eject can hand it to the application
requirement-tests was package-only because no reference template existed. It now ships one holding the generator and the default stub renderer in a single file, since an eject copies one file and the stub text is what an application is most likely to change. The built-in stays the oracle: the copy is byte-identity-gated over a ledger with requirements, in both grains.
Refs docs/superpowers/plans/2026-10-05-requirements-slice-1-checks-and-test-generators.md and ADR-0057.
* test(conformance): requirement-check corpus, run by the TypeScript reference
42 cases under fixtures/requirement-check-conformance pin the requirement gate's codes, severities, paths, message text and summary counts, so the four other ports can be held to the TypeScript reference. Expectations are written by scripts/write-requirement-corpus-expected.ts and reviewed by hand; the corpus gets its row in docs/CONFORMANCE.md and the site payload its count, which the site-counts gate requires of any new corpus.
Refs docs/superpowers/plans/2026-10-05-requirements-slice-1-checks-and-test-generators.md and ADR-0057.
* docs(plan): requirements slice 1 — what building the corpora found
A 43rd check case so the strict switch cannot pass as warnings-as-errors,
file-name load order and the runner's coverage defaults as runner rules,
an unknown grain refused in every port, and the single-document rule for
the unpackaged identity case.
Refs the plan and ADR-0057.
* test(conformance): requirement-check corpus cases that a plausible wrong port would have passed
Adds require-implementers-raises-only-that-code (the strict switch leaves the deferral and coverage warnings at warn), a levelled architectural L4 with no links, a string-prefix probe for the undecided roll-up and a cross-package subtype extending by qualified name. The runner now validates option types and asserts the require-implementers input equals its twin; the README says what the supersededBy and did-you-mean cases really pin and names two runner preconditions.
Refs docs/superpowers/plans/2026-10-05-requirements-slice-1-checks-and-test-generators.md and ADR-0057.
* fix(codegen-ts): compare every branch of the requirement-tests reference template, and refuse an unknown grain
The byte-identity gate now reaches the custom-path warning, the capped uncovered list, the undecided gap line and the generator's name, target and orphan policy, and renders hand-built arguments through both renderers; the reference renderer reads the status as the built-in does. An unknown grain is refused by the identity functions and both generators instead of running half of each grain, and a non-ASCII digest is pinned so a character count cannot pass for a byte length.
Refs docs/superpowers/plans/2026-10-05-requirements-slice-1-checks-and-test-generators.md and ADR-0057.
* docs(plan): requirements slice 1 — every port's generator test refuses an unknown grain
No corpus pins the refusal, so each port's own test is the gate.
Refs the plan and ADR-0057.
* test(conformance): requirement-test identity corpus, run by the TypeScript reference
24 cases under fixtures/requirement-test-identity-conformance pin what may not differ between the ports' requirement-test generators: which tests a ledger yields, each test's id, witness key, skip state and claim digest, and the requirement view a project's filter is shown, through seven named predicates each port's runner implements. Expectations are written by scripts/write-requirement-corpus-expected.ts identity and were recomputed independently from the contract; docs/CONFORMANCE.md gains the corpus's row and the check corpus's current count (43), and AGENTS.md and the site payload the true corpora count (28).
Refs docs/superpowers/plans/2026-10-05-requirements-slice-1-checks-and-test-generators.md and ADR-0057.
* feat(java): the requirement gate in metaobjects:verify
Ports the TypeScript requirement gate (codes, order, message text, summary) to Java, held to it by the shared check corpus; Kotlin gets it through the same Maven goal. One did-you-mean helper is shared with the loader. Refs docs/superpowers/plans/2026-10-05-requirements-slice-1-checks-and-test-generators.md and ADR-0057.
* docs(plan): requirements slice 1 — what reviewing the identity corpus found
The effective package of a requirement nested under a package-declaring
parent is the parent's, as the reference has it; the mangle class is ASCII
and excludes the underscore; an eighth named predicate pins an absent
level; an abstract requirement is pinned as collected; and the check
corpus gains a member reference whose owner does not resolve.
Refs the plan and ADR-0057.
* fix(python): import PACKAGE_SEP in yaml_desugar, so a node-level package under a packaged root loads
A YAML node declaring its own package under a packaged root hit an undefined name at load; the desugar's package branch was otherwise correct (absolute taken literally, leading :: relative to the parent). Refs docs/superpowers/plans/2026-10-05-requirements-slice-1-checks-and-test-generators.md and ADR-0057.
* test(conformance): requirement-test identity corpus cases that an idiomatic wrong port would have passed
Review of the identity corpus found rules a wrong port could pass. filter-by-package now nests a child under each package-declaring requirement, witness-key-collision gains a doubled underscore, digest-multibyte-and-crlf a CR LF in the statement, and digest-claim-fields a pair differing only in supersededBy; two cases are new, filter-by-absent-level (an eighth named predicate, unlevelled) and abstract-collected. The runner's and the script's filter tables become Maps, so a name found on Object.prototype is refused, and the key function gets a direct test with letters outside ASCII.
Refs docs/superpowers/plans/2026-10-05-requirements-slice-1-checks-and-test-generators.md and ADR-0057.
* docs(plan): requirements slice 1 — say exactly which word class fails which mangle probe
Refs the plan and ADR-0057.
* feat(python): the requirement gate in metaobjects verify
Ports the requirement checks to Python, held to the TypeScript reference by the shared requirement-check corpus, and runs them on every verify. Refs docs/superpowers/plans/2026-10-05-requirements-slice-1-checks-and-test-generators.md and ADR-0057.
* test(conformance): a member reference whose owner does not resolve gets the object hint
dangling-object-did-you-mean gains an L5 claiming Invoice.total from a package where Invoice is not local: the message quotes the whole reference and the did-you-mean hint names the object. No case reached that branch of the dangling check before.
Refs docs/superpowers/plans/2026-10-05-requirements-slice-1-checks-and-test-generators.md and ADR-0057.
* feat(java): requirement-tests generator emitting JUnit with a typed witness interface
Adds the Java identity function and the ejectable JUnit Jupiter generator over the shared identity corpus, and hands the project class loader to a generator that loads a renderer or filter class by name. Refs docs/superpowers/plans/2026-10-05-requirements-slice-1-checks-and-test-generators.md and ADR-0057.
* fix(python): the requirement gate no longer fails open on an unexpected load error
The shared verify load helper caught every Exception, so a loader bug turned the gate off with exit 0 and no line. It now catches only the errors the loader and config readers raise, and the gate no longer retries a load that already failed. Adds config-mode CLI coverage of in_scope, the file count, the dependencies suffix and the undecided line, and a direct three-segment resolve_claim test. Refs docs/superpowers/plans/2026-10-05-requirements-slice-1-checks-and-test-generators.md and ADR-0057.
* feat(csharp): the requirement gate in dotnet meta verify
Ports the TypeScript requirement gate to C# (claim resolver, eleven codes plus object coverage, summary) and runs it on every verify; the shared 43-case corpus passes. A model with no requirement sees no change. Refs docs/superpowers/plans/2026-10-05-requirements-slice-1-checks-and-test-generators.md and ADR-0057.
* docs(plan): requirements slice 1 — one uncovered-warning text, stale files and load failures of a project's hook
Rulings from the Java generator's review that the C#, Kotlin and Python
generators must share.
Refs the plan and ADR-0057.
* fix(java): report a requirement-test filter or renderer that fails to link, and pin three unpinned output rules
A class found but unlinkable is no longer reported as missing; the uncovered warning names paths; sort, carriage-return escaping and the witness header are pinned; the identity runner has a case floor and its direct tests run once. Refs docs/superpowers/plans/2026-10-05-requirements-slice-1-checks-and-test-generators.md and ADR-0057.
* docs(plan): requirements slice 1 — which package-context shapes the ports are held to agree on
Two multi-file shapes differ between ports at the loader level and are
recorded, not pinned.
Refs the plan and ADR-0057.
* fix(csharp): the requirement gate formats numbers invariantly and refuses a level that overflows
Level saturates instead of wrapping and the gate reads the authored RawLevel; messages and printed lines format numbers with the invariant culture; the CLI test child no longer inherits META_REQUIRE_IMPLEMENTERS; the gate is exercised under --codegen. Refs docs/superpowers/plans/2026-10-05-requirements-slice-1-checks-and-test-generators.md and ADR-0057.
* feat(kotlin): requirement-tests generator emitting JUnit with a typed witness interface
Adds the ejectable Kotlin generator that writes one JUnit Jupiter test per declared requirement over the shared JVM identity function, registers it with its eject resource, and proves a package-renamed copy emits the same bytes. Refs docs/superpowers/plans/2026-10-05-requirements-slice-1-checks-and-test-generators.md and ADR-0057.
* feat(python): requirement-tests generator emitting pytest with project-owned witnesses
One machine-owned pytest file per package; each live test calls a project-owned witness function and fails naming the counterexample when there is none. Adds the identity function and digest (26/26 corpus cases), the requirementTests config block and an ejectable registry entry. Refs docs/superpowers/plans/2026-10-05-requirements-slice-1-checks-and-test-generators.md and ADR-0057.
* feat(csharp): requirement-tests generator emitting xUnit with a typed witness interface
Adds the C# identity function (digest, witness key, filter seam; all 26 identity-corpus cases pass) and an ejectable generator writing one xUnit test per requirement over a witness interface with default members. Options (TestNamespace, WitnessClass, Grain, Filter, Renderer, WarnUncovered) are public init properties on the generator because this port has no per-generator option channel; with none set, the namespace and witness class derive from the run namespace. Refs docs/superpowers/plans/2026-10-05-requirements-slice-1-checks-and-test-generators.md and ADR-0057.
* docs(plan): requirements slice 1 — the stale-witness compile signal is conditional in Java and C#
Table H stated it unconditionally. It holds by language rule only in
Kotlin; Java needs @OverRide and C# needs explicit interface
implementation, and each generated header must say so.
Refs the plan and ADR-0057.
* fix(csharp): generated requirement tests steer witnesses to explicit interface implementation, so a stale one stops compiling
The witness header now tells the project to implement each member explicitly (a stale one fails with CS0539), the limit of the implicit form is pinned, generated names use global:: and keyword or non-ASCII segments are handled, the generator selects through the function the identity corpus pins, and the owned copy is tested with a project filter and renderer. Refs docs/superpowers/plans/2026-10-05-requirements-slice-1-checks-and-test-generators.md and ADR-0057.
* fix(kotlin): pin the @test annotation on generated requirement tests, and escape keyword package segments
Kotlin: backtick-escape hard-keyword package segments; tests pin @test, the uncovered warning's default and nested paths, triple quotes, name refusals, a silenced log, a stale override failing to compile, and the shipped eject resource (maven-plugin). Java generator: the header now asks for @OverRide (the orphan-witness signal depends on it) and its test changes (@test, warning default and nested path, silenced log, stale override compile checks) are in this commit too. codegen-base: renderer javadoc is language-neutral. Refs docs/superpowers/plans/2026-10-05-requirements-slice-1-checks-and-test-generators.md and ADR-0057.
* fix(python): an ejected requirement-tests generator works with a project renderer, and one resolver for config symbols
The renderer hook types now live in the package, so an ejected copy accepts the RenderedTest a project renderer imports. Config symbols and owned generators share one resolver that never unloads an installed package. Also: witnessModule validated as a config error, a wrong renderer return is a clean error, member grain keeps the first duplicate reference, control characters are escaped in comments. Refs docs/superpowers/plans/2026-10-05-requirements-slice-1-checks-and-test-generators.md and ADR-0057.
* docs(requirements): the gate and the requirement-test generator in every port (ADR-0057)
Docs, agent skills, the changelog and the pillar summaries now state what ships per port: the requirement gate in every verify, an ejectable requirement-tests generator in every port presented as a recommended approach, the strict switch, the conditional stale-witness signal and the known cross-port differences. The project's own ledger is unchanged: no planned entry concerned the gate or the generated tests, and it omits implementedBy by design.
Refs docs/superpowers/plans/2026-10-05-requirements-slice-1-checks-and-test-generators.md and ADR-0057.
* docs(requirements): three remaining statements of the TypeScript-only split, and small corrections
Review round 1: two llms sentences and the Java README still said test scaffolding was TypeScript-only; the showcase config comment, the harness slot counts (115 and 575), the C# Program.cs example's using, and which ports the load-failure refusal applies to.
Refs docs/superpowers/plans/2026-10-05-requirements-slice-1-checks-and-test-generators.md and ADR-0057.
* fix(python): the project symbol resolver loads the right copy when another project's is cached
The resolver now drops a cached module that is not under the current project root (except the running metaobjects package and the standard library), so a config provider or another project cannot leave its copy answering for an owned generator. Path-aware root test, fullmatch for module names, and a hook-types docstring that says what each grain passes. Refs docs/superpowers/plans/2026-10-05-requirements-slice-1-checks-and-test-generators.md and ADR-0057.
* docs(loader): the requirement shape rule's comment no longer says the gate is TypeScript-only
The gate runs in every port's verify since ADR-0057; the rule stays in the loader because a refused shape is unreachable whether or not verify runs. Refs docs/superpowers/plans/2026-10-05-requirements-slice-1-checks-and-test-generators.md and ADR-0057.
* docs(plan): requirements slice 1 — record where the built code differs from the task text
An as-built table beside the amendments, and the Python eject destination
and hook-module corrections in Table L and Task 6.
Refs the plan and ADR-0057.
* fix(python): the project symbol resolver drops a cached module only when the project offers that name
An installed package named by several config hooks is now one module again; a project package that shadows a standard-library name is refused deterministically instead of by load order. Module:symbol patterns reject whitespace, and the docstrings state the final rule and the pre-existing holes. Refs docs/superpowers/plans/2026-10-05-requirements-slice-1-checks-and-test-generators.md and ADR-0057.
* fix(python): the requirement gate reports a model that does not load instead of passing silently
verify with no generators selected loaded nothing else, so metadata the loader refuses exited 0. The gate's own load is now strict unless --lax and reports its failure once, unless a gate that ran already printed it. Also: the stdlib-name refusal names the real path, the witness-key collision message matches the other ports, and tests pin the summary sentence and the library package set.
Refs docs/superpowers/plans/2026-10-05-requirements-slice-1-checks-and-test-generators.md and ADR-0057.
* fix(csharp): the requirement gate reports a failed load on the handed-off codegen path
When --codegen ran in an owned codegen/ project, stopped for want of --out, or only --db was asked for, no gate in the process loaded the model and a failed load was skipped with nothing said. The gate now prints the load errors and returns 1, unless a gate that ran here already reported them. Also: the generated witness header names the interface with its namespace, a dead regex is removed, and tests pin the summary sentence, the recorded-gaps line and the library package set.
Refs docs/superpowers/plans/2026-10-05-requirements-slice-1-checks-and-test-generators.md and ADR-0057.
* fix(java): a requirement-test hook whose constructor throws is reported with its real cause
A renderer or filter whose constructor threw was told it needs a public no-argument constructor, in the Java and the Kotlin generator; both now name what was thrown. Also: the Maven goal logs every error before any warning, getLevel() saturates instead of wrapping, the requirement javadoc no longer says the checks are the Node CLI's or that an architectural requirement carries no level, and tests pin the summary sentence, the recorded-gaps line, the claims comment under member grain and the library package set.
Refs docs/superpowers/plans/2026-10-05-requirements-slice-1-checks-and-test-generators.md and ADR-0057.
* fix(codegen-ts): named package separator in the requirement walk, and hermetic strict-switch tests
The qualified address was built with a literal separator where PACKAGE_SEPARATOR exists. The verify end-to-end tests read the ambient META_REQUIRE_IMPLEMENTERS and failed with it exported; each test now starts with it unset and restores it after.
Refs docs/superpowers/plans/2026-10-05-requirements-slice-1-checks-and-test-generators.md and ADR-0057.
* docs(requirements): the decision record and port pages state the final behaviour
ADR-0057 says what is realized and states the stale-witness signal per language. The port pages, the changelog, the ledger spec and the corpus README are corrected where a review found them wrong or silent: the owned Program.cs advice for C#, the Python refusal of a project package under a standard-library name, how hooks and providers are imported, the Kotlin generator count, which loaders refuse a non-integer level, bare-name binding, and what verify does with metadata that does not load.
Refs docs/superpowers/plans/2026-10-05-requirements-slice-1-checks-and-test-generators.md and ADR-0057.1 parent e0fc3f4 commit fff01da
325 files changed
Lines changed: 21927 additions & 319 deletions
File tree
- agent-context/skills
- metaobjects-audit/references
- metaobjects-authoring/references
- metaobjects-codegen/references
- metaobjects-verify/references
- docs
- features
- llms
- ports
- superpowers/plans
- examples/showcase
- fixtures
- agent-context-conformance
- java-kotlin-react-tanstack/expected/.claude/skills/metaobjects-codegen/references
- java-react/expected/.claude/skills/metaobjects-codegen/references
- python/expected/.claude/skills/metaobjects-codegen/references
- ts-react-tanstack/expected/.claude/skills/metaobjects-codegen/references
- ts-requirements/expected/.claude/skills
- metaobjects-audit/references
- metaobjects-authoring/references
- metaobjects-codegen/references
- metaobjects-verify/references
- generator-registry-conformance
- requirement-check-conformance
- arch-levelled-tree
- input
- arch-live-no-implementers
- input
- arch-mixed-grain-clean
- input
- arch-planned-clean
- input
- arch-retired-clean
- input
- arch-unlevelled-exempt
- input
- bad-level-out-of-range
- input
- claim-on-root-template
- input
- claim-package-local
- input
- clean-fully-claimed
- input
- coverage-arch-claim-propagates
- input
- coverage-exemptions
- input
- coverage-functional-claim-does-not-propagate
- input
- coverage-library-only-not-measured
- input
- coverage-library-overlay-does-not-activate
- input
- coverage-library-plus-project
- input
- coverage-planned-claim-does-not-count
- input
- coverage-unclaimed-entity
- input
- dangling-bare-name-in-two-packages
- input
- dangling-member-first-missing-segment
- input
- dangling-member-of-resolved-object
- input
- dangling-object-did-you-mean
- input
- dangling-object-live
- input
- dangling-object-partial
- input
- dangling-object-planned-clean
- input
- deferred-untracked
- input
- disposition-not-applicable
- input
- l4-names-member
- input
- l5-member-resolves-clean
- input
- l5-names-object
- input
- level-nesting
- input
- link-above-floor
- input
- no-requirements
- input
- nothing-implements-delegating-parent-clean
- input
- nothing-implements-subtree
- input
- require-implementers-raises-only-that-code
- input
- require-implementers
- input
- retired-clean
- input
- same-name-in-two-branches
- input
- summary-undecided-rollup
- input
- superseded-by-dangling
- input
- superseded-by-package-local
- input
- superseded-by-resolves-clean
- input
- requirement-harness
- requirement-test-identity-conformance
- abstract-collected
- input
- concern-fanout
- input
- default-filter
- input
- digest-claim-fields
- input
- digest-inherited
- input
- digest-multibyte-and-crlf
- input
- filter-all
- input
- filter-by-absent-level
- input
- filter-by-claimed-concern
- input
- filter-by-level
- input
- filter-by-package
- input
- filter-by-path
- input
- filter-by-status
- input
- filter-by-subtype
- input
- member-grain-duplicate-ref
- input
- member-grain-unresolved-dropped
- input
- member-grain
- input
- nested-path
- input
- no-targets
- input
- package-in-address
- input
- partial-not-skipped
- input
- planned-skip
- input
- retired-skip
- input
- unpackaged
- input
- witness-key-collision
- input
- worked-example
- input
- scripts
- site
- server
- csharp
- MetaObjects.Cli.Tests
- MetaObjects.Cli
- MetaObjects.Codegen.Tests
- MetaObjects.Codegen
- Generators
- MetaObjects.Conformance.Tests
- MetaObjects
- Core/Requirement
- Library
- Meta
- java
- codegen-base/src/main/java/com/metaobjects/generator
- requirement
- codegen-kotlin
- src
- main/kotlin/com/metaobjects/generator/kotlin
- test/kotlin/com/metaobjects/generator/kotlin
- codegen-spring
- src
- main/java/com/metaobjects/generator
- spring
- test/java/com/metaobjects/generator/spring
- maven-plugin/src
- main/java/com/metaobjects/mojo
- test/java/com/metaobjects/mojo
- metadata/src
- main/java/com/metaobjects
- library
- loader
- requirement
- test/java/com/metaobjects
- conformance
- library
- requirement
- python
- src/metaobjects
- codegen
- generators
- config
- library
- loader
- meta/core/requirement
- tests
- codegen
- conformance
- loader
- unit
- typescript/packages
- cli
- src
- commands
- lib
- test
- __snapshots__
- unit
- codegen-ts
- src
- generators
- reference
- templates
- test
- metadata/src/loader
- spec
- decisions
Some content is hidden
Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.
| Original file line number | Diff line number | Diff line change | |
|---|---|---|---|
| |||
6 | 6 | | |
7 | 7 | | |
8 | 8 | | |
9 | | - | |
| 9 | + | |
10 | 10 | | |
11 | 11 | | |
12 | 12 | | |
13 | | - | |
| 13 | + | |
14 | 14 | | |
15 | 15 | | |
16 | 16 | | |
17 | 17 | | |
18 | 18 | | |
19 | | - | |
| 19 | + | |
20 | 20 | | |
21 | 21 | | |
22 | 22 | | |
| |||
75 | 75 | | |
76 | 76 | | |
77 | 77 | | |
78 | | - | |
| 78 | + | |
79 | 79 | | |
80 | 80 | | |
81 | 81 | | |
| |||
0 commit comments