xdrs-core 0.55.0 → 0.56.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (26) hide show
  1. package/.xdrs/_core/adrs/index.md +2 -0
  2. package/.xdrs/_core/adrs/principles/001-xdrs-standards.md +1 -0
  3. package/.xdrs/_core/adrs/principles/002-policy-standards.md +2 -0
  4. package/.xdrs/_core/adrs/principles/003-skill-standards.md +6 -33
  5. package/.xdrs/_core/adrs/principles/004-article-standards.md +5 -0
  6. package/.xdrs/_core/adrs/principles/006-research-standards.md +5 -0
  7. package/.xdrs/_core/adrs/principles/007-initiative-standards.md +5 -0
  8. package/.xdrs/_core/adrs/principles/010-scope-governance.md +2 -2
  9. package/.xdrs/_core/adrs/principles/011-core-scope-type.md +1 -1
  10. package/.xdrs/_core/adrs/principles/019-compiled-scope-type.md +6 -1
  11. package/.xdrs/_core/adrs/principles/022-scope-activation.md +3 -1
  12. package/.xdrs/_core/adrs/principles/023-skill-runtime-standards.md +63 -0
  13. package/.xdrs/_core/adrs/principles/024-sync-date-frontmatter.md +76 -0
  14. package/.xdrs/_core/adrs/principles/skills/compile-scope/SKILL.md +10 -8
  15. package/.xdrs/_core/adrs/principles/skills/review/SKILL.md +5 -6
  16. package/.xdrs/_core/adrs/principles/skills/write-article/SKILL.md +3 -3
  17. package/.xdrs/_core/adrs/principles/skills/write-initiative/SKILL.md +3 -3
  18. package/.xdrs/_core/adrs/principles/skills/write-policy/SKILL.md +3 -3
  19. package/.xdrs/_core/adrs/principles/skills/write-research/SKILL.md +3 -3
  20. package/.xdrs/_core/adrs/principles/skills/write-skill/SKILL.md +9 -8
  21. package/.xdrs/_core/adrs/principles/skills/write-xdrs-doc/SKILL.md +4 -4
  22. package/.xdrs/_core/index.md +1 -1
  23. package/README.md +2 -1
  24. package/lib/lint.js +61 -16
  25. package/lib/lint.test.js +293 -4
  26. package/package.json +1 -1
package/lib/lint.test.js CHANGED
@@ -5905,16 +5905,147 @@ test('reports a local scope whose type is defined only in a disabled scope as fr
5905
5905
  expect(activationErrors(result)).toContain('Local scope "shop" is frozen (read-only) because scope type "widget" is defined only in disabled scope(s) "widgets-core"');
5906
5906
  });
5907
5907
 
5908
- test('reports missing dependencies of a disabled local scope as errors [022.05]', () => {
5908
+ test('does not report missing dependencies of a disabled scope [022.06]', () => {
5909
5909
  const workspaceRoot = createWorkspace('activation-disabled-local-missing-deps', {
5910
5910
  '.xdrs/index.md': rootIndex(['[_core](_core/index.md)', '[View scope myteam](myteam/index.md) `disabled`', ACTIVATION_LEGEND]),
5911
5911
  ...scopeFiles('myteam', 'follows: ghost-core\nextends: ghost-lib\n', 'phantom'),
5912
5912
  ...coreWithScopeTypes(['standard']),
5913
5913
  });
5914
5914
  const errors = lintWorkspace(workspaceRoot, { ignoreExternal: false }).errors.join('\n');
5915
- expect(errors).toContain('follows references scope "ghost-core" which does not exist in the workspace');
5916
- expect(errors).toContain('ghost-lib');
5917
- expect(errors).toContain('phantom');
5915
+ expect(errors).not.toContain('ghost-core');
5916
+ expect(errors).not.toContain('ghost-lib');
5917
+ expect(errors).not.toContain('phantom');
5918
+ });
5919
+
5920
+ test('does not report a disabled scope extending a disabled scope [022.06]', () => {
5921
+ const workspaceRoot = createWorkspace('activation-disabled-extends-disabled', {
5922
+ '.xdrs/index.md': rootIndex(['[_core](_core/index.md)', '[View scope lib](lib/index.md) `disabled`', '[View scope mid](mid/index.md) `disabled`', ACTIVATION_LEGEND]),
5923
+ ...scopeFiles('lib'),
5924
+ ...scopeFiles('mid', 'extends: lib\n'),
5925
+ });
5926
+ const result = lintWorkspace(workspaceRoot, { ignoreExternal: false });
5927
+ expect(activationErrors(result)).toBe('');
5928
+ expect(result.errors.join('\n')).not.toContain('frozen');
5929
+ });
5930
+
5931
+ test('does not report a disabled scope following a disabled core scope [022.06]', () => {
5932
+ const workspaceRoot = createWorkspace('activation-disabled-follows-disabled', {
5933
+ '.xdrs/index.md': rootIndex(['[_core](_core/index.md)', '[View scope area-core](area-core/index.md) `disabled`', '[View scope myteam](myteam/index.md) `disabled`', ACTIVATION_LEGEND]),
5934
+ ...scopeFiles('area-core', '', 'core'),
5935
+ ...scopeFiles('myteam', 'follows: area-core\n'),
5936
+ });
5937
+ expect(activationErrors(lintWorkspace(workspaceRoot, { ignoreExternal: false }))).toBe('');
5938
+ });
5939
+
5940
+ test('does not report a disabled scope whose type is defined only in a disabled scope [022.06]', () => {
5941
+ const workspaceRoot = createWorkspace('activation-disabled-type-in-disabled', {
5942
+ '.xdrs/index.md': rootIndex(['[_core](_core/index.md)', '[View scope widgets-core](widgets-core/index.md) `disabled`', '[View scope shop](shop/index.md) `disabled`', ACTIVATION_LEGEND]),
5943
+ '.xdrs/widgets-core/index.md': scopeIndexWith('widgets-core', '', 'core'),
5944
+ '.xdrs/widgets-core/adrs/index.md': teamAdrIndex(['- [001-widget-scope-type](principles/001-widget-scope-type.md) - Widget type']),
5945
+ '.xdrs/widgets-core/adrs/principles/001-widget-scope-type.md': structuredScopeTypePolicy('widgets-core', '001', 'widget'),
5946
+ ...scopeFiles('shop', '', 'widget'),
5947
+ ...coreWithScopeTypes(['standard']),
5948
+ });
5949
+ expect(activationErrors(lintWorkspace(workspaceRoot, { ignoreExternal: false }))).toBe('');
5950
+ });
5951
+
5952
+ test('does not report a disabled scope extending a scope with an invalid index [022.06]', () => {
5953
+ const workspaceRoot = createWorkspace('activation-disabled-extends-invalid', {
5954
+ '.xdrs/index.md': rootIndex(['[_core](_core/index.md)', '[View scope lib](lib/index.md)', '[View scope mid](mid/index.md) `disabled`', ACTIVATION_LEGEND]),
5955
+ ...scopeFiles('lib'),
5956
+ '.xdrs/lib/index.md': '# lib without frontmatter\n',
5957
+ ...scopeFiles('mid', 'extends: lib\n'),
5958
+ });
5959
+ expect(activationErrors(lintWorkspace(workspaceRoot, { ignoreExternal: false }))).not.toContain('Local scope "mid" is frozen');
5960
+ });
5961
+
5962
+ test('does not report a disabled external scope extending a disabled or missing scope [022.06]', () => {
5963
+ const workspaceRoot = createWorkspace('activation-disabled-external-extends', {
5964
+ '.xdrs/index.md': rootIndex(['[_core](_core/index.md)', '[View scope lib](lib/index.md) `disabled`', '[View scope vendor](vendor/index.md) `disabled`', ACTIVATION_LEGEND]),
5965
+ ...scopeFiles('lib'),
5966
+ ...scopeFiles('vendor', 'extends: lib, ghost-lib\n'),
5967
+ '.filedist.lock': '.xdrs/vendor/index.md|some-package|1.0.0\n',
5968
+ });
5969
+ expect(activationErrors(lintWorkspace(workspaceRoot, { ignoreExternal: false }))).toBe('');
5970
+ });
5971
+
5972
+ test('does not report a disabled scope with extends-only: true extending a disabled scope [022.06]', () => {
5973
+ const workspaceRoot = createWorkspace('activation-disabled-extends-only-field', {
5974
+ '.xdrs/index.md': rootIndex(['[_core](_core/index.md)', '[View scope lib](lib/index.md) `disabled`', '[View scope mid](mid/index.md) `disabled`', ACTIVATION_LEGEND]),
5975
+ ...scopeFiles('lib'),
5976
+ ...scopeFiles('mid', 'extends: lib\nextends-only: true\n'),
5977
+ });
5978
+ expect(activationErrors(lintWorkspace(workspaceRoot, { ignoreExternal: false }))).toBe('');
5979
+ });
5980
+
5981
+ test('reports only the enabled extender in the chain enabled -> disabled -> disabled [022.06]', () => {
5982
+ const workspaceRoot = createWorkspace('activation-chain-enabled-disabled-disabled', {
5983
+ '.xdrs/index.md': rootIndex(['[_core](_core/index.md)', '[View scope lib](lib/index.md) `disabled`', '[View scope mid](mid/index.md) `disabled`', '[View scope myteam](myteam/index.md)', ACTIVATION_LEGEND]),
5984
+ ...scopeFiles('lib'),
5985
+ ...scopeFiles('mid', 'extends: lib\n'),
5986
+ ...scopeFiles('myteam', 'extends: mid\n'),
5987
+ });
5988
+ const errors = activationErrors(lintWorkspace(workspaceRoot, { ignoreExternal: false }));
5989
+ expect(errors).toContain('Local scope "myteam" is frozen (read-only) because extends: scope "mid" is tagged `disabled`');
5990
+ expect(errors).not.toContain('Local scope "mid"');
5991
+ });
5992
+
5993
+ test('reports only the direct extender in the chain enabled -> enabled -> disabled [022.06]', () => {
5994
+ const workspaceRoot = createWorkspace('activation-chain-enabled-enabled-disabled', {
5995
+ '.xdrs/index.md': rootIndex(['[_core](_core/index.md)', '[View scope lib](lib/index.md) `disabled`', '[View scope mid](mid/index.md)', '[View scope myteam](myteam/index.md)', ACTIVATION_LEGEND]),
5996
+ ...scopeFiles('lib'),
5997
+ ...scopeFiles('mid', 'extends: lib\n'),
5998
+ ...scopeFiles('myteam', 'extends: mid\n'),
5999
+ });
6000
+ const errors = activationErrors(lintWorkspace(workspaceRoot, { ignoreExternal: false }));
6001
+ expect(errors).toContain('Local scope "mid" is frozen (read-only) because extends: scope "lib" is tagged `disabled`');
6002
+ expect(errors).not.toContain('Local scope "myteam"');
6003
+ });
6004
+
6005
+ test('still reports an enabled scope extending a missing scope [010.32]', () => {
6006
+ const workspaceRoot = createWorkspace('activation-enabled-extends-missing', {
6007
+ '.xdrs/index.md': rootIndex(['[_core](_core/index.md)', '[View scope myteam](myteam/index.md)']),
6008
+ ...scopeFiles('myteam', 'extends: ghost-lib\n'),
6009
+ });
6010
+ const errors = lintWorkspace(workspaceRoot, { ignoreExternal: false }).errors.join('\n');
6011
+ expect(errors).toContain('extends references scope "ghost-lib" which does not exist in the workspace');
6012
+ });
6013
+
6014
+ test('still reports extends cycles and self-extends in disabled scopes [010.30, 010.31]', () => {
6015
+ const workspaceRoot = createWorkspace('activation-disabled-structural', {
6016
+ '.xdrs/index.md': rootIndex(['[_core](_core/index.md)', '[View scope a](a/index.md) `disabled`', '[View scope b](b/index.md) `disabled`', '[View scope c](c/index.md) `disabled`', ACTIVATION_LEGEND]),
6017
+ ...scopeFiles('a', 'extends: b\n'),
6018
+ ...scopeFiles('b', 'extends: a\n'),
6019
+ ...scopeFiles('c', 'extends: c\n'),
6020
+ });
6021
+ const errors = lintWorkspace(workspaceRoot, { ignoreExternal: false }).errors.join('\n');
6022
+ expect(errors).toContain('Circular extends chain detected');
6023
+ expect(errors).toContain('must not reference the scope itself');
6024
+ });
6025
+
6026
+ test('still reports a disabled scope following a non-core scope [001]', () => {
6027
+ const workspaceRoot = createWorkspace('activation-disabled-follows-non-core', {
6028
+ '.xdrs/index.md': rootIndex(['[_core](_core/index.md)', '[View scope lib](lib/index.md)', '[View scope mid](mid/index.md) `disabled`', ACTIVATION_LEGEND]),
6029
+ ...scopeFiles('lib'),
6030
+ ...scopeFiles('mid', 'follows: lib\n'),
6031
+ });
6032
+ const errors = lintWorkspace(workspaceRoot, { ignoreExternal: false }).errors.join('\n');
6033
+ expect(errors).toContain('follows references scope "lib" which is not a core-type scope');
6034
+ });
6035
+
6036
+ test('reports an enabled scope type defined only in a disabled scope as frozen while a disabled user is exempt [022.06]', () => {
6037
+ const workspaceRoot = createWorkspace('activation-type-enabled-vs-disabled-user', {
6038
+ '.xdrs/index.md': rootIndex(['[_core](_core/index.md)', '[View scope widgets-core](widgets-core/index.md) `disabled`', '[View scope shop](shop/index.md)', '[View scope kiosk](kiosk/index.md) `disabled`', ACTIVATION_LEGEND]),
6039
+ '.xdrs/widgets-core/index.md': scopeIndexWith('widgets-core', '', 'core'),
6040
+ '.xdrs/widgets-core/adrs/index.md': teamAdrIndex(['- [001-widget-scope-type](principles/001-widget-scope-type.md) - Widget type']),
6041
+ '.xdrs/widgets-core/adrs/principles/001-widget-scope-type.md': structuredScopeTypePolicy('widgets-core', '001', 'widget'),
6042
+ ...scopeFiles('shop', '', 'widget'),
6043
+ ...scopeFiles('kiosk', '', 'widget'),
6044
+ ...coreWithScopeTypes(['standard']),
6045
+ });
6046
+ const errors = activationErrors(lintWorkspace(workspaceRoot, { ignoreExternal: false }));
6047
+ expect(errors).toContain('Local scope "shop" is frozen (read-only)');
6048
+ expect(errors).not.toContain('Local scope "kiosk"');
5918
6049
  });
5919
6050
 
5920
6051
  test('prints frozen local scopes as errors and never prints warning or READ-ONLY lines [022.06]', () => {
@@ -6048,3 +6179,161 @@ test('accepts compiled combined with a non-core type [011.10]', () => {
6048
6179
  const result = lintWorkspace(workspaceRoot, { ignoreExternal: false });
6049
6180
  expect(result.errors.join('\n')).not.toContain('011.10');
6050
6181
  });
6182
+
6183
+ // ---------------------------------------------------------------------------
6184
+ // sync-date frontmatter (_core-adr-policy-024)
6185
+ // ---------------------------------------------------------------------------
6186
+
6187
+ const SYNC_DATE_ERRORS = (result) => result.errors.filter((e) => e.includes('sync-date')).join('\n');
6188
+
6189
+ function syncDatePolicy(extraFrontmatter) {
6190
+ return [
6191
+ '---',
6192
+ 'name: _local-adr-policy-001-main',
6193
+ 'description: Test XDRS element',
6194
+ 'apply-to: All scopes',
6195
+ 'valid-from: 2026-01-01',
6196
+ ...extraFrontmatter,
6197
+ '---',
6198
+ '',
6199
+ '# _local-adr-policy-001: Main decision',
6200
+ '',
6201
+ '## Context and Problem Statement',
6202
+ '',
6203
+ 'Test body.',
6204
+ '',
6205
+ '## Decision Outcome',
6206
+ '',
6207
+ 'Test decision outcome.',
6208
+ ''
6209
+ ].join('\n');
6210
+ }
6211
+
6212
+ test('accepts a valid sync-date in Policy frontmatter', () => {
6213
+ const workspaceRoot = createWorkspace('syncd-policy-valid', {
6214
+ '.xdrs/index.md': rootIndex(),
6215
+ '.xdrs/_local/adrs/index.md': localAdrIndex(['- [001-main](principles/001-main.md) - Main decision']),
6216
+ '.xdrs/_local/adrs/principles/001-main.md': syncDatePolicy(['sync-date: 2026-11-04']),
6217
+ });
6218
+
6219
+ const result = lintWorkspace(workspaceRoot);
6220
+
6221
+ expect(SYNC_DATE_ERRORS(result)).toBe('');
6222
+ expect(result.errors.join('\n')).not.toContain('unknown field');
6223
+ });
6224
+
6225
+ test('reports invalid and empty sync-date in Policy frontmatter', () => {
6226
+ for (const [name, value] of [['syncd-policy-invalid', 'sync-date: yesterday'], ['syncd-policy-empty', 'sync-date:'], ['syncd-policy-quoted', 'sync-date: "2026-11-04"']]) {
6227
+ const workspaceRoot = createWorkspace(name, {
6228
+ '.xdrs/index.md': rootIndex(),
6229
+ '.xdrs/_local/adrs/index.md': localAdrIndex(['- [001-main](principles/001-main.md) - Main decision']),
6230
+ '.xdrs/_local/adrs/principles/001-main.md': syncDatePolicy([value]),
6231
+ });
6232
+
6233
+ const result = lintWorkspace(workspaceRoot);
6234
+
6235
+ expect(SYNC_DATE_ERRORS(result)).toContain('Policy frontmatter sync-date must be a valid ISO date YYYY-MM-DD');
6236
+ }
6237
+ });
6238
+
6239
+ test('reports sync-date in a Policy of a compiled scope', () => {
6240
+ const policy = validCompiledPolicy().replace('valid-from: 2026-01-01\n', 'valid-from: 2026-01-01\nsync-date: 2026-11-04\n');
6241
+ const workspaceRoot = createWorkspace('syncd-compiled-policy', {
6242
+ '.xdrs/index.md': rootIndex(['[my-compiled](my-compiled/index.md)']),
6243
+ '.xdrs/my-compiled/index.md': compiledScopeIndex(),
6244
+ '.xdrs/my-compiled/adrs/index.md': compiledAdrIndex(['- [001-a01](principles/001-a01.md) - A01']),
6245
+ '.xdrs/my-compiled/adrs/principles/001-a01.md': policy,
6246
+ });
6247
+
6248
+ const result = lintWorkspace(workspaceRoot);
6249
+
6250
+ expect(SYNC_DATE_ERRORS(result)).toContain('024.07-compiled-scopes');
6251
+ });
6252
+
6253
+ test('accepts sync-date in the scope index of a compiled scope', () => {
6254
+ const workspaceRoot = createWorkspace('syncd-compiled-scope-index', {
6255
+ '.xdrs/index.md': rootIndex(['[my-compiled](my-compiled/index.md)']),
6256
+ '.xdrs/my-compiled/index.md': compiledScopeIndex().replace('valid-from: 2026-01-01\n', 'valid-from: 2026-01-01\nsync-date: 2026-11-04\n'),
6257
+ '.xdrs/my-compiled/adrs/index.md': compiledAdrIndex(['- [001-a01](principles/001-a01.md) - A01']),
6258
+ '.xdrs/my-compiled/adrs/principles/001-a01.md': validCompiledPolicy(),
6259
+ });
6260
+
6261
+ const result = lintWorkspace(workspaceRoot);
6262
+
6263
+ expect(SYNC_DATE_ERRORS(result)).toBe('');
6264
+ expect(result.errors.join('\n')).not.toContain('unknown field');
6265
+ });
6266
+
6267
+ test('reports invalid sync-date in scope index frontmatter', () => {
6268
+ const workspaceRoot = createWorkspace('syncd-scope-index-invalid', {
6269
+ '.xdrs/index.md': rootIndex(['[myteam](myteam/index.md)']),
6270
+ '.xdrs/myteam/index.md': '---\nscope-type: standard\nname: myteam\ndescription: Team.\napply-to: Test team\nvalid-from: 2026-01-01\nsync-date: 2026-13-45\n---\n\n# myteam Scope Overview\n\n[ADRs](adrs/index.md)\n',
6271
+ '.xdrs/myteam/adrs/index.md': teamAdrIndex(['- [001-team](principles/001-team.md) - Team decision']),
6272
+ '.xdrs/myteam/adrs/principles/001-team.md': teamXdrDocument('Team decision.'),
6273
+ });
6274
+
6275
+ const result = lintWorkspace(workspaceRoot, { ignoreExternal: false });
6276
+
6277
+ expect(SYNC_DATE_ERRORS(result)).toContain('Scope index frontmatter sync-date must be a valid ISO date YYYY-MM-DD');
6278
+ });
6279
+
6280
+ test('validates metadata.sync-date in SKILL.md frontmatter', () => {
6281
+ const skillWith = (syncDate) => fullSkillDocument().replace(
6282
+ 'description: Test skill document\n---',
6283
+ `description: Test skill document\nmetadata:\n version: "1.0.0"\n author: test\n updated: 2026-11-04\n sync-date: ${syncDate}\n---`
6284
+ );
6285
+ const build = (name, syncDate) => createWorkspace(name, {
6286
+ '.xdrs/index.md': rootIndex(),
6287
+ '.xdrs/_local/adrs/index.md': localAdrIndex(['- [check-links](principles/skills/check-links/SKILL.md) - Check links']),
6288
+ '.xdrs/_local/adrs/principles/skills/check-links/SKILL.md': skillWith(syncDate),
6289
+ });
6290
+
6291
+ const valid = lintWorkspace(build('syncd-skill-valid', '2026-11-04'));
6292
+ const invalid = lintWorkspace(build('syncd-skill-invalid', 'soon'));
6293
+
6294
+ expect(SYNC_DATE_ERRORS(valid)).toBe('');
6295
+ expect(SYNC_DATE_ERRORS(invalid)).toContain('SKILL.md frontmatter metadata.sync-date must be a valid ISO date YYYY-MM-DD');
6296
+ });
6297
+
6298
+ test('accepts sync-date-only frontmatter in article, research and initiative documents', () => {
6299
+ const fm = '---\nsync-date: 2026-11-04\n---\n\n';
6300
+ const workspaceRoot = createWorkspace('syncd-docs-valid', {
6301
+ '.xdrs/index.md': rootIndex(),
6302
+ '.xdrs/_local/adrs/index.md': localAdrIndex([
6303
+ '- [001-guide](principles/articles/001-guide.md) - Guide',
6304
+ '- [001-study](principles/researches/001-study.md) - Study',
6305
+ '- [001-myinitiative](principles/initiatives/001-myinitiative.md) - My initiative',
6306
+ ]),
6307
+ '.xdrs/_local/adrs/principles/articles/001-guide.md': fm + articleDocument('Body.'),
6308
+ '.xdrs/_local/adrs/principles/researches/001-study.md': fm + researchDocument('Context.', 'Question: Is this right?'),
6309
+ '.xdrs/_local/adrs/principles/initiatives/001-myinitiative.md': fm + initiativeDocument('Body.'),
6310
+ });
6311
+
6312
+ const result = lintWorkspace(workspaceRoot);
6313
+
6314
+ expect(SYNC_DATE_ERRORS(result)).toBe('');
6315
+ expect(result.errors.join('\n')).not.toContain('title must start with');
6316
+ expect(result.errors.join('\n')).not.toContain('frontmatter');
6317
+ });
6318
+
6319
+ test('reports unknown, missing and invalid frontmatter fields in article, research and initiative documents', () => {
6320
+ const workspaceRoot = createWorkspace('syncd-docs-invalid', {
6321
+ '.xdrs/index.md': rootIndex(),
6322
+ '.xdrs/_local/adrs/index.md': localAdrIndex([
6323
+ '- [001-guide](principles/articles/001-guide.md) - Guide',
6324
+ '- [001-study](principles/researches/001-study.md) - Study',
6325
+ '- [001-myinitiative](principles/initiatives/001-myinitiative.md) - My initiative',
6326
+ ]),
6327
+ '.xdrs/_local/adrs/principles/articles/001-guide.md': '---\nsync-date: 2026-11-04\nauthor: me\n---\n\n' + articleDocument('Body.'),
6328
+ '.xdrs/_local/adrs/principles/researches/001-study.md': '---\nsync-date: never\n---\n\n' + researchDocument('Context.', 'Question: Is this right?'),
6329
+ '.xdrs/_local/adrs/principles/initiatives/001-myinitiative.md': '---\nauthor: me\n---\n\n' + initiativeDocument('Body.'),
6330
+ });
6331
+
6332
+ const result = lintWorkspace(workspaceRoot);
6333
+ const errors = result.errors.join('\n');
6334
+
6335
+ expect(errors).toContain('Article frontmatter has unknown field "author" (only sync-date is allowed)');
6336
+ expect(errors).toContain('Research frontmatter sync-date must be a valid ISO date YYYY-MM-DD');
6337
+ expect(errors).toContain('Initiative frontmatter has unknown field "author" (only sync-date is allowed)');
6338
+ expect(errors).toContain('Initiative frontmatter must include a sync-date field when present');
6339
+ });
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "xdrs-core",
3
- "version": "0.55.0",
3
+ "version": "0.56.1",
4
4
  "description": "XDRS (eXtensible Decision Record System): a framework to structure, compile and distribute Architectural (ADR), Business (BDR), and Engineering (EDR) decision records contents so that AI agents and humans can reliably find and use them with hierarchical scopes and controlled rollout in the format of distributable versioned packages.",
5
5
  "repository": {
6
6
  "type": "git",