naive-framework 0.2.0 → 0.3.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.
- package/AGENTS.md +1 -1
- package/docs/decisions/decisions.json +15 -0
- package/evidence/skills/fidelity-ladder-audit/ladder-census.mjs +2 -1
- package/interface/adapters.mjs +7 -6
- package/interface/boundaries.mjs +5 -4
- package/interface/brand.mjs +6 -5
- package/interface/cli/mentura.mjs +4 -3
- package/interface/cli/naive.mjs +11 -6
- package/interface/context.mjs +7 -6
- package/interface/demo/board.mjs +9 -8
- package/interface/demo/decision-harness.mjs +4 -3
- package/interface/gate-hooks.mjs +2 -1
- package/interface/harness/evals.mjs +8 -7
- package/interface/harness/run.mjs +14 -13
- package/interface/instrumentation.mjs +4 -3
- package/interface/package-routes.mjs +4 -3
- package/interface/provenance.mjs +5 -4
- package/interface/reads.mjs +4 -3
- package/interface/release-card.mjs +2 -1
- package/interface/router.mjs +10 -9
- package/interface/vitals.mjs +3 -2
- package/knowledge/connectors/catalog.mjs +3 -2
- package/knowledge/connectors/filesystem.mjs +10 -5
- package/knowledge/connectors/index.mjs +3 -2
- package/operations/marketing/check-public.mjs +7 -6
- package/operations/marketing/site/plan.mjs +4 -3
- package/operations/marketing/site/presence.mjs +4 -3
- package/package.json +1 -1
- package/platform/integrations/rho.mjs +2 -1
- package/purpose/frameworks/idea-map/route.mjs +5 -4
- package/purpose/frameworks/product-anatomy/anatomy.mjs +2 -1
- package/schema/access.mjs +2 -1
- package/schema/add-department.mjs +3 -2
- package/schema/assess-problem.mjs +3 -2
- package/schema/assets.mjs +6 -5
- package/schema/brand.mjs +11 -10
- package/schema/caching.mjs +5 -4
- package/schema/check-config.mjs +4 -3
- package/schema/check-data-model.mjs +2 -1
- package/schema/check-data-packages.mjs +5 -4
- package/schema/check-execution.mjs +4 -3
- package/schema/check-people.mjs +22 -8
- package/schema/check-private.mjs +2 -1
- package/schema/check-ready.mjs +6 -5
- package/schema/check-sources.mjs +2 -1
- package/schema/check-where-used.mjs +4 -3
- package/schema/decision-analytics.mjs +2 -1
- package/schema/decisions.mjs +14 -11
- package/schema/foundation.mjs +8 -7
- package/schema/founder.schema.json +2 -2
- package/schema/frames.mjs +4 -3
- package/schema/freshness.mjs +13 -12
- package/schema/gate-drafts.mjs +8 -7
- package/schema/init-venture.mjs +38 -20
- package/schema/migrate-venture.mjs +8 -7
- package/schema/migrations/kit-to-package.mjs +4 -3
- package/schema/migrations/package-layout.mjs +9 -5
- package/schema/model-steps.mjs +8 -7
- package/schema/naive-config.mjs +4 -3
- package/schema/need-now.mjs +5 -4
- package/schema/packages.mjs +11 -10
- package/schema/payouts.mjs +3 -2
- package/schema/people.schema.json +2 -3
- package/schema/port-venture.mjs +206 -132
- package/schema/release-read.mjs +5 -4
- package/schema/releases.mjs +21 -20
- package/schema/run-handoff.mjs +5 -4
- package/schema/setup.mjs +5 -4
- package/schema/stale.mjs +6 -5
- package/schema/structure.mjs +5 -4
- package/schema/time-to-ready.mjs +7 -6
- package/schema/triggers.mjs +7 -6
- package/schema/upgrades.mjs +31 -30
- package/schema/venture-paths.mjs +85 -0
- package/schema/venture.schema.json +25 -17
- package/schema/workspace.schema.json +5 -1
package/schema/model-steps.mjs
CHANGED
|
@@ -47,6 +47,7 @@ import { call as routerCall, files as ventureFiles, glob, routes } from "../inte
|
|
|
47
47
|
import { agentFromEnv, entries as provEntries, record as prov } from "../interface/provenance.mjs";
|
|
48
48
|
import { decisions as decisionsOf, propose } from "./decisions.mjs";
|
|
49
49
|
import { loadPackages } from "./load-packages.mjs";
|
|
50
|
+
import { ventureFile } from "./venture-paths.mjs";
|
|
50
51
|
|
|
51
52
|
const repo = new URL("..", import.meta.url).pathname;
|
|
52
53
|
const load = (p) => JSON.parse(readFileSync(p, "utf8"));
|
|
@@ -264,7 +265,7 @@ async function context(dir, { call = routerCall, workspace } = {}) {
|
|
|
264
265
|
let byId = null;
|
|
265
266
|
const recordById = (id) => {
|
|
266
267
|
byId ??= new Map(ventureFiles(dir).filter((f) => f.endsWith(".json") && !f.startsWith("knowledge/judgments/")).flatMap((f) => {
|
|
267
|
-
try { const r = load(
|
|
268
|
+
try { const r = load(ventureFile(dir, f)); return r && typeof r.id === "string" ? [[r.id, { file: f, record: r }]] : []; } catch { return []; }
|
|
268
269
|
}));
|
|
269
270
|
return byId.get(id) ?? null;
|
|
270
271
|
};
|
|
@@ -583,8 +584,8 @@ function confirmedBy(dir, file) {
|
|
|
583
584
|
return c ? c.agent.id ?? "a person" : null;
|
|
584
585
|
}
|
|
585
586
|
const isModelJudgment = (dir, f) => {
|
|
586
|
-
if (!glob(`${JUDGMENTS}/*.json`).test(f) || !existsSync(
|
|
587
|
-
try { return load(
|
|
587
|
+
if (!glob(`${JUDGMENTS}/*.json`).test(f) || !existsSync(ventureFile(dir, f))) return false;
|
|
588
|
+
try { return load(ventureFile(dir, f)).by?.kind === "model"; } catch { return false; }
|
|
588
589
|
};
|
|
589
590
|
|
|
590
591
|
/**
|
|
@@ -603,12 +604,12 @@ export async function provenanceOf(dir, file, { checks = false, call = routerCal
|
|
|
603
604
|
if (last.agent.kind === "person" || confirmed) return { entity: file, status: "person", model: false, downstream_of_model: [],
|
|
604
605
|
why: confirmed ? `confirmed by ${confirmed.agent.id ?? "a person"}` : `${last.activity === "accept" ? "accepted" : "written"} by ${last.agent.id ?? "a person"}` };
|
|
605
606
|
const upstream = [];
|
|
606
|
-
for (const d of (last.derived_from ?? []).map((x) => x.split("#")[0]).filter((x) => !seen.has(x) && existsSync(
|
|
607
|
+
for (const d of (last.derived_from ?? []).map((x) => x.split("#")[0]).filter((x) => !seen.has(x) && existsSync(ventureFile(dir, x)))) {
|
|
607
608
|
const u = await provenanceOf(dir, d, { seen });
|
|
608
609
|
if (u.model) upstream.push(d); else upstream.push(...u.downstream_of_model);
|
|
609
610
|
}
|
|
610
611
|
const res = { entity: file, status: "agent", model, downstream_of_model: [...new Set(upstream)], why: model ? `a model's judgment (${last.note ?? "use model"}); a person confirms it` : upstream.length ? "an agent wrote it from a model's output" : "an agent wrote it" };
|
|
611
|
-
if (checks && !(model && load(
|
|
612
|
+
if (checks && !(model && load(ventureFile(dir, file)).kind === "draft") && last.route) {
|
|
612
613
|
const venture = load(join(dir, "venture.json")).id;
|
|
613
614
|
const r = await call({ venture, workspace: workspace ?? dirname(dir), route: last.route, action: "check" });
|
|
614
615
|
if (r.ok && r.result?.length) return { ...res, status: "clear", why: `${res.why}; its checks pass (${r.result.map((x) => x.check).join(", ")})` };
|
|
@@ -620,8 +621,8 @@ export async function provenanceOf(dir, file, { checks = false, call = routerCal
|
|
|
620
621
|
export function confirm(dir, id, { by, note } = {}) {
|
|
621
622
|
if (!by) throw new Expected("confirming needs the person's name (--by)", "refused");
|
|
622
623
|
const file = `${JUDGMENTS}/${id}.json`;
|
|
623
|
-
if (!existsSync(
|
|
624
|
-
const j = load(
|
|
624
|
+
if (!existsSync(ventureFile(dir, file))) throw new Expected(`no judgment ${id}`, "missing record");
|
|
625
|
+
const j = load(ventureFile(dir, file));
|
|
625
626
|
if (j.outcome === "uncertain") throw new Expected(`${id} is uncertain: answer its decision ${j.decision} instead`, "refused");
|
|
626
627
|
const e = prov(dir, { entity: file, route: `knowledge/judgment/${id}`, activity: "confirm", agent: agentFromEnv("person", "cli", { id: by }), note: note ?? `confirmed ${j.package}/${j.step}${j.item ? ` for ${j.item}` : ""}` });
|
|
627
628
|
return { confirmed: id, by, provenance: e.hash };
|
package/schema/naive-config.mjs
CHANGED
|
@@ -10,6 +10,7 @@
|
|
|
10
10
|
|
|
11
11
|
import { existsSync, readFileSync, readdirSync, writeFileSync } from "node:fs";
|
|
12
12
|
import { join } from "node:path";
|
|
13
|
+
import { ventureFile } from "./venture-paths.mjs";
|
|
13
14
|
|
|
14
15
|
const repo = new URL("..", import.meta.url).pathname;
|
|
15
16
|
const load = (p) => JSON.parse(readFileSync(p, "utf8"));
|
|
@@ -36,7 +37,7 @@ function merge(base, over) {
|
|
|
36
37
|
|
|
37
38
|
/** The venture's naive.config.json as written, or {} when it has none. A file that is not JSON throws, naming the file. */
|
|
38
39
|
export function rawConfig(dir) {
|
|
39
|
-
const f = dir &&
|
|
40
|
+
const f = dir && ventureFile(dir, CONFIG);
|
|
40
41
|
if (!f || !existsSync(f)) return {};
|
|
41
42
|
try { return load(f); } catch (e) { throw new Error(`${CONFIG} is not valid JSON: ${e.message}`); }
|
|
42
43
|
}
|
|
@@ -139,7 +140,7 @@ export function pinsBlocking(config, recordType) {
|
|
|
139
140
|
|
|
140
141
|
/** The venture's naive.config.json, or {} when it has none. A file that is not JSON throws. */
|
|
141
142
|
export function readConfig(dir) {
|
|
142
|
-
const f =
|
|
143
|
+
const f = ventureFile(dir, CONFIG);
|
|
143
144
|
if (!existsSync(f)) return {};
|
|
144
145
|
try { return JSON.parse(readFileSync(f, "utf8")); }
|
|
145
146
|
catch (e) { throw new Error(`${CONFIG} is not valid JSON: ${e.message}`); }
|
|
@@ -149,7 +150,7 @@ export function readConfig(dir) {
|
|
|
149
150
|
export function writeConfig(dir, cfg) {
|
|
150
151
|
const order = ["naive", "packages", "kits", "triggers", "gate"];
|
|
151
152
|
const out = Object.fromEntries([...order.filter((k) => cfg[k] !== undefined).map((k) => [k, cfg[k]]), ...Object.entries(cfg).filter(([k]) => !order.includes(k))]);
|
|
152
|
-
writeFileSync(
|
|
153
|
+
writeFileSync(ventureFile(dir, CONFIG), JSON.stringify(out, null, 2) + "\n");
|
|
153
154
|
return out;
|
|
154
155
|
}
|
|
155
156
|
|
package/schema/need-now.mjs
CHANGED
|
@@ -15,6 +15,7 @@
|
|
|
15
15
|
import { existsSync, readFileSync, readdirSync } from "node:fs";
|
|
16
16
|
import { join } from "node:path";
|
|
17
17
|
import { catalog } from "./departments.mjs";
|
|
18
|
+
import { ventureFile } from "./venture-paths.mjs";
|
|
18
19
|
|
|
19
20
|
const root = new URL("..", import.meta.url).pathname;
|
|
20
21
|
const load = (p) => JSON.parse(readFileSync(p, "utf8"));
|
|
@@ -27,14 +28,14 @@ const glob = (g) => new RegExp("^" + g.replace(/[.+^${}()|[\]\\]/g, "\\$&").repl
|
|
|
27
28
|
/** Facts about a venture that the need-now conditions test. */
|
|
28
29
|
export function factsOf(dir) {
|
|
29
30
|
const v = load(join(dir, "venture.json"));
|
|
30
|
-
const json = (p) => existsSync(
|
|
31
|
-
const products = existsSync(join(dir, "products")) ? readdirSync(join(dir, "products")).filter((f) => f.endsWith(".json")).map((f) => load(join(dir, "products", f))) : [];
|
|
31
|
+
const json = (p) => existsSync(ventureFile(dir, p)) ? load(ventureFile(dir, p)) : null;
|
|
32
|
+
const products = existsSync(join(ventureFile(dir, "products"))) ? readdirSync(join(ventureFile(dir, "products"))).filter((f) => f.endsWith(".json")).map((f) => load(join(ventureFile(dir, "products"), f))) : [];
|
|
32
33
|
const members = (v.members ?? []).map((m) => typeof m === "string" ? { kind: "person", role: m } : m);
|
|
33
34
|
const own = json("governance/ownership.json");
|
|
34
|
-
const hDir = join(dir, "operations/handoffs");
|
|
35
|
+
const hDir = join(ventureFile(dir, "operations/handoffs"));
|
|
35
36
|
const handoffs = existsSync(hDir) ? readdirSync(hDir).filter((f) => f.endsWith(".json")).map((f) => load(join(hDir, f))) : [];
|
|
36
37
|
// The founding team, as the founder answered Naive's team question (EE-060): solo, cofounders or looking.
|
|
37
|
-
const teamFile = join(dir, "decisions/venture.team.decision.json");
|
|
38
|
+
const teamFile = join(ventureFile(dir, "decisions/venture.team.decision.json"));
|
|
38
39
|
const td = existsSync(teamFile) ? load(teamFile) : null;
|
|
39
40
|
const team = td?.status === "decided" ? ["solo", "cofounders", "looking"].find((t) => (td.answer ?? "").toLowerCase().startsWith(t)) ?? null : null;
|
|
40
41
|
return {
|
package/schema/packages.mjs
CHANGED
|
@@ -31,6 +31,7 @@ import { route } from "../purpose/frameworks/idea-map/route.mjs";
|
|
|
31
31
|
import { loadPackages } from "./load-packages.mjs";
|
|
32
32
|
// Upgrades hook (U-5): packages a venture adopted early in naive.config.json open now.
|
|
33
33
|
import { adopted } from "./naive-config.mjs";
|
|
34
|
+
import { ventureFile } from "./venture-paths.mjs";
|
|
34
35
|
|
|
35
36
|
const repo = new URL("..", import.meta.url).pathname;
|
|
36
37
|
const load = (p) => JSON.parse(readFileSync(p, "utf8"));
|
|
@@ -39,7 +40,7 @@ export const OUT = "package";
|
|
|
39
40
|
const MODEL = load(join(repo, "schema/data-model.json"));
|
|
40
41
|
const PHASES = ["discovery", "validation", "beachhead", "scale", "platform"];
|
|
41
42
|
const r2 = (x) => Math.round(x * 100) / 100;
|
|
42
|
-
const json = (dir, f) => existsSync(
|
|
43
|
+
const json = (dir, f) => existsSync(ventureFile(dir, f)) ? load(ventureFile(dir, f)) : null;
|
|
43
44
|
|
|
44
45
|
/** The facts the packages test: need-now's, the founder's flags, and the question matrix's answers. */
|
|
45
46
|
export function situation(dir, { flags = {}, answers = null } = {}) {
|
|
@@ -52,7 +53,7 @@ export function situation(dir, { flags = {}, answers = null } = {}) {
|
|
|
52
53
|
const settled = {
|
|
53
54
|
raising: flags.raising != null ? !!flags.raising : f.funding === "bootstrapped" ? false : undefined,
|
|
54
55
|
// A site read by site presence; a planned sitemap does not count, since the pipeline plans one for every venture.
|
|
55
|
-
site: existsSync(join(dir, "operations/marketing/site-presence.json")) || undefined,
|
|
56
|
+
site: existsSync(join(ventureFile(dir, "operations/marketing/site-presence.json"))) || undefined,
|
|
56
57
|
partner_led: profiles.some((p) => p.reached_through?.length) || products.some((p) => (p.offered_to ?? []).some((id) => profiles.some((y) => y.reached_through?.includes(id)))) || undefined,
|
|
57
58
|
hiring: flags.hiring != null ? !!flags.hiring : f.team === "looking" ? true : undefined,
|
|
58
59
|
regulated: undefined,
|
|
@@ -60,7 +61,7 @@ export function situation(dir, { flags = {}, answers = null } = {}) {
|
|
|
60
61
|
};
|
|
61
62
|
const Q = PACKAGES.questions;
|
|
62
63
|
// Jev's answers from the last written package stand, unless new answers replace them.
|
|
63
|
-
const last = existsSync(join(dir, OUT, "venture-package.json")) ? Object.fromEntries(load(join(dir, OUT, "venture-package.json")).situation.questions.filter((q) => q.p != null).map((q) => [`q:${q.id}`, { noul: q.p }])) : {};
|
|
64
|
+
const last = existsSync(join(ventureFile(dir, OUT), "venture-package.json")) ? Object.fromEntries(load(join(ventureFile(dir, OUT), "venture-package.json")).situation.questions.filter((q) => q.p != null).map((q) => [`q:${q.id}`, { noul: q.p }])) : {};
|
|
64
65
|
answers = { ...last, ...(answers ?? {}) };
|
|
65
66
|
const questions = Q.items.filter((q) => q.phases.includes(phase)).map((q) => {
|
|
66
67
|
if (settled[q.id] !== undefined) return { ...q, value: settled[q.id], by: "records" };
|
|
@@ -77,8 +78,8 @@ export function request(dir) {
|
|
|
77
78
|
const { questions } = situation(dir);
|
|
78
79
|
const v = load(join(dir, "venture.json"));
|
|
79
80
|
const say = (o) => o ? JSON.stringify(o).slice(0, 1200) : null;
|
|
80
|
-
const dumpFile = ["raw/dump.md", "purpose/ideas/dump.md"].find((f) => existsSync(
|
|
81
|
-
const dump = dumpFile ? readFileSync(
|
|
81
|
+
const dumpFile = ["raw/dump.md", "purpose/ideas/dump.md"].find((f) => existsSync(ventureFile(dir, f)));
|
|
82
|
+
const dump = dumpFile ? readFileSync(ventureFile(dir, dumpFile), "utf8").slice(0, 2500) : null;
|
|
82
83
|
const problem = json(dir, "foundation/problem.json") ?? json(dir, "purpose/validation/problem.json");
|
|
83
84
|
const icpRec = json(dir, "foundation/icp.json") ?? json(dir, "purpose/icp.json");
|
|
84
85
|
return { state: { venture: say({ name: v.name, phase: v.phase, ambition: v.ambition, form: v.form, core: v.core }), problem: say(problem), icp: say(icpRec),
|
|
@@ -89,9 +90,9 @@ export function request(dir) {
|
|
|
89
90
|
|
|
90
91
|
/** A record's state in this venture: confirmed by a person, written by an agent, waiting as a draft, or missing. */
|
|
91
92
|
function stateOf(dir, type) {
|
|
92
|
-
const files = filesOf(dir, type).filter((f) => existsSync(
|
|
93
|
+
const files = filesOf(dir, type).filter((f) => existsSync(ventureFile(dir, f)) && !(f.endsWith(".json") && ["retired", "archived"].includes(json(dir, f)?.status)));
|
|
93
94
|
const drafts = (filesOf(dir, type).length ? filesOf(dir, type) : [MODEL.records.find((r) => r.id === type)?.paths?.find((p) => p.startsWith("instance/**/"))?.slice(12)].filter(Boolean))
|
|
94
|
-
.filter((f) => !f.includes("*") && existsSync(
|
|
95
|
+
.filter((f) => !f.includes("*") && existsSync(ventureFile(dir, `_drafts/${f.replace(/\//g, "__")}.draft`)));
|
|
95
96
|
if (!files.length) return { status: drafts.length ? "draft" : "missing", files: [], drafts };
|
|
96
97
|
const confirmed = files.every((f) => confirmedIn(dir, f, null));
|
|
97
98
|
return { status: drafts.length ? "draft" : confirmed ? "confirmed" : "agent", files, drafts };
|
|
@@ -174,7 +175,7 @@ const LEAD = ["name", "title", "who", "statement", "question", "label", "id"];
|
|
|
174
175
|
const lead = (o) => { const k = LEAD.find((k) => typeof o[k] === "string"); return k ? o[k] : ""; };
|
|
175
176
|
const rest = (o) => { const k = LEAD.find((k) => typeof o[k] === "string"); return Object.fromEntries(Object.entries(o).filter(([x]) => x !== k)); };
|
|
176
177
|
const body = (dir, f) => {
|
|
177
|
-
const t = readFileSync(
|
|
178
|
+
const t = readFileSync(ventureFile(dir, f), "utf8");
|
|
178
179
|
if (f.endsWith(".json")) return md(JSON.parse(t));
|
|
179
180
|
return t.replace(/^---\n[\s\S]*?\n---\n/, "").replace(/^#\s.*\n/, "").trim();
|
|
180
181
|
};
|
|
@@ -183,7 +184,7 @@ const STATE = { complete: "complete: its automation may run", review: "every rec
|
|
|
183
184
|
|
|
184
185
|
/** A new version each time a package completes or the phase changes; earlier versions are kept. */
|
|
185
186
|
export function versions(dir, r) {
|
|
186
|
-
const f = join(dir, OUT, "venture-package.json");
|
|
187
|
+
const f = join(ventureFile(dir, OUT), "venture-package.json");
|
|
187
188
|
const before = existsSync(f) ? load(f) : null;
|
|
188
189
|
const list = before?.versions ?? [];
|
|
189
190
|
const last = list.at(-1);
|
|
@@ -196,7 +197,7 @@ export function versions(dir, r) {
|
|
|
196
197
|
|
|
197
198
|
/** Write the readable view: the manifest, the index, and one document per open core package. */
|
|
198
199
|
export function write(dir, r) {
|
|
199
|
-
const out =
|
|
200
|
+
const out = ventureFile(dir, OUT);
|
|
200
201
|
mkdirSync(out, { recursive: true });
|
|
201
202
|
r.versions = versions(dir, r);
|
|
202
203
|
writeFileSync(join(out, "venture-package.json"), JSON.stringify(r, null, 2) + "\n");
|
package/schema/payouts.mjs
CHANGED
|
@@ -16,6 +16,7 @@
|
|
|
16
16
|
|
|
17
17
|
import { existsSync, readFileSync } from "node:fs";
|
|
18
18
|
import { join } from "node:path";
|
|
19
|
+
import { ventureFile } from "./venture-paths.mjs";
|
|
19
20
|
|
|
20
21
|
export function payouts(own, value) {
|
|
21
22
|
const classes = new Map(own.classes.map((c) => [c.id, c]));
|
|
@@ -74,8 +75,8 @@ export function payouts(own, value) {
|
|
|
74
75
|
if (import.meta.url === `file://${process.argv[1]}`) {
|
|
75
76
|
const [dir, arg] = process.argv.slice(2);
|
|
76
77
|
if (!dir) { console.error("usage: node schema/payouts.mjs <venture dir> [value] [--json]"); process.exit(2); }
|
|
77
|
-
const own = JSON.parse(readFileSync(join(dir, "governance/ownership.json"), "utf8"));
|
|
78
|
-
const exitFile = join(dir, "governance/exit.json");
|
|
78
|
+
const own = JSON.parse(readFileSync(join(ventureFile(dir, "governance/ownership.json")), "utf8"));
|
|
79
|
+
const exitFile = join(ventureFile(dir, "governance/exit.json"));
|
|
79
80
|
const scenarios = arg && !arg.startsWith("--") ? [{ id: "given", value: Number(arg) }]
|
|
80
81
|
: existsSync(exitFile) ? JSON.parse(readFileSync(exitFile, "utf8")).scenarios ?? [] : [];
|
|
81
82
|
if (!scenarios.length) { console.error("no scenarios: pass a value or add scenarios to governance/exit.json"); process.exit(2); }
|
|
@@ -29,8 +29,7 @@
|
|
|
29
29
|
"required": [
|
|
30
30
|
"id",
|
|
31
31
|
"name",
|
|
32
|
-
"role"
|
|
33
|
-
"hats"
|
|
32
|
+
"role"
|
|
34
33
|
],
|
|
35
34
|
"additionalProperties": false,
|
|
36
35
|
"properties": {
|
|
@@ -65,7 +64,7 @@
|
|
|
65
64
|
]
|
|
66
65
|
},
|
|
67
66
|
"uniqueItems": true,
|
|
68
|
-
"description": "The functions this person owns (
|
|
67
|
+
"description": "The functions this person owns. In the structured layout (EE-086) hats are read from the org chart in venture.json and not stored here"
|
|
69
68
|
},
|
|
70
69
|
"founder_file": {
|
|
71
70
|
"type": "string",
|