feat(hydra-gates): a schema can declare that it carries no demo data - #781
Merged
Merged
Conversation
buildiq's register holds the schemas the app keeps about itself: the apps it
has built, their versions, the slug route index, the template store and the
export jobs it has run. ADR-111 rule 1 asks for three demo objects per schema,
so the generator wrote three of each, and on a demo instance that put three
apps in the Apps list and on the dashboard that cannot be opened. Their
applicationVersion rows carry the placeholder a format: uuid property gets
(00000000-0000-4000-8000-000000000000) and a manifest with no pages, so the
detail page renders empty and /apps/buildiq/builder/<slug>/ never resolves.
Three more sat in the template store beside the four real built-ins, and three
export-job rows read as finished exports nobody ran.
Every one of those objects satisfies its schema, which is why --check was green
on the dataset that broke the demo: conformance is about an object's shape, and
nothing in a schema says whether its rows are content somebody authors or
bookkeeping the app writes. So the app states it, the way a catalogue already
does:
"Application": { "x-openregister-demo-data": false, ... }
A string is accepted in place of false and printed as the reason. true and
absence both mean generate, which is what every schema in the fleet does today,
so nothing changes for an app that adds no marker.
Three places honour it:
- build() generates nothing for the schema, and does so BEFORE --keep carries
objects forward. An app adopting the marker regenerates an existing
descriptor, and the objects it wants gone are exactly the ones --keep
preserves.
- check() SKIPs it instead of demanding three, so the gate cannot ask for the
rows the app just removed.
- check() FAILs when a mock descriptor still carries objects for it. Skipping
alone would leave the broken rows in place for ever, and those rows are the
defect.
Six arms in test_generate_mock_register.py. Five go red with the generator
reverted (5 failures); the sixth is the control that true and absence still
generate, and is green both ways on purpose.
rubenvdlinde
added a commit
to ConductionNL/buildiq
that referenced
this pull request
Sep 18, 2026
…e opened (#853) * fix(demo-data): buildiq's own control-plane schemas carry no demo data The setup walkthrough's example data imported three objects for every schema in the buildiq register. That register holds the schemas buildiq keeps about itself, so the import created three apps that appear in the Apps list and on the dashboard and cannot be opened: their applicationVersion rows carry application: 00000000-0000-4000-8000-000000000000, the placeholder a format: uuid property gets, and a manifest with no pages, so the detail page renders empty and /apps/buildiq/builder/<slug>/ never resolves. Three more stood in the template store beside the four real built-ins and would clone into an equally empty app, and three export-job rows read as finished exports nobody ran. Seen on the demo instance on 2026-09-18, app c5a2e155-432b-4ea8-a965-56661b991463, slug ccdc. Every one of those objects satisfies its schema, which is why the generator and its --check were both green. Conformance is about an object's shape; nothing in a schema says whether its rows are content somebody authors or bookkeeping the app writes. Eight schemas now say so with x-openregister-demo-data, the marker ConductionNL/.github#781 adds: built-app the register of apps buildiq has built applicationVersion written by publish and promote built-app-route an index the Application lifecycle maintains application-template the store's starter packs export-job written by the export pipeline rule-execution-log written by the rule engine, a GDPR art. 22 record agent-run written by AgentRunLogger formDraft one person's half-filled form, owner-only hello-message keeps its three objects: it is the app's content schema and the reason the dataset exists. So do the schemas an administrator authors by hand (automation, buildAgent, component-block, pageLayout, registrationForm and the rule-set family): their rows are content, not bookkeeping, and none of them generates today anyway. Regenerated with the patched generator. The dataset goes from 18 objects to 3, and --check exits 0 with five SKIP lines that each say why. * fix(demo-data): the import refuses a dataset carrying buildiq's own bookkeeping The dataset is generated, so it can regress without anybody editing it: a generator run against a schema that has lost its declaration writes the control-plane objects straight back. They then import in silence, because they satisfy their schemas, OpenRegister has no opinion about what they mean, and the wizard reports a cheerful count over three apps that cannot be opened. DemoDataService now reads the x-openregister-demo-data declarations from the app's own descriptors, the same file the generator reads, and refuses the import before anything is written when the dataset addresses one of them. It throws rather than filtering: half a dataset is not what the operator asked for, and SetupController already surfaces the message. Three arms cover it, plus a guard on the shipped file: - DemoDataServiceTest: the refusal, that the importer is never called, and the control that an ordinary content schema still imports. - DemoDatasetExcludesControlPlaneTest: the shipped dataset carries no object for a declared schema, the five control-plane schemas still declare it with a reason, and hello-message still carries its three objects. Verified by mutation. Against the dataset shipped before this change the guard test reddens naming all five schemas and three objects each; with the refusal removed from install(), two of the three service arms redden and the control stays green. * style(demo-data): split the declaration reader so phpmd and phpcs are clean The first version put path discovery, the mock filter and the per-schema decision in one method: cyclomatic complexity 15 against a threshold of 10, an NPath of 1188 against 200, and five phpcs errors from the `?:` on glob and an unnamed argument. All NEW findings on lines this change wrote, so they are this PR's to fix. No behaviour change. phpcs, phpmd and phpmd-unusedparams all exit 0 on the file, and the sixteen demo-data tests still pass.
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
What this changes
A schema can now say that it carries no demo data:
A string is accepted in place of
falseand is printed as the reason.trueand absence both mean generate, so nothing changes for any app that adds no marker.Why
buildiq's register holds the schemas the app keeps about itself: the apps it has built, their versions, the slug route index, the template store, the export jobs it has run. ADR-111 rule 1 asks for three demo objects per schema, so the generator wrote three of each.
On the demo instance that produced three apps in the Apps list and on the dashboard that cannot be opened. Their
applicationVersionrows carry the placeholder aformat: uuidproperty gets,00000000-0000-4000-8000-000000000000, and a manifest with no pages, so the detail page renders empty and/apps/buildiq/builder/<slug>/never resolves. Three more sat in the template store beside the four real built-in templates and would clone into an equally empty app. Threeexport-jobrows read as finished exports nobody ran. Measured 2026-09-18 on appc5a2e155-432b-4ea8-a965-56661b991463, slugccdc.Every one of those objects satisfies its schema. That is why
--checkwas green on the dataset that broke the demo: conformance is about an object's shape, and nothing in a schema says whether its rows are content somebody authors or bookkeeping the app writes. So the app states it, the way a catalogue already does.Three places honour the marker
build()generates nothing for the schema, and it does so before--keepcarries objects forward. An app adopting the marker regenerates an existing descriptor, and the objects it wants gone are exactly the ones--keeppreserves.check()prints SKIP instead of demanding three, so gate 101 cannot ask for the rows the app just removed.check()prints FAIL when a mock descriptor still carries objects for the schema. Skipping alone would leave the broken rows in place for ever, and those rows are the defect.How this was verified
python3 hydra-gates/scripts/lib/test_generate_mock_register.py: 25 tests, exit 0.Six of them are new. Reverting
generate_mock_register.pyand rerunning turns five of the six red:The sixth,
test_true_and_absence_both_still_generate, is the control. It is green with and without the change on purpose: it is what separates "the exclusion works" from "the generator stopped generating".Blast radius
The fleet's apps run gate 101 from
ConductionNL/.github@main, so this lands everywhere the minute it merges. No app declares the marker today, so the SKIP arm and the FAIL arm are both unreachable until one does. The only behaviour change for an app that adds no marker is none.What merges after this
ConductionNL/buildiq marks its five control-plane schemas and regenerates its dataset. That PR's gate 101 needs this one on
mainfirst, otherwise the gate asks buildiq for the threebuilt-approws the PR removes.🤖 Generated with Claude Code