Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
16 changes: 9 additions & 7 deletions build/model.mjs
Original file line number Diff line number Diff line change
Expand Up @@ -21,6 +21,7 @@ import { fileURLToPath } from "node:url";
import { parseInstance, imagesOf } from "companygraph-meta-model/instance";
import { syncImages } from "@robertblust/design/images";
import { readInstance } from "./read.mjs";
import { readSchemas } from "./schemas.mjs";

const ROOT = path.join(path.dirname(fileURLToPath(import.meta.url)), "..");
const { repo, commit } = JSON.parse(fs.readFileSync(path.join(ROOT, "source.json"), "utf8"));
Expand All @@ -32,13 +33,14 @@ const SUB = "model/";

// The vendored core sits beside the container, and the parser reads the model against it:
// R16 makes the declared type the only thing that decides which fields are edges, so the
// schemas travel with the pages they declare.
const CORE = "meta/core/";

const [files, schemas] = await Promise.all([
readInstance({ repo, commit, sub: SUB }),
readInstance({ repo, commit, sub: CORE }),
]);
// schemas travel with the pages they declare. The packs the model's `.companygraph/manifest.json`
// lists are vendored beside core and read with it (`build/schemas.mjs`), or a pack's folders
// fail R13 as declared by no schema. A file read is the one file at that path, or undefined.
const read = async (sub, o) => {
const got = await readInstance({ repo, commit, sub });
return o?.file ? got.get("") : got;
};
const [files, schemas] = await Promise.all([readInstance({ repo, commit, sub: SUB }), readSchemas(read)]);
// `repo` travels with the data because the stage draws more than one repository's model and the
// file link has to point at the right one. `sub` is where these files sit in the model's own
// repository, and the parser needs it: an entity's `path` is what a page turns into a link to
Expand Down
4 changes: 4 additions & 0 deletions build/read.mjs
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,10 @@ function readLocal(dir, commit, sub) {
}
const root = path.join(dir, sub);
const files = new Map();
// An absent folder is no files, as it is on GitHub, and a path to one file is that file
// under the empty key, as the remote listing gives it.
if (!fs.existsSync(root)) return files;
if (fs.statSync(root).isFile()) return files.set("", fs.readFileSync(root, "utf8"));
const walk = (d) => {
for (const ent of fs.readdirSync(d, { withFileTypes: true })) {
const p = path.join(d, ent.name);
Expand Down
38 changes: 38 additions & 0 deletions build/renderers.test.mjs
Original file line number Diff line number Diff line change
Expand Up @@ -322,3 +322,41 @@ test("check mode reports a home page behind the blog index", () => {
test("a blog index with no entry is an error, not an empty section", () => {
assert.throws(() => writeLatest({}, { root: latestSite("") }), /no entry/);
});

import { readSchemas } from "./schemas.mjs";

// The model's repository as `read(sub, { file })` sees it: a folder read returns the files
// under the prefix with it stripped, a file read returns the text or undefined.
function repoReader(tree) {
return async (sub, { file } = {}) => {
if (file) return tree[sub];
return new Map(Object.entries(tree).filter(([k]) => k.startsWith(sub)).map(([k, v]) => [k.slice(sub.length), v]));
};
}

test("readSchemas carries each pack the manifest lists beside core, under <pack>/<file>", async () => {
const read = repoReader({
".companygraph/manifest.json": JSON.stringify({ units: "meta", packs: ["landscape"] }),
"meta/core/skill-schema.md": "core skill",
"meta/landscape/system-schema.md": "pack system",
"meta/other/stray-schema.md": "not listed",
"model/skill/x.md": "a page",
});
assert.deepEqual([...(await readSchemas(read)).keys()].sort(), ["landscape/system-schema.md", "skill-schema.md"]);
});

test("readSchemas on a model without packs is core alone, as before", async () => {
for (const manifest of [JSON.stringify({ units: "meta" }), undefined]) {
const read = repoReader({
...(manifest ? { ".companygraph/manifest.json": manifest } : {}),
"meta/core/a-schema.md": "a",
"meta/landscape/b-schema.md": "left on disk, not taken",
});
assert.deepEqual([...(await readSchemas(read)).keys()], ["a-schema.md"]);
}
});

test("readSchemas names the manifest and the folder when a listed pack has no files", async () => {
const read = repoReader({ ".companygraph/manifest.json": JSON.stringify({ packs: ["landscape"] }), "meta/core/a-schema.md": "a" });
await assert.rejects(readSchemas(read), /manifest\.json lists the pack "landscape", but meta\/landscape\/ has no files/);
});
29 changes: 29 additions & 0 deletions build/schemas.mjs
Original file line number Diff line number Diff line change
@@ -0,0 +1,29 @@
// The schemas an instance is written against: its core, vendored at `<units>/core/`, and the
// pack folders its `.companygraph/manifest.json` lists, vendored beside it at `<units>/<pack>/`.
// Core's files travel under bare keys and a pack's under `<pack>/<file>`, which is how the
// parser tells them apart (R20) and how meta-model's own `readInstance` hands them over.
// `read(sub)` returns the files under one folder of the instance's repository with that
// prefix stripped, whether from a checkout or from GitHub.
export async function readSchemas(read) {
const where = ".companygraph/manifest.json";
const text = await read(where, { file: true });
let manifest = {};
if (text !== undefined) {
try { manifest = JSON.parse(text); }
catch (e) { throw new Error(`${where} is not valid JSON: ${e.message}`); }
}
const packs = manifest.packs ?? [];
if (!Array.isArray(packs) || packs.some((p) => typeof p !== "string"))
throw new Error(`${where}: "packs" must be an array of pack names, got ${JSON.stringify(packs)}`);
const units = manifest.units ?? "meta";
const schemas = new Map(await read(`${units}/core/`));
for (const pack of packs) {
let files;
try { files = await read(`${units}/${pack}/`); }
catch (e) { if (e?.code !== "ENOENT") throw e; files = new Map(); }
if (files.size === 0)
throw new Error(`${where} lists the pack "${pack}", but ${units}/${pack}/ has no files in the instance`);
for (const [file, text] of files) schemas.set(`${pack}/${file}`, text);
}
return schemas;
}
13 changes: 13 additions & 0 deletions id/01a1713f-850d-7445-bc3b-c9601a117304/index.html
Original file line number Diff line number Diff line change
@@ -0,0 +1,13 @@
<!doctype html>
<html lang="en">
<head>
<meta charset="utf-8">
<meta name="viewport" content="width=device-width, initial-scale=1">
<title>Deployment</title>
<meta name="robots" content="noindex">
<meta http-equiv="refresh" content="0; url=../../model/?stage=expanded#system-kinds/deployment">
</head>
<body>
<p>Go on to <a href="../../model/?stage=expanded#system-kinds/deployment">Deployment</a>.</p>
</body>
</html>
13 changes: 13 additions & 0 deletions id/01a1713f-93a4-77e2-ae7c-46e9dfe5e912/index.html
Original file line number Diff line number Diff line change
@@ -0,0 +1,13 @@
<!doctype html>
<html lang="en">
<head>
<meta charset="utf-8">
<meta name="viewport" content="width=device-width, initial-scale=1">
<title>id.blust.ch</title>
<meta name="robots" content="noindex">
<meta http-equiv="refresh" content="0; url=../../model/?stage=expanded#systems/id-blust-ch">
</head>
<body>
<p>Go on to <a href="../../model/?stage=expanded#systems/id-blust-ch">id.blust.ch</a>.</p>
</body>
</html>
125 changes: 124 additions & 1 deletion model.json
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
{
"commit": "c259512efa40734c3fa9102ef718d0641bfcb9e7",
"commit": "7fd8db9bc43194bf8c01a6cae0498349de9340f5",
"core": "0.69.0",
"root": "Robert Blust",
"rootId": "01a04c85-bc20-7849-9ec1-d877215d70b4",
Expand Down Expand Up @@ -202,6 +202,18 @@
"owner": null,
"singular": false
},
{
"type": "system",
"folder": "systems",
"owner": null,
"singular": false
},
{
"type": "system-kind",
"folder": "system-kinds",
"owner": null,
"singular": false
},
{
"type": "track",
"folder": "tracks",
Expand Down Expand Up @@ -21766,6 +21778,81 @@
"owner": null,
"path": "model/surfaces/mcp-registry-listing.md"
},
{
"id": "01a1713f-850d-7445-bc3b-c9601a117304",
"address": "system-kinds/deployment",
"type": "system-kind",
"name": "Deployment",
"tagline": "Software the company deploys from its own repositories to a platform it rents, and runs there.",
"fields": {
"id": "01a1713f-850d-7445-bc3b-c9601a117304",
"source": "Local",
"rank": "10",
"element": "application-component"
},
"sections": [
{
"heading": "What it means",
"text": "A deployment is software that one of the company's repositories deploys, by that repository's workflows on a merge, to a platform the company rents, whether the company wrote the software or runs it as its maker publishes it. The company holds what the deployment needs to run: its configuration, its secrets and the project it runs in. It is not software a vendor runs that the company only signs in to, and not the platform a deployment runs on.",
"tables": []
}
],
"owner": null,
"path": "model/system-kinds/deployment.md"
},
{
"id": "01a1713f-93a4-77e2-ae7c-46e9dfe5e912",
"address": "systems/id-blust-ch",
"type": "system",
"name": "id.blust.ch",
"tagline": "Signs readers in to the chat on blust.ch, and to the chats on companygraph.io and guestgraph.io, with ZITADEL, the identity service the company runs at https://id.blust.ch in its Google Cloud project blust-ch-mcp in the Zurich region, where accounts are by invitation only, and issues the token from which each chat reads the models a reader may choose.",
"fields": {
"id": "01a1713f-93a4-77e2-ae7c-46e9dfe5e912",
"source": "Local",
"kind": "Deployment",
"owner": "Owner",
"processor": "Google Cloud",
"serves": [
"Answering"
]
},
"sections": [
{
"heading": "References",
"text": "",
"tables": [
{
"caption": null,
"columns": [
"What",
"URL"
],
"rows": [
[
"The service's source, infrastructure and the owner's steps",
"https://github.com/robertblust/id-blust-ch"
]
]
}
],
"table": {
"caption": null,
"columns": [
"What",
"URL"
],
"rows": [
[
"The service's source, infrastructure and the owner's steps",
"https://github.com/robertblust/id-blust-ch"
]
]
}
}
],
"owner": null,
"path": "model/systems/id-blust-ch.md"
},
{
"id": "01a04d2d-0070-7801-8563-bbc8d6eed1d0",
"address": "values/build-the-alternative-before-making-the-point",
Expand Down Expand Up @@ -33571,6 +33658,42 @@
"to": "01a0c9f6-44b8-757d-a3e5-7401751adee7",
"via": "surfaces",
"attrs": {}
},
{
"from": "01a1713f-850d-7445-bc3b-c9601a117304",
"to": "01a03d8e-dd00-7372-ac62-ba79f12bf81a",
"via": "source",
"attrs": {}
},
{
"from": "01a1713f-93a4-77e2-ae7c-46e9dfe5e912",
"to": "01a1713f-850d-7445-bc3b-c9601a117304",
"via": "kind",
"attrs": {}
},
{
"from": "01a1713f-93a4-77e2-ae7c-46e9dfe5e912",
"to": "01a0a6f1-f188-70b0-9317-126308ad1e41",
"via": "owner",
"attrs": {}
},
{
"from": "01a1713f-93a4-77e2-ae7c-46e9dfe5e912",
"to": "01a108dc-de29-78aa-9804-a6150ebfabad",
"via": "processor",
"attrs": {}
},
{
"from": "01a1713f-93a4-77e2-ae7c-46e9dfe5e912",
"to": "01a0ccd4-b070-7ae5-9228-5189a9306e5a",
"via": "serves",
"attrs": {}
},
{
"from": "01a1713f-93a4-77e2-ae7c-46e9dfe5e912",
"to": "01a03d8e-dd00-7372-ac62-ba79f12bf81a",
"via": "source",
"attrs": {}
}
],
"repo": "robertblust/mental-model"
Expand Down
Binary file modified model/og.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
2 changes: 1 addition & 1 deletion model/og.sha
Original file line number Diff line number Diff line change
@@ -1 +1 @@
ebc452621cd2a289a901344ba89207fed58c964eab21e17fe2b85984a25e5537
b2c1fd3af566aa9eb5c4ab3efcc754783bbce38eb585f48a5cca511759411b68
2 changes: 1 addition & 1 deletion principles/index.html
Original file line number Diff line number Diff line change
Expand Up @@ -337,7 +337,7 @@ <h3 data-de="Die Produktion ist das Ziel">Production is the finish line</h3>
</article>
</section>

<p class="derived" data-de="Erzeugt aus <a href='https://github.com/robertblust/mental-model'>robertblust/mental-model</a>@c259512 – <code class='mono'>model/vision.md</code> und <code class='mono'>model/values/</code>. Dieses Repository ist eine Instanz von <a href='https://companygraph.io/'>CompanyGraph</a>, einem Meta-Modell, das ein Unternehmen als Graph aus Markdown beschreibt.">Generated from <a href="https://github.com/robertblust/mental-model">robertblust/mental-model</a>@c259512 — <code class="mono">model/vision.md</code> and <code class="mono">model/values/</code>. That repository is an instance of <a href="https://companygraph.io/">CompanyGraph</a>, a meta-model for describing a company as a graph of Markdown.</p>
<p class="derived" data-de="Erzeugt aus <a href='https://github.com/robertblust/mental-model'>robertblust/mental-model</a>@7fd8db9 – <code class='mono'>model/vision.md</code> und <code class='mono'>model/values/</code>. Dieses Repository ist eine Instanz von <a href='https://companygraph.io/'>CompanyGraph</a>, einem Meta-Modell, das ein Unternehmen als Graph aus Markdown beschreibt.">Generated from <a href="https://github.com/robertblust/mental-model">robertblust/mental-model</a>@7fd8db9 — <code class="mono">model/vision.md</code> and <code class="mono">model/values/</code>. That repository is an instance of <a href="https://companygraph.io/">CompanyGraph</a>, a meta-model for describing a company as a graph of Markdown.</p>
<!-- principles:end -->
</div>
</main>
Expand Down
2 changes: 1 addition & 1 deletion principles/og.sha
Original file line number Diff line number Diff line change
@@ -1 +1 @@
e3b6dce5253245bf0f5378fc7a0df039a7c9680e51410d0b7ba5a55588a254d6
99f3376a98c9aeff81473d3b57abbdca25d6f40b6f6d9e70f224cdb19f5a28a0
2 changes: 1 addition & 1 deletion privacy/index.html
Original file line number Diff line number Diff line change
Expand Up @@ -335,7 +335,7 @@ <h2 data-de="Wohin Ihre Daten gehen">Where your data goes</h2>
<!-- privacy:start -->
<div class="lineage" id="lineage">
<svg class="wires" id="wires" aria-hidden="true"></svg>
<div class="ln-model" id="lnmodel"><div class="lbl" data-de="Auf blust.ch">On blust.ch</div><div class="nm" data-de="Ihr Besuch">Your visit</div><div class="at mono">@c259512</div></div>
<div class="ln-model" id="lnmodel"><div class="lbl" data-de="Auf blust.ch">On blust.ch</div><div class="nm" data-de="Ihr Besuch">Your visit</div><div class="at mono">@7fd8db9</div></div>
<ul class="ln-groups">
<li class="ln-group hand">
<div class="ln-maker" data-maker="local-storage"><svg class="mk hand" aria-hidden="true"><use href="#m-hand"/></svg><span class="who"><span data-de="In Ihrem Browser gespeichert">Kept in your browser</span><span class="how" data-de="bis Sie die Daten löschen · nie automatisch übermittelt">until you clear it · never sent on its own</span></span></div>
Expand Down
2 changes: 1 addition & 1 deletion privacy/og.sha
Original file line number Diff line number Diff line change
@@ -1 +1 @@
a97c64b659f599c39c237d41abcbbf99dcf5fee8b55430c30328914aa1fb06b6
60f5ce748f40a0bfed6492e636b43d053cee8ad739ca81849da5c693973c5041
2 changes: 1 addition & 1 deletion processes/og.sha
Original file line number Diff line number Diff line change
@@ -1 +1 @@
7e878999753343b538b1c1b25450aa72e7f5fbfa67af349c44c93f649e1dd301
0e179f115321f31c3c8d006f3092240f569cd9e06acc2b73c889e6134deb674c
2 changes: 1 addition & 1 deletion source.json
Original file line number Diff line number Diff line change
@@ -1 +1 @@
{"repo":"robertblust/mental-model","commit":"c259512efa40734c3fa9102ef718d0641bfcb9e7"}
{"repo":"robertblust/mental-model","commit":"7fd8db9bc43194bf8c01a6cae0498349de9340f5"}
2 changes: 1 addition & 1 deletion surfaces/index.html
Original file line number Diff line number Diff line change
Expand Up @@ -351,7 +351,7 @@ <h1 data-de="<span class='r70'>Ein Modell,</span><span class='rcl'>jede <em>Surf
<!-- surfaces:start -->
<div class="lineage" id="lineage">
<svg class="wires" id="wires" aria-hidden="true"></svg>
<div class="ln-model" id="lnmodel"><div class="lbl" data-de="Das Modell">The model</div><div class="nm">mental-model</div><div class="at mono">@c259512</div></div>
<div class="ln-model" id="lnmodel"><div class="lbl" data-de="Das Modell">The model</div><div class="nm">mental-model</div><div class="at mono">@7fd8db9</div></div>
<ul class="ln-groups">
<li class="ln-group hand">
<div class="ln-maker" data-maker="hand"><svg class="mk hand" aria-hidden="true"><use href="#m-hand"/></svg><span class="who"><span data-de="Der Owner">The owner</span><span class="how" data-de="von Hand">by hand</span></span></div>
Expand Down
2 changes: 1 addition & 1 deletion surfaces/og.sha
Original file line number Diff line number Diff line change
@@ -1 +1 @@
7d20294be3f2fc9249ff51498c79df180c6ed5170902b22687aa471a7652a8a6
a4f9d12c866c4bb50fc2b768c5e18e7d2b3185c69a93a6487a9c527028a31402
2 changes: 1 addition & 1 deletion timeline/og.sha
Original file line number Diff line number Diff line change
@@ -1 +1 @@
8caff229862ccce71e15f81bfda399075b5c6ea4f39ad8c36804f65a9a992553
5907b8dc81e82f99485669f983c520f7f0dbc546e8585ee32af04a794cae4892
Loading