@aibvf/core 0.7.1 → 0.8.0

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.
@@ -0,0 +1,62 @@
1
+ /**
2
+ * assemble_portfolio: agents arrive with initiative names, plain-language
3
+ * functions and half the pillar scores, then hand-build the portfolio JSON
4
+ * and get the shape wrong. This assembles the canonical BVF v1.0 document
5
+ * from loose inputs deterministically: aliases resolved through the same
6
+ * taxonomy mapping as map_to_taxonomy, ids generated from names, missing
7
+ * pillars estimated with provenance reported, and the finished document
8
+ * validated before it is returned. Pure function, no state, nothing stored.
9
+ */
10
+ import type { AuditRecord, Bucket, ComplianceFramework, PillarScores, Portfolio, Readiness, ValidationResult } from './types.js';
11
+ export interface AssembleInitiativeInput {
12
+ /** Required. Plain name, used to generate the id when none is given. */
13
+ name: string;
14
+ /** Optional slug (lowercase letters, digits, hyphens). Generated from the name when absent. */
15
+ id?: string;
16
+ /** Business function, canonical or plain language ("customer service" resolves to cx). */
17
+ function: string;
18
+ /** AI tier, canonical or plain language ("agentic" resolves to gen3). */
19
+ ai_tier: string;
20
+ /** The pillar scores you have evidence for, as bare numbers 0 to 100. Missing pillars are estimated and reported. */
21
+ scores?: Partial<PillarScores>;
22
+ bucket?: Bucket;
23
+ compliance?: ComplianceFramework[];
24
+ }
25
+ export interface AssembleInput {
26
+ organization: {
27
+ name: string;
28
+ /** Canonical or plain language ("banking" resolves to financial). */
29
+ industry: string;
30
+ revenue_eur?: number;
31
+ region?: string;
32
+ headcount?: number;
33
+ };
34
+ initiatives: AssembleInitiativeInput[];
35
+ /** Organisational readiness, canonical or plain language. Drives pillar estimation. Defaults to traditional. */
36
+ readiness?: string;
37
+ }
38
+ export interface AssembleIssue {
39
+ path: string;
40
+ msg: string;
41
+ suggestions?: string[];
42
+ }
43
+ export interface AssembleResult {
44
+ /** The assembled BVF v1.0 document, or null when a required field could not be resolved. */
45
+ portfolio: Portfolio | null;
46
+ /** Plain-language notes on every alias resolution the assembler performed. */
47
+ resolutions: string[];
48
+ /** Initiative id to the pillars the assembler estimated, so scoring can haircut honestly. */
49
+ estimated_pillars: Record<string, string[]>;
50
+ /** Every default the assembler applied, in plain language. No hidden judgements: what was not given is named here. */
51
+ assumptions: string[];
52
+ /** Unresolved or invalid inputs, each with suggestions where the taxonomy has them. */
53
+ issues: AssembleIssue[];
54
+ /** validate() run on the assembled document. Null when assembly failed. */
55
+ validation: ValidationResult | null;
56
+ /** The readiness used for estimation, resolved or defaulted. */
57
+ readiness_used: Readiness;
58
+ guidance: string;
59
+ audit: AuditRecord;
60
+ }
61
+ export declare function assemblePortfolio(input: AssembleInput): AssembleResult;
62
+ //# sourceMappingURL=assemblePortfolio.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"assemblePortfolio.d.ts","sourceRoot":"","sources":["../src/assemblePortfolio.ts"],"names":[],"mappings":"AAAA;;;;;;;;GAQG;AACH,OAAO,KAAK,EACV,WAAW,EAAE,MAAM,EAAE,mBAAmB,EACxC,YAAY,EAAE,SAAS,EAAE,SAAS,EAAE,gBAAgB,EACrD,MAAM,YAAY,CAAC;AAWpB,MAAM,WAAW,uBAAuB;IACtC,wEAAwE;IACxE,IAAI,EAAE,MAAM,CAAC;IACb,+FAA+F;IAC/F,EAAE,CAAC,EAAE,MAAM,CAAC;IACZ,0FAA0F;IAC1F,QAAQ,EAAE,MAAM,CAAC;IACjB,yEAAyE;IACzE,OAAO,EAAE,MAAM,CAAC;IAChB,qHAAqH;IACrH,MAAM,CAAC,EAAE,OAAO,CAAC,YAAY,CAAC,CAAC;IAC/B,MAAM,CAAC,EAAE,MAAM,CAAC;IAChB,UAAU,CAAC,EAAE,mBAAmB,EAAE,CAAC;CACpC;AAED,MAAM,WAAW,aAAa;IAC5B,YAAY,EAAE;QACZ,IAAI,EAAE,MAAM,CAAC;QACb,qEAAqE;QACrE,QAAQ,EAAE,MAAM,CAAC;QACjB,WAAW,CAAC,EAAE,MAAM,CAAC;QACrB,MAAM,CAAC,EAAE,MAAM,CAAC;QAChB,SAAS,CAAC,EAAE,MAAM,CAAC;KACpB,CAAC;IACF,WAAW,EAAE,uBAAuB,EAAE,CAAC;IACvC,gHAAgH;IAChH,SAAS,CAAC,EAAE,MAAM,CAAC;CACpB;AAED,MAAM,WAAW,aAAa;IAC5B,IAAI,EAAE,MAAM,CAAC;IACb,GAAG,EAAE,MAAM,CAAC;IACZ,WAAW,CAAC,EAAE,MAAM,EAAE,CAAC;CACxB;AAED,MAAM,WAAW,cAAc;IAC7B,4FAA4F;IAC5F,SAAS,EAAE,SAAS,GAAG,IAAI,CAAC;IAC5B,8EAA8E;IAC9E,WAAW,EAAE,MAAM,EAAE,CAAC;IACtB,6FAA6F;IAC7F,iBAAiB,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,EAAE,CAAC,CAAC;IAC5C,sHAAsH;IACtH,WAAW,EAAE,MAAM,EAAE,CAAC;IACtB,uFAAuF;IACvF,MAAM,EAAE,aAAa,EAAE,CAAC;IACxB,2EAA2E;IAC3E,UAAU,EAAE,gBAAgB,GAAG,IAAI,CAAC;IACpC,gEAAgE;IAChE,cAAc,EAAE,SAAS,CAAC;IAC1B,QAAQ,EAAE,MAAM,CAAC;IACjB,KAAK,EAAE,WAAW,CAAC;CACpB;AAaD,wBAAgB,iBAAiB,CAAC,KAAK,EAAE,aAAa,GAAG,cAAc,CAoJtE"}
@@ -0,0 +1,174 @@
1
+ import { mapToTaxonomy } from './aliases.js';
2
+ import { estimatePillars } from './score.js';
3
+ import { validate } from './validate.js';
4
+ import { buildAudit } from './audit.js';
5
+ const PILLARS = ['strategic_alignment', 'financial_return', 'change_enablement', 'governance_risk'];
6
+ /** Confidence attached to pillar values the assembler estimated rather than received. */
7
+ const ESTIMATED_CONFIDENCE = 40;
8
+ function slugify(name) {
9
+ // Input is uncontrolled tool input: cap it before any regex work, and trim
10
+ // hyphen runs with index arithmetic rather than unanchored regexes, which
11
+ // backtrack polynomially on adversarial strings of repeated separators.
12
+ const slug = name.slice(0, 240).toLowerCase().replace(/[^a-z0-9]+/g, '-').slice(0, 64);
13
+ let start = 0, end = slug.length;
14
+ while (start < end && slug[start] === '-')
15
+ start++;
16
+ while (end > start && slug[end - 1] === '-')
17
+ end--;
18
+ return slug.slice(start, end) || 'initiative';
19
+ }
20
+ export function assemblePortfolio(input) {
21
+ const issues = [];
22
+ const resolutions = [];
23
+ const assumptions = [];
24
+ const estimated = {};
25
+ const rules = [];
26
+ const orgIn = input?.organization;
27
+ const list = input?.initiatives;
28
+ if (!orgIn || typeof orgIn.name !== 'string' || !orgIn.name) {
29
+ issues.push({ path: 'organization.name', msg: 'Required. The organisation the portfolio belongs to.' });
30
+ }
31
+ if (!Array.isArray(list) || list.length === 0) {
32
+ issues.push({ path: 'initiatives', msg: 'Required. At least one initiative to assemble.' });
33
+ }
34
+ // Readiness: resolved from plain language, defaulted when absent or unresolvable.
35
+ let readiness = 'traditional';
36
+ if (input?.readiness) {
37
+ const m = mapToTaxonomy({ readiness: input.readiness }).readiness;
38
+ if (m?.resolved) {
39
+ readiness = m.resolved;
40
+ if (m.matched_on !== 'exact') {
41
+ resolutions.push(`readiness: ${input.readiness} resolved to ${readiness}`);
42
+ rules.push('alias:readiness');
43
+ }
44
+ }
45
+ else {
46
+ issues.push({ path: 'readiness', msg: `Could not resolve "${input.readiness}". Defaulted to traditional.`, suggestions: m?.suggestions });
47
+ assumptions.push('Readiness defaulted to traditional because the given value did not resolve. Estimated pillars lean on it.');
48
+ rules.push('default:readiness');
49
+ }
50
+ }
51
+ else {
52
+ assumptions.push('Readiness was not given: defaulted to traditional. Estimated pillars lean on it, so confirm it or measure it with infer_readiness.');
53
+ rules.push('default:readiness');
54
+ }
55
+ // Industry: required, resolved through the same aliases as map_to_taxonomy.
56
+ let industry = null;
57
+ if (orgIn && typeof orgIn.industry === 'string' && orgIn.industry) {
58
+ const m = mapToTaxonomy({ industry: orgIn.industry }).industry;
59
+ if (m?.resolved) {
60
+ industry = m.resolved;
61
+ if (m.matched_on !== 'exact') {
62
+ resolutions.push(`industry: ${orgIn.industry} resolved to ${industry}`);
63
+ rules.push('alias:industry');
64
+ }
65
+ }
66
+ else {
67
+ issues.push({ path: 'organization.industry', msg: `Could not resolve "${orgIn.industry}" to a canonical industry.`, suggestions: m?.suggestions });
68
+ }
69
+ }
70
+ else {
71
+ issues.push({ path: 'organization.industry', msg: 'Required. Canonical id or plain language.' });
72
+ }
73
+ const usedIds = new Set();
74
+ const initiatives = [];
75
+ (Array.isArray(list) ? list : []).forEach((raw, i) => {
76
+ const base = `initiatives[${i}]`;
77
+ if (!raw || typeof raw.name !== 'string' || !raw.name) {
78
+ issues.push({ path: `${base}.name`, msg: 'Required. Every initiative needs a name.' });
79
+ return;
80
+ }
81
+ const fn = typeof raw.function === 'string' && raw.function ? mapToTaxonomy({ function: raw.function }).function : undefined;
82
+ if (!fn?.resolved) {
83
+ issues.push({ path: `${base}.function`, msg: `Could not resolve "${raw?.function ?? ''}" to a canonical function.`, suggestions: fn?.suggestions });
84
+ return;
85
+ }
86
+ if (fn.matched_on !== 'exact') {
87
+ resolutions.push(`${raw.name}: function ${raw.function} resolved to ${fn.resolved}`);
88
+ rules.push('alias:function');
89
+ }
90
+ const tier = typeof raw.ai_tier === 'string' && raw.ai_tier ? mapToTaxonomy({ ai_tier: raw.ai_tier }).ai_tier : undefined;
91
+ if (!tier?.resolved) {
92
+ issues.push({ path: `${base}.ai_tier`, msg: `Could not resolve "${raw?.ai_tier ?? ''}" to a canonical tier.`, suggestions: tier?.suggestions });
93
+ return;
94
+ }
95
+ if (tier.matched_on !== 'exact') {
96
+ resolutions.push(`${raw.name}: ai_tier ${raw.ai_tier} resolved to ${tier.resolved}`);
97
+ rules.push('alias:ai_tier');
98
+ }
99
+ // Id: given and kept, or generated from the name, deduplicated deterministically.
100
+ let id = typeof raw.id === 'string' && /^[a-z0-9-]{1,64}$/.test(raw.id) ? raw.id : slugify(raw.name);
101
+ if (raw.id && id !== raw.id)
102
+ issues.push({ path: `${base}.id`, msg: `Given id "${raw.id}" is not a valid slug. Replaced with "${id}".` });
103
+ let candidate = id, n = 2;
104
+ while (usedIds.has(candidate))
105
+ candidate = `${id}-${n++}`.slice(0, 64);
106
+ if (candidate !== id)
107
+ rules.push('dedupe:id');
108
+ usedIds.add(candidate);
109
+ id = candidate;
110
+ // Pillars: given values pass through as bare numbers; missing ones are
111
+ // estimated from taxonomy and readiness, carry a low confidence in the
112
+ // document, and are reported so downstream scoring can haircut honestly.
113
+ const est = estimatePillars({
114
+ industry: (industry ?? 'universal'),
115
+ function: fn.resolved,
116
+ ai_tier: tier.resolved,
117
+ readiness,
118
+ });
119
+ const scores = {};
120
+ const estHere = [];
121
+ for (const p of PILLARS) {
122
+ const given = raw.scores?.[p];
123
+ if (typeof given === 'number') {
124
+ scores[p] = given;
125
+ }
126
+ else {
127
+ scores[p] = { value: est[p], confidence: ESTIMATED_CONFIDENCE };
128
+ estHere.push(p);
129
+ }
130
+ }
131
+ if (estHere.length) {
132
+ estimated[id] = estHere;
133
+ assumptions.push(`${raw.name}: ${estHere.join(', ')} estimated from readiness, tier, function and published benchmarks at confidence ${ESTIMATED_CONFIDENCE}. Structure, not evidence.`);
134
+ rules.push('estimate:pillars');
135
+ }
136
+ const init = { id, name: raw.name, function: fn.resolved, ai_tier: tier.resolved, scores };
137
+ if (raw.bucket)
138
+ init.bucket = raw.bucket;
139
+ if (raw.compliance)
140
+ init.compliance = raw.compliance;
141
+ initiatives.push(init);
142
+ });
143
+ const blocked = !industry || !orgIn?.name || initiatives.length === 0;
144
+ const portfolio = blocked ? null : {
145
+ bvf_version: '1.0',
146
+ organization: {
147
+ name: orgIn.name,
148
+ industry: industry,
149
+ ...(typeof orgIn.revenue_eur === 'number' ? { revenue_eur: orgIn.revenue_eur } : {}),
150
+ ...(typeof orgIn.region === 'string' && orgIn.region ? { region: orgIn.region } : {}),
151
+ ...(typeof orgIn.headcount === 'number' ? { headcount: orgIn.headcount } : {}),
152
+ },
153
+ initiatives,
154
+ };
155
+ const validation = portfolio ? validate(portfolio) : null;
156
+ const estimatedCount = Object.keys(estimated).length;
157
+ const guidance = portfolio
158
+ ? (estimatedCount
159
+ ? 'The document is assembled and validated. Estimated pillars carry low confidence in the document and are listed in estimated_pillars: gather real evidence for them, or expect scoring to haircut decision confidence on those initiatives.'
160
+ : 'The document is assembled and validated. Pass it to validate_portfolio, score_portfolio or sequence_portfolio as it stands.')
161
+ : 'Assembly is blocked on the issues listed. Resolve each one, the suggestions name the nearest canonical values, and call again.';
162
+ return {
163
+ portfolio,
164
+ resolutions,
165
+ assumptions,
166
+ estimated_pillars: estimated,
167
+ issues,
168
+ validation,
169
+ readiness_used: readiness,
170
+ guidance,
171
+ audit: buildAudit(rules.filter((r, i, a) => a.indexOf(r) === i), { organization: orgIn?.name ?? null, industry, initiatives: Array.isArray(list) ? list.length : 0, readiness }),
172
+ };
173
+ }
174
+ //# sourceMappingURL=assemblePortfolio.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"assemblePortfolio.js","sourceRoot":"","sources":["../src/assemblePortfolio.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,2 @@
1
+ export {};
2
+ //# sourceMappingURL=assemblePortfolio.test.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"assemblePortfolio.test.d.ts","sourceRoot":"","sources":["../src/assemblePortfolio.test.ts"],"names":[],"mappings":""}
@@ -0,0 +1,96 @@
1
+ import test from 'node:test';
2
+ import assert from 'node:assert/strict';
3
+ import { assemblePortfolio } from './assemblePortfolio.js';
4
+ import { validate } from './validate.js';
5
+ const loose = {
6
+ organization: { name: 'Health Group', industry: 'pharma', revenue_eur: 800_000_000 },
7
+ readiness: 'bureaucratic',
8
+ initiatives: [
9
+ { name: 'Invoice Matching Automation', function: 'accounts payable', ai_tier: 'rpa', scores: { strategic_alignment: 70, financial_return: 62, change_enablement: 55, governance_risk: 30 } },
10
+ { name: 'Contact Centre Copilot', function: 'customer service', ai_tier: 'copilot', scores: { strategic_alignment: 68 } },
11
+ { name: 'Contact Centre Copilot', function: 'cx', ai_tier: 'gen2' },
12
+ ],
13
+ };
14
+ test('assembles a valid document from plain-language inputs', () => {
15
+ const r = assemblePortfolio(loose);
16
+ assert.ok(r.portfolio, 'portfolio assembled');
17
+ assert.equal(r.portfolio.organization.industry, 'healthcare');
18
+ assert.equal(r.portfolio.initiatives[0].function, 'finance');
19
+ assert.equal(r.portfolio.initiatives[0].ai_tier, 'gen1');
20
+ assert.equal(r.portfolio.initiatives[1].function, 'cx');
21
+ assert.equal(r.portfolio.initiatives[1].ai_tier, 'gen2');
22
+ assert.equal(r.readiness_used, 'siloed');
23
+ assert.ok(r.validation?.valid, 'assembled document passes validate()');
24
+ assert.ok(validate(r.portfolio).valid, 'external validate agrees');
25
+ });
26
+ test('ids generated from names and deduplicated deterministically', () => {
27
+ const r = assemblePortfolio(loose);
28
+ const ids = r.portfolio.initiatives.map((i) => i.id);
29
+ assert.equal(ids[0], 'invoice-matching-automation');
30
+ assert.equal(ids[1], 'contact-centre-copilot');
31
+ assert.equal(ids[2], 'contact-centre-copilot-2');
32
+ });
33
+ test('missing pillars estimated, reported, and carried with low confidence', () => {
34
+ const r = assemblePortfolio(loose);
35
+ const est = r.estimated_pillars['contact-centre-copilot'];
36
+ assert.deepEqual(est, ['financial_return', 'change_enablement', 'governance_risk']);
37
+ const scores = r.portfolio.initiatives[1].scores;
38
+ assert.equal(typeof scores.strategic_alignment, 'number', 'given pillar stays a bare number');
39
+ assert.equal(typeof scores.financial_return.value, 'number', 'estimated pillar wrapped');
40
+ assert.ok(scores.financial_return.confidence <= 50, 'estimated pillar carries low confidence');
41
+ assert.equal(r.estimated_pillars['invoice-matching-automation'], undefined, 'fully-given initiative reports nothing');
42
+ });
43
+ test('deterministic: same input, same document', () => {
44
+ assert.deepEqual(assemblePortfolio(loose), assemblePortfolio(loose));
45
+ });
46
+ test('read-only: the input object is not mutated', () => {
47
+ const input = structuredClone(loose);
48
+ const snapshot = JSON.stringify(input);
49
+ assemblePortfolio(input);
50
+ assert.equal(JSON.stringify(input), snapshot);
51
+ });
52
+ test('every default is named in assumptions, in plain language', () => {
53
+ const r = assemblePortfolio(loose);
54
+ assert.ok(r.assumptions.some((a) => a.includes('Contact Centre Copilot')), 'estimation named per initiative');
55
+ const noReadiness = assemblePortfolio({ ...structuredClone(loose), readiness: undefined });
56
+ assert.ok(noReadiness.assumptions.some((a) => a.includes('defaulted to traditional')), 'readiness default named');
57
+ const fullyGiven = assemblePortfolio({
58
+ organization: { name: 'X', industry: 'retail' },
59
+ readiness: 'agile',
60
+ initiatives: [{ name: 'A', function: 'cx', ai_tier: 'gen2', scores: { strategic_alignment: 70, financial_return: 60, change_enablement: 60, governance_risk: 30 } }],
61
+ });
62
+ assert.deepEqual(fullyGiven.assumptions, [], 'nothing assumed when everything is given');
63
+ });
64
+ test('unresolvable inputs block assembly with suggestions, never guesses', () => {
65
+ const r = assemblePortfolio({
66
+ organization: { name: 'X', industry: 'floristry' },
67
+ initiatives: [{ name: 'A', function: 'gardening', ai_tier: 'gen2' }],
68
+ });
69
+ assert.equal(r.portfolio, null);
70
+ assert.ok(r.issues.some((i) => i.path === 'organization.industry'));
71
+ assert.ok(r.issues.some((i) => i.path.endsWith('.function')));
72
+ assert.equal(r.validation, null);
73
+ });
74
+ test('adversarial names slugify fast and clean, no polynomial backtracking', () => {
75
+ const hostile = '-'.repeat(500_000) + 'x';
76
+ const started = process.hrtime.bigint();
77
+ const r = assemblePortfolio({
78
+ organization: { name: 'X', industry: 'retail' },
79
+ initiatives: [
80
+ { name: hostile, function: 'cx', ai_tier: 'gen2' },
81
+ { name: '---Invoice --- Matching---', function: 'cx', ai_tier: 'gen2' },
82
+ ],
83
+ });
84
+ const elapsedMs = Number(process.hrtime.bigint() - started) / 1e6;
85
+ assert.ok(elapsedMs < 1000, `slugify took ${elapsedMs}ms on hostile input`);
86
+ assert.equal(r.portfolio.initiatives[0].id, 'initiative');
87
+ assert.equal(r.portfolio.initiatives[1].id, 'invoice-matching');
88
+ });
89
+ test('voice rules hold on all output text', () => {
90
+ const blob = JSON.stringify(assemblePortfolio(loose)) + JSON.stringify(assemblePortfolio({ organization: { name: 'X', industry: 'floristry' }, initiatives: [] }));
91
+ assert.ok(!blob.includes('—'), 'em-dash found');
92
+ for (const w of ['boardroom', 'leverage', 'crucial', 'seamless', 'delve', 'robust']) {
93
+ assert.ok(!blob.toLowerCase().includes(w), `banned word: ${w}`);
94
+ }
95
+ });
96
+ //# sourceMappingURL=assemblePortfolio.test.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"assemblePortfolio.test.js","sourceRoot":"","sources":["../src/assemblePortfolio.test.ts"],"names":[],"mappings":"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"}
package/dist/audit.d.ts CHANGED
@@ -6,6 +6,6 @@
6
6
  */
7
7
  import type { AuditRecord } from './types.js';
8
8
  /** Single source of truth for the engine version; bump with package.json. */
9
- export declare const CORE_VERSION = "0.7.1";
9
+ export declare const CORE_VERSION = "0.8.0";
10
10
  export declare function buildAudit(rules_fired: string[], inputs_used: Record<string, unknown>): AuditRecord;
11
11
  //# sourceMappingURL=audit.d.ts.map
package/dist/audit.js CHANGED
@@ -1,5 +1,5 @@
1
1
  /** Single source of truth for the engine version; bump with package.json. */
2
- export const CORE_VERSION = '0.7.1';
2
+ export const CORE_VERSION = '0.8.0';
3
3
  export function buildAudit(rules_fired, inputs_used) {
4
4
  return {
5
5
  engine: '@aibvf/core',
package/dist/index.d.ts CHANGED
@@ -4,6 +4,7 @@ export { diagnoseProcess, BRAIN_VERSION, EVIDENCE, FUNCTION_MEDIANS, } from './d
4
4
  export { buildChangePlan } from './changePlan.js';
5
5
  export { inferReadiness } from './inferReadiness.js';
6
6
  export { sequencePortfolio } from './sequencePortfolio.js';
7
+ export { assemblePortfolio } from './assemblePortfolio.js';
7
8
  export { mapToTaxonomy } from './aliases.js';
8
9
  export { buildAudit, CORE_VERSION } from './audit.js';
9
10
  export { bvfSchema } from './schema.js';
@@ -1 +1 @@
1
- {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,QAAQ,EAAE,MAAM,eAAe,CAAC;AACzC,OAAO,EACL,KAAK,EACL,qBAAqB,EACrB,sBAAsB,EACtB,eAAe,EAAE,cAAc,EAC/B,UAAU,EAAE,QAAQ,EAAE,QAAQ,EAAE,iBAAiB,EAAE,cAAc,GAClE,MAAM,YAAY,CAAC;AACpB,OAAO,EACL,eAAe,EACf,aAAa,EAAE,QAAQ,EAAE,gBAAgB,GAC1C,MAAM,eAAe,CAAC;AACvB,OAAO,EAAE,eAAe,EAAE,MAAM,iBAAiB,CAAC;AAClD,OAAO,EAAE,cAAc,EAAE,MAAM,qBAAqB,CAAC;AACrD,OAAO,EAAE,iBAAiB,EAAE,MAAM,wBAAwB,CAAC;AAC3D,OAAO,EAAE,aAAa,EAAE,MAAM,cAAc,CAAC;AAC7C,OAAO,EAAE,UAAU,EAAE,YAAY,EAAE,MAAM,YAAY,CAAC;AACtD,OAAO,EAAE,SAAS,EAAE,MAAM,aAAa,CAAC;AACxC,OAAO,EAAE,UAAU,EAAE,SAAS,EAAE,QAAQ,EAAE,SAAS,EAAE,cAAc,EAAE,cAAc,EAAE,UAAU,EAAE,MAAM,eAAe,CAAC;AACvH,mBAAmB,YAAY,CAAC;AAEhC,eAAO,MAAM,WAAW,QAAQ,CAAC"}
1
+ {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,QAAQ,EAAE,MAAM,eAAe,CAAC;AACzC,OAAO,EACL,KAAK,EACL,qBAAqB,EACrB,sBAAsB,EACtB,eAAe,EAAE,cAAc,EAC/B,UAAU,EAAE,QAAQ,EAAE,QAAQ,EAAE,iBAAiB,EAAE,cAAc,GAClE,MAAM,YAAY,CAAC;AACpB,OAAO,EACL,eAAe,EACf,aAAa,EAAE,QAAQ,EAAE,gBAAgB,GAC1C,MAAM,eAAe,CAAC;AACvB,OAAO,EAAE,eAAe,EAAE,MAAM,iBAAiB,CAAC;AAClD,OAAO,EAAE,cAAc,EAAE,MAAM,qBAAqB,CAAC;AACrD,OAAO,EAAE,iBAAiB,EAAE,MAAM,wBAAwB,CAAC;AAC3D,OAAO,EAAE,iBAAiB,EAAE,MAAM,wBAAwB,CAAC;AAC3D,OAAO,EAAE,aAAa,EAAE,MAAM,cAAc,CAAC;AAC7C,OAAO,EAAE,UAAU,EAAE,YAAY,EAAE,MAAM,YAAY,CAAC;AACtD,OAAO,EAAE,SAAS,EAAE,MAAM,aAAa,CAAC;AACxC,OAAO,EAAE,UAAU,EAAE,SAAS,EAAE,QAAQ,EAAE,SAAS,EAAE,cAAc,EAAE,cAAc,EAAE,UAAU,EAAE,MAAM,eAAe,CAAC;AACvH,mBAAmB,YAAY,CAAC;AAEhC,eAAO,MAAM,WAAW,QAAQ,CAAC"}
package/dist/index.js CHANGED
@@ -4,6 +4,7 @@ export { diagnoseProcess, BRAIN_VERSION, EVIDENCE, FUNCTION_MEDIANS, } from './d
4
4
  export { buildChangePlan } from './changePlan.js';
5
5
  export { inferReadiness } from './inferReadiness.js';
6
6
  export { sequencePortfolio } from './sequencePortfolio.js';
7
+ export { assemblePortfolio } from './assemblePortfolio.js';
7
8
  export { mapToTaxonomy } from './aliases.js';
8
9
  export { buildAudit, CORE_VERSION } from './audit.js';
9
10
  export { bvfSchema } from './schema.js';
package/dist/index.js.map CHANGED
@@ -1 +1 @@
1
- {"version":3,"file":"index.js","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,QAAQ,EAAE,MAAM,eAAe,CAAC;AACzC,OAAO,EACL,KAAK,EACL,qBAAqB,EACrB,sBAAsB,EACtB,eAAe,EAAE,cAAc,EAC/B,UAAU,EAAE,QAAQ,EAAE,QAAQ,EAAE,iBAAiB,EAAE,cAAc,GAClE,MAAM,YAAY,CAAC;AACpB,OAAO,EACL,eAAe,EACf,aAAa,EAAE,QAAQ,EAAE,gBAAgB,GAC1C,MAAM,eAAe,CAAC;AACvB,OAAO,EAAE,eAAe,EAAE,MAAM,iBAAiB,CAAC;AAClD,OAAO,EAAE,cAAc,EAAE,MAAM,qBAAqB,CAAC;AACrD,OAAO,EAAE,iBAAiB,EAAE,MAAM,wBAAwB,CAAC;AAC3D,OAAO,EAAE,aAAa,EAAE,MAAM,cAAc,CAAC;AAC7C,OAAO,EAAE,UAAU,EAAE,YAAY,EAAE,MAAM,YAAY,CAAC;AACtD,OAAO,EAAE,SAAS,EAAE,MAAM,aAAa,CAAC;AACxC,OAAO,EAAE,UAAU,EAAE,SAAS,EAAE,QAAQ,EAAE,SAAS,EAAE,cAAc,EAAE,cAAc,EAAE,UAAU,EAAE,MAAM,eAAe,CAAC;AAGvH,MAAM,CAAC,MAAM,WAAW,GAAG,KAAK,CAAC"}
1
+ {"version":3,"file":"index.js","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,QAAQ,EAAE,MAAM,eAAe,CAAC;AACzC,OAAO,EACL,KAAK,EACL,qBAAqB,EACrB,sBAAsB,EACtB,eAAe,EAAE,cAAc,EAC/B,UAAU,EAAE,QAAQ,EAAE,QAAQ,EAAE,iBAAiB,EAAE,cAAc,GAClE,MAAM,YAAY,CAAC;AACpB,OAAO,EACL,eAAe,EACf,aAAa,EAAE,QAAQ,EAAE,gBAAgB,GAC1C,MAAM,eAAe,CAAC;AACvB,OAAO,EAAE,eAAe,EAAE,MAAM,iBAAiB,CAAC;AAClD,OAAO,EAAE,cAAc,EAAE,MAAM,qBAAqB,CAAC;AACrD,OAAO,EAAE,iBAAiB,EAAE,MAAM,wBAAwB,CAAC;AAC3D,OAAO,EAAE,iBAAiB,EAAE,MAAM,wBAAwB,CAAC;AAC3D,OAAO,EAAE,aAAa,EAAE,MAAM,cAAc,CAAC;AAC7C,OAAO,EAAE,UAAU,EAAE,YAAY,EAAE,MAAM,YAAY,CAAC;AACtD,OAAO,EAAE,SAAS,EAAE,MAAM,aAAa,CAAC;AACxC,OAAO,EAAE,UAAU,EAAE,SAAS,EAAE,QAAQ,EAAE,SAAS,EAAE,cAAc,EAAE,cAAc,EAAE,UAAU,EAAE,MAAM,eAAe,CAAC;AAGvH,MAAM,CAAC,MAAM,WAAW,GAAG,KAAK,CAAC"}
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@aibvf/core",
3
- "version": "0.7.1",
3
+ "version": "0.8.0",
4
4
  "description": "AI BVF \u2014 open protocol for scoring AI investments. Validator and scoring engine.",
5
5
  "keywords": [
6
6
  "ai",