feat: model NewRecruit schema additions over BattleScribe v2.03 - #308
Merged
Conversation
NewRecruit evolved the BattleScribe catalogue/gameSystem data format with new nodes, enum values, and attributes. Model them as part of the format: - Enum values: SelectionEntryKind +unit-group/mount/crew; ConstraintKind +exactly; ConditionKind +always/never/before; ConditionGroupKind +the numeric/comparison set; ModifierKind +the math/string ops (+hide). - New nodes: AssociationCore, AttributeTypeCore, LocalConditionGroupCore. - New collections: selectionEntry `associations`; modifier `localConditionGroups`; profileType `attributeTypes`; catalogue-root `sharedForceEntries`/`sharedAssociations`. - New attributes: constraint negative/automatic/message; charType kind/defaultValue; profileType kind. - latest/Catalogue.xsd extended to declare all of the above so the model validates against the schema (Source.Tests schema-validation green). The serializer normally writes every value-type attribute. negative/automatic are NR-only, so emitting them on every constraint broke round-trip fidelity with original BattleScribe data (which has neither). Teach the generated writer to honor [DefaultValue]: a value-type attribute equal to its DefaultValue is omitted. negative/automatic carry [DefaultValue(false)], so BattleScribe data round-trips byte-identically while NR data still emits them when set. Adds NewRecruitAdditionsTests: schema-validation + serialize/deserialize round-trip for the new nodes, and a guard that default constraint flags stay out of the output. Full wham suite green. Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01U2KM751pP6hYS8GztAMnQw
amis92
added a commit
to WarHub/battlescribe-spec
that referenced
this pull request
Jun 23, 2026
Catalogue/gameSystem axis marked complete; roster axis audited (no confirmed .ros format additions, one deferred question); remaining = wham re-pin after WarHub/wham#308 merges + the optional roster association-state spike. Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01U2KM751pP6hYS8GztAMnQw
amis92
added a commit
to WarHub/battlescribe-spec
that referenced
this pull request
Jun 23, 2026
WarHub/wham#308 merged. Re-pin the submodule from the PR branch to the squash- merge commit on wham main (7770868). Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01U2KM751pP6hYS8GztAMnQw
amis92
added a commit
to WarHub/battlescribe-spec
that referenced
this pull request
Jun 23, 2026
…cs (#267) * feat(gamedata): NR-superset — discover tooling + schema-additions specs Treat NewRecruit's additions to the BattleScribe data format as the base spec, with original BattleScribe the excluded subset. Both NR engines must satisfy them; battlescribe/battlescribe-ui are skipped. - `bs-spec discover nodes|enums|xml` (DiscoverCommand): drives the frozen NR editor headlessly to dump creatable node types, dropdown vocabularies, and byte-exact serialized XML. Seed: tools/discovery/seed.yaml (outside specs/). - Harness extended to the NR-superset: CatXmlGenerator (generic [XmlEnum] reflection mapper + new-node mappers), ProtocolMessages (+ association / attributeType / localConditionGroup), spec/protocol JSON schemas, assertion model (GameDataTypes/SpecModels/Runner), and both NR engines' read paths. - 10 specs under specs/gamedata/nr/ (engines: battlescribe/battlescribe-ui skip), green on newrecruit + newrecruit-ui: association/exactly, selection entry types, type-def additions, localConditionGroup, conditionGroup types, extended modifier types, condition types, condition `before`, query vocab (associations / root-entry / limit::<costType>), shared collections. - docs/nr-schema-additions/ inventory + docs/gamedata-coverage.md NR-superset section. Re-pins .deps/wham to the NewRecruit schema-additions branch (to be re-pinned to the merged wham SHA before this merges). Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01U2KM751pP6hYS8GztAMnQw * docs(gamedata): correct roster-additions audit — no .ros format additions Audit of the roster axis: customName/customNotes are baseline original- BattleScribe roster format (v2_03 roster schema RosterElementBase/Roster), not NR additions — the NR aspect is purely behavioural (NR builder can set them, original BattleScribe can't) and is already covered by protocol-kitchen-sink.yaml's setCustomization steps + nr-behavioral-differences. duplicateForce and friends are runtime ops, also covered. The one open .ros-format question — whether a roster selection serialises chosen-association state — is deferred with reason: the army builder's roster serializer is a separate app from the NR editor and is not reachable by the catalogue discover trick; confirming it needs a live army-builder capture spike. Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01U2KM751pP6hYS8GztAMnQw * docs(gamedata): finalize NR schema-additions README status Catalogue/gameSystem axis marked complete; roster axis audited (no confirmed .ros format additions, one deferred question); remaining = wham re-pin after WarHub/wham#308 merges + the optional roster association-state spike. Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01U2KM751pP6hYS8GztAMnQw * chore: re-pin .deps/wham to merged NewRecruit schema-additions SHA WarHub/wham#308 merged. Re-pin the submodule from the PR branch to the squash- merge commit on wham main (7770868). Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01U2KM751pP6hYS8GztAMnQw * fix(cli): rename `_e` disposal local to satisfy naming analyzer The build enforces code style as errors; `using var _e = engine;` tripped the "prefix '_' is not expected" naming rule. Rename to `engineScope`. Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01U2KM751pP6hYS8GztAMnQw --------- Co-authored-by: Claude Opus 4.8 <noreply@anthropic.com>
This was referenced Jul 31, 2026
Closed
amis92
added a commit
that referenced
this pull request
Jul 31, 2026
Restores documentation and adds the test coverage that came with #221, the original `prepend` contribution. `ModifierKind.Prepend` reached `main` via #308, which modelled the whole NewRecruit block at once under a single `//` comment. The enum value and the XSD enumeration both landed, but two things from #221 did not: - the doc comment describing what `prepend` does, while every pre-NewRecruit member of this enum carries one - test coverage — nothing anywhere in `tests/` exercised `prepend` Adds: - doc comments for `Prepend` (verbatim from #221) and `Replace` - `String_modifier_kinds_round_trip` — asserts `prepend`/`append`/`replace` serialise to the expected wire name and survive a round-trip - `String_modifier_kinds_are_schema_validated` — asserts they validate against `Catalogue.xsd` The existing `NewRecruit_additions_round_trip` covers numeric kinds (`multiply`) but no string operation, so this was a real gap. Credit for the original `prepend` work goes to @The4D6 in #221. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
amis92
added a commit
that referenced
this pull request
Jul 31, 2026
Restores documentation and adds the test coverage that came with #221, the original `prepend` contribution. `ModifierKind.Prepend` reached `main` via #308, which modelled the whole NewRecruit block at once under a single `//` comment. The enum value and the XSD enumeration both landed, but two things from #221 did not: - the doc comment describing what `prepend` does, while every pre-NewRecruit member of this enum carries one - test coverage — nothing anywhere in `tests/` exercised `prepend` Adds: - doc comments for `Prepend` (verbatim from #221) and `Replace` - `String_modifier_kinds_round_trip` — asserts `prepend`/`append`/`replace` serialise to the expected wire name and survive a round-trip - `String_modifier_kinds_are_schema_validated` — asserts they validate against `Catalogue.xsd` The existing `NewRecruit_additions_round_trip` covers numeric kinds (`multiply`) but no string operation, so this was a real gap. Credit for the original `prepend` work goes to @The4D6 in #221. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
This was referenced Jul 31, 2026
amis92
added a commit
that referenced
this pull request
Jul 31, 2026
Restores documentation and adds the test coverage that came with #221, the original `prepend` contribution. `ModifierKind.Prepend` reached `main` via #308, which modelled the whole NewRecruit block at once under a single `//` comment. The enum value and the XSD enumeration both landed, but two things from #221 did not: - the doc comment describing what `prepend` does, while every pre-NewRecruit member of this enum carries one - test coverage — nothing anywhere in `tests/` exercised `prepend` Adds: - doc comments for `Prepend` (verbatim from #221) and `Replace` - `String_modifier_kinds_round_trip` — asserts `prepend`/`append`/`replace` serialise to the expected wire name and survive a round-trip - `String_modifier_kinds_are_schema_validated` — asserts they validate against `Catalogue.xsd` The existing `NewRecruit_additions_round_trip` covers numeric kinds (`multiply`) but no string operation, so this was a real gap. Credit for the original `prepend` work goes to @The4D6 in #221. Co-authored-by: Claude Opus 5 <noreply@anthropic.com>
amis92
added a commit
that referenced
this pull request
Jul 31, 2026
`[Unreleased]` had been empty since 0.14.0 (28 Feb) even though several changes had landed. Brings it up to date with everything currently on `main`: - the roster-engine stack (#315-#322) and the YAML reader (#325) - the NewRecruit format additions (#308) and the MSBuild targets file (#313) - the zipped-datafile fix (#324) and the dependency bump (#327) - the `prepend` documentation and tests (#326), crediting @The4D6 for the original contribution in #221 The `NodeFactory.Force` breaking change is called out explicitly with the migration, since it lands in the shipped `WarHub.ArmouryModel.Source` package. Co-authored-by: Claude Opus 5 <noreply@anthropic.com>
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.
Summary
NewRecruit reimplemented the abandoned BattleScribe data engine and then evolved the catalogue/gameSystem data format. This models those additions as part of the format, so downstream tooling (e.g. the BattleScribe conformance spec suite) can treat the NR-superset as the base and exclude only original BattleScribe.
Model additions
SelectionEntryKind+unit-group/mount/crew;ConstraintKind+exactly;ConditionKind+always/never/before;ConditionGroupKind+the numeric/comparison set (not,count,add…notEqual);ModifierKind+the math/string ops (multiply…replace,hide).AssociationCore,AttributeTypeCore,LocalConditionGroupCore.associations; modifierlocalConditionGroups; profileTypeattributeTypes; catalogue-rootsharedForceEntries/sharedAssociations.negative/automatic/message; characteristicTypekind/defaultValue; profileTypekind.latest/Catalogue.xsdextended to declare all of the above (the single source XSD that is transformed into the three namespace schemas at build), so the model validates against the schema.Serializer fix — preserve BattleScribe round-trip fidelity
The generated writer emits every value-type attribute (only nullable strings are skipped at runtime). So
negative/automatic(non-nullablebool) would have written="false"on every constraint, breaking round-trip with original BattleScribe data that has neither attribute (ReadWriteCatalogue/ReadWriteGamesystem).Fix: teach
WhamSerializerGeneratorto honor[DefaultValue]— a value-type attribute equal to its declared default is omitted.negative/automaticcarry[DefaultValue(false)], so original BattleScribe data round-trips byte-identically while NewRecruit data still emits them when set.Tests
NewRecruitAdditionsTests: schema-validation of a catalogue exercising all new nodes/enums/attributes; a serialize → deserialize round-trip; and a guard that default constraint flags stay out of the output.🤖 Generated with Claude Code