From 76e3e6c0f2e38dc83dc413511b9e3955120183ab Mon Sep 17 00:00:00 2001 From: CLU Date: Thu, 29 Oct 2026 15:23:31 -0500 Subject: [PATCH] feat: the closed-source rule, and the board Christian, 2026-10-29: 'Closed source software, you have no idea. And then all we have is reputation. So you kind of start with one arm or two arms tied behind your back.' That is now arithmetic instead of an opinion. - assessment.source_available: 1 = we can read the code, 0 = we cannot. - Closed source cannot exceed 5 on ANY dimension without tier-1 or tier-2 evidence of kind 'capture' or 'filing'. Reputation is tier 3, and tier 3 is not a measurement. The build fails if a closed-source score breaks the rule. - Verifiability still caps at 3 with no reproducible build. Practical ceiling for closed source: 86/100 in theory, if every dimension is backed by a capture or a court filing. In practice it is a fight for a C. - product.priority puts a human's ask ahead of a crawler's discovery. - v_backlog orders by priority, then measured usage. - migrate(): the database authors itself, so it must survive its own schema changes. Add columns, drop views, let schema.sql recreate them. Never drop and rebuild, which would destroy the self-authored roster. On the board: Slack (closed, capped) and Kino (closed, capped, founders call 2026-10-30 17:00). Neither is scored. Neither gets a number until it has evidence. --- packages/core/db/build.mjs | 36 +++++++++++++++ packages/core/db/schema.sql | 16 +++++-- packages/core/db/seed/0002-board.sql | 28 +++++++++++ packages/core/src/data/generated/catalog.json | 46 ++++++++++++++----- packages/core/src/data/generated/catalog.ts | 46 ++++++++++++++----- packages/web/public/catalog.json | 46 ++++++++++++++----- packages/web/public/oath.json | 8 ++-- 7 files changed, 182 insertions(+), 44 deletions(-) create mode 100644 packages/core/db/seed/0002-board.sql diff --git a/packages/core/db/build.mjs b/packages/core/db/build.mjs index 4bcc10d..8fa4ba3 100644 --- a/packages/core/db/build.mjs +++ b/packages/core/db/build.mjs @@ -57,6 +57,7 @@ const VENDORS = { netflix: ['Netflix, Inc.', 'public', 'US', 'subscription'], 'nextcloud-gmbh': ['Nextcloud GmbH', 'private', 'DE', 'subscription'], 'signal-foundation': ['Signal Technology Foundation', 'nonprofit', 'US', 'none'], + 'kino-ai': ['Kino AI', 'private', 'US', 'subscription'], // discovered products land here until a human or agent resolves the owner unknown: ['Unknown vendor', 'unknown', 'unknown', 'unknown'], }; @@ -90,6 +91,10 @@ async function build({ fresh = false } = {}) { const db = new DatabaseSync(DB_PATH); db.exec('PRAGMA foreign_keys = ON'); db.exec(readFileSync(join(HERE, 'schema.sql'), 'utf8')); + migrate(db); + // second pass: migrate drops the views so this recreates them with the current + // definitions. Views cannot be altered, only replaced. + db.exec(readFileSync(join(HERE, 'schema.sql'), 'utf8')); // vendors const insVendor = db.prepare(`INSERT OR REPLACE INTO vendor @@ -127,6 +132,23 @@ async function build({ fresh = false } = {}) { return { migrated, seeds }; } +// ---------------------------------------------------------------- migrate +// The database authors itself, so it must survive its own schema changes. +// Never drop and rebuild: add the column, drop the views, let schema.sql recreate. +function migrate(db) { + const cols = (t) => db.prepare(`PRAGMA table_info(${t})`).all().map((c) => c.name); + + if (!cols('product').includes('priority')) { + db.exec('ALTER TABLE product ADD COLUMN priority INTEGER NOT NULL DEFAULT 0'); + } + if (!cols('assessment').includes('source_available')) { + db.exec('ALTER TABLE assessment ADD COLUMN source_available INTEGER NOT NULL DEFAULT 1'); + } + for (const v of ['v_backlog', 'v_coverage', 'v_product_score']) { + db.exec(`DROP VIEW IF EXISTS ${v}`); + } +} + // ---------------------------------------------------------------- verify function verify() { const db = new DatabaseSync(DB_PATH, { readOnly: true }); @@ -167,6 +189,20 @@ function verify() { const v = db.prepare("SELECT value FROM score WHERE assessment_id = ? AND dimension_id = 'verifiability'").get(a.id)?.value; if (a.reproducible_build === 0) ok(v <= 3, `${a.id}: no reproducible build but verifiability ${v} > 3`); if (a.reproducible_build === 1) ok(v <= 6, `${a.id}: experimental reproducible build but verifiability ${v} > 6`); + + // Closed source cannot exceed 5 on anything without independent evidence. + // Reputation is tier 3. Tier 3 is not a measurement. + if (a.source_available === 0) { + const above = db.prepare('SELECT * FROM score WHERE assessment_id = ? AND value > 5').all(a.id); + for (const s of above) { + const independent = db.prepare(` + SELECT COUNT(*) AS n FROM evidence + WHERE assessment_id = ? AND dimension_id = ? + AND tier <= 2 AND kind IN ('capture','filing')`).get(a.id, s.dimension_id).n; + ok(independent > 0, + `${a.id}/${s.dimension_id}: closed source scored ${s.value} > 5 with no capture or court filing to back it`); + } + } } const scores = db.prepare('SELECT * FROM v_product_score').all(); diff --git a/packages/core/db/schema.sql b/packages/core/db/schema.sql index 6de60db..f940228 100644 --- a/packages/core/db/schema.sql +++ b/packages/core/db/schema.sql @@ -43,6 +43,8 @@ CREATE TABLE IF NOT EXISTS product ( boss INTEGER NOT NULL DEFAULT 0 CHECK (boss IN (0,1)), art_slot TEXT, monthly_cost REAL, + -- priority > 0 puts a product on the board even before anything discovers it + priority INTEGER NOT NULL DEFAULT 0, notes TEXT, UNIQUE(id, platform) ); @@ -65,6 +67,9 @@ CREATE TABLE IF NOT EXISTS assessment ( method_version TEXT NOT NULL, -- 0 = none, 1 = available but experimental/unverified, 2 = verified reproducible_build INTEGER NOT NULL DEFAULT 0 CHECK (reproducible_build IN (0,1,2)), + -- 1 = we can read the code. 0 = closed. Closed source cannot exceed 5 on any + -- dimension unless independent evidence (a capture or a court filing) says so. + source_available INTEGER NOT NULL DEFAULT 1 CHECK (source_available IN (0,1)), weighted_total REAL NOT NULL CHECK (weighted_total BETWEEN 0 AND 100), grade TEXT NOT NULL, weakest_dimension TEXT NOT NULL REFERENCES dimension(id), @@ -180,17 +185,20 @@ FROM product p LEFT JOIN assessment a ON a.product_id = p.id AND a.assessed_on = (SELECT MAX(assessed_on) FROM assessment WHERE product_id = p.id); --- What to assess next, ordered by how much the thing is actually used. +-- What to assess next. Anything a human put on the board outranks anything a +-- crawler found, and within each tier usage decides. CREATE VIEW IF NOT EXISTS v_backlog AS SELECT p.id AS product_id, p.name, p.platform, p.category_id, - MAX(d.usage_signal) AS usage, + p.priority AS priority, + COALESCE(MAX(d.usage_signal), 0) AS usage, GROUP_CONCAT(DISTINCT d.source) AS found_via FROM product p -JOIN discovery d ON d.product_id = p.id +LEFT JOIN discovery d ON d.product_id = p.id WHERE NOT EXISTS (SELECT 1 FROM assessment a WHERE a.product_id = p.id) + AND (d.id IS NOT NULL OR p.priority > 0) GROUP BY p.id -ORDER BY usage DESC; +ORDER BY p.priority DESC, usage DESC; diff --git a/packages/core/db/seed/0002-board.sql b/packages/core/db/seed/0002-board.sql new file mode 100644 index 0000000..28cbfef --- /dev/null +++ b/packages/core/db/seed/0002-board.sql @@ -0,0 +1,28 @@ +-- ===================================================================== +-- 0002 — the board, 2026-10-29 +-- Products a human put on the queue. priority > 0 outranks anything a crawler found. +-- +-- Neither of these has an assessment yet, and neither gets a number until it +-- has evidence. Slack is closed source, so when it is assessed it will be capped +-- at 5 on every dimension that has no capture or filing behind it. +-- ===================================================================== + +UPDATE product + SET priority = 10, + notes = 'Queued 2026-10-29 by Christian for the Big Tech Report. Closed source, so verifiability caps at 3 and no dimension may exceed 5 without independent capture or court filing. Score is reputation, not measurement.' + WHERE id = 'slack'; + +INSERT OR IGNORE INTO product + (id, vendor_id, name, category_id, platform, source_url, license, + sovereign, boss, art_slot, monthly_cost, priority, notes) +VALUES + ('kino-ai', 'kino-ai', 'Kino', 'video', 'web', 'https://kino.ai', NULL, + 0, 0, NULL, NULL, 10, + 'Queued 2026-10-29. YC S23, four people, browser-native editor and AI media manager. Christian signed up same day and asked founders for WebDAV / Nextcloud compatibility. Closed source.'); + +INSERT OR IGNORE INTO discovery + (product_id, source, source_url, usage_signal, usage_metric, observed_at, raw) +VALUES + ('kino-ai', 'manual', 'https://www.ycombinator.com/companies/kino-ai', NULL, 'queued_by_operator', + '2026-10-29T15:22:00-05:00', + '{"batch":"S23","founders":["Wesley Block","Luke Igel"],"note":"formerly local-first desktop logging tool; now browser-native editor"}'); diff --git a/packages/core/src/data/generated/catalog.json b/packages/core/src/data/generated/catalog.json index 9a22e46..3945b6c 100644 --- a/packages/core/src/data/generated/catalog.json +++ b/packages/core/src/data/generated/catalog.json @@ -1,5 +1,5 @@ { - "generated_at": "2026-10-29T18:23:54.071Z", + "generated_at": "2026-10-29T20:23:11.576Z", "method_version": "btr-0.1", "dimensions": [ { @@ -2634,6 +2634,28 @@ "headline": null, "assessed_on": null }, + { + "id": "kino-ai", + "name": "Kino", + "platform": "web", + "category_id": "video", + "vendor_id": "kino-ai", + "sovereign": 0, + "boss": 0, + "art_slot": null, + "monthly_cost": null, + "vendor": "Kino AI", + "entity_type": "private", + "jurisdiction": "US", + "business_model": "subscription", + "weighted_total": null, + "grade": null, + "policy": null, + "infra": null, + "weakest_dimension": null, + "headline": null, + "assessed_on": null + }, { "id": "teams", "name": "Microsoft Teams", @@ -2829,7 +2851,7 @@ ], "evidence": [ { - "id": 8, + "id": 15, "assessment_id": "A-2026-10-29-SIGNAL-DESKTOP", "dimension_id": "local_data_exposure", "claim": "Attachments are stored unencrypted on the filesystem; the SQLCipher key is held by the OS keyring.", @@ -2840,7 +2862,7 @@ "observed_at": "2026-10-29T13:13:56-05:00" }, { - "id": 9, + "id": 16, "assessment_id": "A-2026-10-29-SIGNAL-DESKTOP", "dimension_id": "telemetry_egress", "claim": "Electron media permission defaults to false and audio is denied unless the user has enabled mediaPermissions.", @@ -2851,7 +2873,7 @@ "observed_at": "2026-10-29T13:13:56-05:00" }, { - "id": 10, + "id": 17, "assessment_id": "A-2026-10-29-SIGNAL-DESKTOP", "dimension_id": "telemetry_egress", "claim": "Zero analytics, tracker or crash-upload dependencies across 224 packages.", @@ -2862,7 +2884,7 @@ "observed_at": "2026-10-29T13:13:56-05:00" }, { - "id": 11, + "id": 18, "assessment_id": "A-2026-10-29-SIGNAL-DESKTOP", "dimension_id": "telemetry_egress", "claim": "Only two audio capture call sites exist and both are reachable only from an explicit UI action.", @@ -2873,7 +2895,7 @@ "observed_at": "2026-10-29T13:13:56-05:00" }, { - "id": 12, + "id": 19, "assessment_id": "A-2026-10-29-SIGNAL-DESKTOP", "dimension_id": "verifiability", "claim": "Signal states reproducible builds for macOS and Windows are not available, and the Linux build is experimental.", @@ -2884,7 +2906,7 @@ "observed_at": "2026-10-29T13:13:56-05:00" }, { - "id": 13, + "id": 20, "assessment_id": "A-2026-10-29-SIGNAL-DESKTOP", "dimension_id": "server_retention", "claim": "Grand jury subpoena response returned two timestamps and nothing else.", @@ -2895,7 +2917,7 @@ "observed_at": "2026-10-29T13:13:56-05:00" }, { - "id": 14, + "id": 21, "assessment_id": "A-2026-10-29-SIGNAL-DESKTOP", "dimension_id": "ownership_jurisdiction", "claim": "Signal Technology Foundation is a 501(c)(3) with EIN 82-4506840.", @@ -2908,7 +2930,7 @@ ], "findings": [ { - "id": 5, + "id": 9, "assessment_id": "A-2026-10-29-SIGNAL-DESKTOP", "severity": "high", "title": "Received attachments are stored unencrypted on disk", @@ -2917,7 +2939,7 @@ "cve": "CVE-2023-24069" }, { - "id": 6, + "id": 10, "assessment_id": "A-2026-10-29-SIGNAL-DESKTOP", "severity": "medium", "title": "No verified reproducible build for the Linux package", @@ -2926,7 +2948,7 @@ "cve": null }, { - "id": 7, + "id": 11, "assessment_id": "A-2026-10-29-SIGNAL-DESKTOP", "severity": "medium", "title": "Local database key is held in the OS keyring", @@ -2935,7 +2957,7 @@ "cve": null }, { - "id": 8, + "id": 12, "assessment_id": "A-2026-10-29-SIGNAL-DESKTOP", "severity": "low", "title": "Registration requires a phone number", diff --git a/packages/core/src/data/generated/catalog.ts b/packages/core/src/data/generated/catalog.ts index d70aa23..1b3ca15 100644 --- a/packages/core/src/data/generated/catalog.ts +++ b/packages/core/src/data/generated/catalog.ts @@ -39,7 +39,7 @@ export interface CatalogDimension { } export const catalog = { - "generated_at": "2026-10-29T18:23:54.071Z", + "generated_at": "2026-10-29T20:23:11.576Z", "method_version": "btr-0.1", "dimensions": [ { @@ -2674,6 +2674,28 @@ export const catalog = { "headline": null, "assessed_on": null }, + { + "id": "kino-ai", + "name": "Kino", + "platform": "web", + "category_id": "video", + "vendor_id": "kino-ai", + "sovereign": 0, + "boss": 0, + "art_slot": null, + "monthly_cost": null, + "vendor": "Kino AI", + "entity_type": "private", + "jurisdiction": "US", + "business_model": "subscription", + "weighted_total": null, + "grade": null, + "policy": null, + "infra": null, + "weakest_dimension": null, + "headline": null, + "assessed_on": null + }, { "id": "teams", "name": "Microsoft Teams", @@ -2869,7 +2891,7 @@ export const catalog = { ], "evidence": [ { - "id": 8, + "id": 15, "assessment_id": "A-2026-10-29-SIGNAL-DESKTOP", "dimension_id": "local_data_exposure", "claim": "Attachments are stored unencrypted on the filesystem; the SQLCipher key is held by the OS keyring.", @@ -2880,7 +2902,7 @@ export const catalog = { "observed_at": "2026-10-29T13:13:56-05:00" }, { - "id": 9, + "id": 16, "assessment_id": "A-2026-10-29-SIGNAL-DESKTOP", "dimension_id": "telemetry_egress", "claim": "Electron media permission defaults to false and audio is denied unless the user has enabled mediaPermissions.", @@ -2891,7 +2913,7 @@ export const catalog = { "observed_at": "2026-10-29T13:13:56-05:00" }, { - "id": 10, + "id": 17, "assessment_id": "A-2026-10-29-SIGNAL-DESKTOP", "dimension_id": "telemetry_egress", "claim": "Zero analytics, tracker or crash-upload dependencies across 224 packages.", @@ -2902,7 +2924,7 @@ export const catalog = { "observed_at": "2026-10-29T13:13:56-05:00" }, { - "id": 11, + "id": 18, "assessment_id": "A-2026-10-29-SIGNAL-DESKTOP", "dimension_id": "telemetry_egress", "claim": "Only two audio capture call sites exist and both are reachable only from an explicit UI action.", @@ -2913,7 +2935,7 @@ export const catalog = { "observed_at": "2026-10-29T13:13:56-05:00" }, { - "id": 12, + "id": 19, "assessment_id": "A-2026-10-29-SIGNAL-DESKTOP", "dimension_id": "verifiability", "claim": "Signal states reproducible builds for macOS and Windows are not available, and the Linux build is experimental.", @@ -2924,7 +2946,7 @@ export const catalog = { "observed_at": "2026-10-29T13:13:56-05:00" }, { - "id": 13, + "id": 20, "assessment_id": "A-2026-10-29-SIGNAL-DESKTOP", "dimension_id": "server_retention", "claim": "Grand jury subpoena response returned two timestamps and nothing else.", @@ -2935,7 +2957,7 @@ export const catalog = { "observed_at": "2026-10-29T13:13:56-05:00" }, { - "id": 14, + "id": 21, "assessment_id": "A-2026-10-29-SIGNAL-DESKTOP", "dimension_id": "ownership_jurisdiction", "claim": "Signal Technology Foundation is a 501(c)(3) with EIN 82-4506840.", @@ -2948,7 +2970,7 @@ export const catalog = { ], "findings": [ { - "id": 5, + "id": 9, "assessment_id": "A-2026-10-29-SIGNAL-DESKTOP", "severity": "high", "title": "Received attachments are stored unencrypted on disk", @@ -2957,7 +2979,7 @@ export const catalog = { "cve": "CVE-2023-24069" }, { - "id": 6, + "id": 10, "assessment_id": "A-2026-10-29-SIGNAL-DESKTOP", "severity": "medium", "title": "No verified reproducible build for the Linux package", @@ -2966,7 +2988,7 @@ export const catalog = { "cve": null }, { - "id": 7, + "id": 11, "assessment_id": "A-2026-10-29-SIGNAL-DESKTOP", "severity": "medium", "title": "Local database key is held in the OS keyring", @@ -2975,7 +2997,7 @@ export const catalog = { "cve": null }, { - "id": 8, + "id": 12, "assessment_id": "A-2026-10-29-SIGNAL-DESKTOP", "severity": "low", "title": "Registration requires a phone number", diff --git a/packages/web/public/catalog.json b/packages/web/public/catalog.json index 9a22e46..3945b6c 100644 --- a/packages/web/public/catalog.json +++ b/packages/web/public/catalog.json @@ -1,5 +1,5 @@ { - "generated_at": "2026-10-29T18:23:54.071Z", + "generated_at": "2026-10-29T20:23:11.576Z", "method_version": "btr-0.1", "dimensions": [ { @@ -2634,6 +2634,28 @@ "headline": null, "assessed_on": null }, + { + "id": "kino-ai", + "name": "Kino", + "platform": "web", + "category_id": "video", + "vendor_id": "kino-ai", + "sovereign": 0, + "boss": 0, + "art_slot": null, + "monthly_cost": null, + "vendor": "Kino AI", + "entity_type": "private", + "jurisdiction": "US", + "business_model": "subscription", + "weighted_total": null, + "grade": null, + "policy": null, + "infra": null, + "weakest_dimension": null, + "headline": null, + "assessed_on": null + }, { "id": "teams", "name": "Microsoft Teams", @@ -2829,7 +2851,7 @@ ], "evidence": [ { - "id": 8, + "id": 15, "assessment_id": "A-2026-10-29-SIGNAL-DESKTOP", "dimension_id": "local_data_exposure", "claim": "Attachments are stored unencrypted on the filesystem; the SQLCipher key is held by the OS keyring.", @@ -2840,7 +2862,7 @@ "observed_at": "2026-10-29T13:13:56-05:00" }, { - "id": 9, + "id": 16, "assessment_id": "A-2026-10-29-SIGNAL-DESKTOP", "dimension_id": "telemetry_egress", "claim": "Electron media permission defaults to false and audio is denied unless the user has enabled mediaPermissions.", @@ -2851,7 +2873,7 @@ "observed_at": "2026-10-29T13:13:56-05:00" }, { - "id": 10, + "id": 17, "assessment_id": "A-2026-10-29-SIGNAL-DESKTOP", "dimension_id": "telemetry_egress", "claim": "Zero analytics, tracker or crash-upload dependencies across 224 packages.", @@ -2862,7 +2884,7 @@ "observed_at": "2026-10-29T13:13:56-05:00" }, { - "id": 11, + "id": 18, "assessment_id": "A-2026-10-29-SIGNAL-DESKTOP", "dimension_id": "telemetry_egress", "claim": "Only two audio capture call sites exist and both are reachable only from an explicit UI action.", @@ -2873,7 +2895,7 @@ "observed_at": "2026-10-29T13:13:56-05:00" }, { - "id": 12, + "id": 19, "assessment_id": "A-2026-10-29-SIGNAL-DESKTOP", "dimension_id": "verifiability", "claim": "Signal states reproducible builds for macOS and Windows are not available, and the Linux build is experimental.", @@ -2884,7 +2906,7 @@ "observed_at": "2026-10-29T13:13:56-05:00" }, { - "id": 13, + "id": 20, "assessment_id": "A-2026-10-29-SIGNAL-DESKTOP", "dimension_id": "server_retention", "claim": "Grand jury subpoena response returned two timestamps and nothing else.", @@ -2895,7 +2917,7 @@ "observed_at": "2026-10-29T13:13:56-05:00" }, { - "id": 14, + "id": 21, "assessment_id": "A-2026-10-29-SIGNAL-DESKTOP", "dimension_id": "ownership_jurisdiction", "claim": "Signal Technology Foundation is a 501(c)(3) with EIN 82-4506840.", @@ -2908,7 +2930,7 @@ ], "findings": [ { - "id": 5, + "id": 9, "assessment_id": "A-2026-10-29-SIGNAL-DESKTOP", "severity": "high", "title": "Received attachments are stored unencrypted on disk", @@ -2917,7 +2939,7 @@ "cve": "CVE-2023-24069" }, { - "id": 6, + "id": 10, "assessment_id": "A-2026-10-29-SIGNAL-DESKTOP", "severity": "medium", "title": "No verified reproducible build for the Linux package", @@ -2926,7 +2948,7 @@ "cve": null }, { - "id": 7, + "id": 11, "assessment_id": "A-2026-10-29-SIGNAL-DESKTOP", "severity": "medium", "title": "Local database key is held in the OS keyring", @@ -2935,7 +2957,7 @@ "cve": null }, { - "id": 8, + "id": 12, "assessment_id": "A-2026-10-29-SIGNAL-DESKTOP", "severity": "low", "title": "Registration requires a phone number", diff --git a/packages/web/public/oath.json b/packages/web/public/oath.json index 57f241b..3e6856b 100644 --- a/packages/web/public/oath.json +++ b/packages/web/public/oath.json @@ -1,10 +1,10 @@ { - "digest": "5aadd709b394ab19e13a65aa21fb5182cb736f53e2b60c175abebb8dd11f1d8a", + "digest": "37a9774dc7569335d8135828aa5b97d294e26252185b0b31dc4a8f4dadde59db", "algorithm": "sha256", "file": "catalog.json", - "byte_length": 79846, - "rebuilt_at": "2026-10-29T18:23:54.074Z", + "byte_length": 80389, + "rebuilt_at": "2026-10-29T20:23:11.578Z", "method_version": "btr-0.1", - "products": 122, + "products": 123, "assessed": 1 } \ No newline at end of file