@besales/ops-framework 0.1.14 → 0.1.15

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.
package/CHANGELOG.md CHANGED
@@ -1,5 +1,10 @@
1
1
  # Changelog
2
2
 
3
+ ## 0.1.15
4
+
5
+ - Strengthened the initiative track-scope/storage synthesis gate to detect wide meeting tracks routed to commitments/decisions/risks via `related_person_id` when that storage is deferred.
6
+ - Linked the track-scope gate action to the apply-contract decision so synthesis resolves both scope and write semantics together.
7
+
3
8
  ## 0.1.14
4
9
 
5
10
  - Added initiative synthesis readiness gates for missing critical concepts, ADR/NFR coverage, scope/storage conflicts, apply-contract ambiguity, sequencing hints and stronger source-reference warnings.
@@ -1064,18 +1064,21 @@ function addMissingConceptGate({
1064
1064
  }
1065
1065
 
1066
1066
  function addScopeStorageConflictGate({ gates, sourceText, requirementText }) {
1067
- const mentionsWideTrackTaxonomy = /(tracker|advisor[_ -]?network|investor|grant[_ -]?funding)/i.test(requirementText);
1068
- const defersFactStorage = /(commitments?|decisions?|risks?|related_person_id).{0,120}(phase\s*2|future|defer|отлож)/is.test(`${requirementText}\n${sourceText}`)
1069
- || /(phase\s*2|future|defer|отлож).{0,120}(commitments?|decisions?|risks?|related_person_id)/is.test(`${requirementText}\n${sourceText}`);
1067
+ const combinedText = `${requirementText}\n${sourceText}`;
1068
+ const mentionsWideTrackTaxonomy = /(tracker|advisor[_ -]?network|advisor-network|investor|grant[_ -]?funding|fundraising|grants?)/i.test(combinedText);
1069
+ const mapsWideTracksToFactStorage = /(advisor[_ -]?network|advisor-network|fundraising|investor|grant[_ -]?funding|grants?|tracker).{0,240}(commitments?|decisions?|risks?|related_person_id|nullable client_id|meeting_track\s+in)/is.test(sourceText)
1070
+ || /(commitments?|decisions?|risks?|related_person_id|nullable client_id|meeting_track\s+in).{0,240}(advisor[_ -]?network|advisor-network|fundraising|investor|grant[_ -]?funding|grants?|tracker)/is.test(sourceText);
1071
+ const defersFactStorage = /(commitments?|decisions?|risks?|related_person_id).{0,160}(phase\s*2|future|defer|deferred|отлож)/is.test(combinedText)
1072
+ || /(phase\s*2|future|defer|deferred|отлож).{0,160}(commitments?|decisions?|risks?|related_person_id)/is.test(combinedText);
1070
1073
  const hasExplicitTrackScopeDecision = /(client\s*\+\s*internal|client and internal|только client|только клиент|only client|track[- ]scope|6 tracks?.{0,80}(phase\s*2|future|defer))/i.test(requirementText);
1071
- if (mentionsWideTrackTaxonomy && defersFactStorage && !hasExplicitTrackScopeDecision) {
1074
+ if (mentionsWideTrackTaxonomy && mapsWideTracksToFactStorage && defersFactStorage && !hasExplicitTrackScopeDecision) {
1072
1075
  gates.push({
1073
1076
  id: 'scope-storage-track-conflict',
1074
1077
  severity: 'needs_decision',
1075
1078
  blocking: true,
1076
1079
  title: 'Track taxonomy conflicts with deferred fact storage',
1077
- issue: 'Requirements mention non-client/internal tracks while storage for commitments/decisions/risks or related-person facts appears deferred.',
1078
- action: 'Decide explicitly: Phase 1 taxonomy is client+internal only, or Phase 1 includes minimal fact storage for the wider track set.',
1080
+ issue: 'Sources connect non-client/internal meeting tracks to commitments/decisions/risks or related-person facts while that storage appears deferred.',
1081
+ action: 'Decide explicitly with the apply-contract gate: Phase 1 extraction is client+internal only, or Phase 1 includes minimal commitments/decisions/risks storage with related_person_id for the wider track set.',
1079
1082
  });
1080
1083
  }
1081
1084
  }
@@ -388,6 +388,7 @@ describe('initiative framework', () => {
388
388
  '- Golden set baseline Week 1-2 for meeting extraction regression.',
389
389
  '- Migration 001b: person_aliases. Meeting fields: meeting_track, series_id, asr_quality, speaker_resolution_status.',
390
390
  '- Analysis found single-label exports, alias zoo, committed_by_person attribution risk.',
391
+ '- advisor_network, fundraising and grants are routed into commitments, decisions and risks by meeting_track.',
391
392
  '- Phase 2 defers commitments decisions risks related_person_id storage.',
392
393
  ].join('\n'));
393
394
  fs.writeFileSync(path.join(docsDir, '07-adrs.md'), [
@@ -445,6 +446,57 @@ describe('initiative framework', () => {
445
446
  expect(pack).toContain('Golden set should baseline meeting extraction');
446
447
  expect(pack).toContain('Stronger source reference available');
447
448
  });
449
+
450
+ it('detects track scope storage conflicts when routing evidence is only in source docs', () => {
451
+ const root = makeProject();
452
+ const docsDir = path.join(root, 'docs', 'delivery-os');
453
+ fs.mkdirSync(docsDir, { recursive: true });
454
+ fs.writeFileSync(path.join(docsDir, '06-roadmap.md'), [
455
+ '# Phase 1',
456
+ '',
457
+ '- MVP taxonomy must cover client, internal, tracker, advisor_network, investor, grant_funding.',
458
+ '- Minimal Phase 1 schema defers commitments, decisions, risks and related_person_id storage to Phase 2.',
459
+ ].join('\n'));
460
+ fs.writeFileSync(path.join(docsDir, '12-para-workspace-contract.md'), [
461
+ '# Workspace Contract',
462
+ '',
463
+ '- advisor-network / fundraising / grants are routed into commitments, decisions and risks where meeting_track IN (...).',
464
+ ].join('\n'));
465
+ fs.writeFileSync(path.join(docsDir, '13-meeting-extraction-profiles.md'), [
466
+ '# Profiles',
467
+ '',
468
+ '- Non-client tracks require nullable client_id plus related_person_id on commitments, decisions and risks.',
469
+ ].join('\n'));
470
+ createInitiative({
471
+ projectRoot: root,
472
+ initiativeId: 'delivery-os-mvp',
473
+ title: 'Delivery OS MVP',
474
+ });
475
+
476
+ initiativeIntake({
477
+ projectRoot: root,
478
+ initiativeId: 'delivery-os-mvp',
479
+ docsDir: 'docs/delivery-os',
480
+ phase: 'phase-1',
481
+ });
482
+ initiativeRequirements({
483
+ projectRoot: root,
484
+ initiativeId: 'delivery-os-mvp',
485
+ phase: 'phase-1',
486
+ });
487
+ const synthesis = initiativeRequirementsSynthesis({
488
+ projectRoot: root,
489
+ initiativeId: 'delivery-os-mvp',
490
+ });
491
+
492
+ const gate = synthesis.gates.find((item) => item.id === 'scope-storage-track-conflict');
493
+ expect(gate).toMatchObject({
494
+ severity: 'needs_decision',
495
+ blocking: true,
496
+ });
497
+ expect(gate.action).toContain('client+internal');
498
+ expect(gate.action).toContain('related_person_id');
499
+ });
448
500
  });
449
501
 
450
502
  function makeProject() {
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@besales/ops-framework",
3
- "version": "0.1.14",
3
+ "version": "0.1.15",
4
4
  "type": "module",
5
5
  "bin": {
6
6
  "ops-agent": "bin/ops-agent.mjs"