Release governance: field-access data is private, never shipped
data-private/ is born: datasets whose publication could help close doors stay out of the web-root and out of public repos, permanently. field-access-visas moved there; the tables index no longer lists it; the key-cities Field Access tab is removed from the public build; the table generator routes it (and any future PRIVATE_TABLES entry) to data-private/ and excludes it from the index. Public-good data (internet gaps, gospel-resource gaps, people-group pairings) ships as before.
This commit is contained in:
parent
e1d9393227
commit
3fee91a193
8 changed files with 32 additions and 17274 deletions
|
|
@ -35,9 +35,9 @@ const TABS = [
|
|||
{ id: 'languages', label: 'By Country', file: 'languages-by-country' },
|
||||
{ id: 'operators', label: 'ISPs & Carriers', file: 'network-operators' },
|
||||
{ id: 'messaging', label: 'Messaging Apps', file: 'messaging-channels' },
|
||||
// Visa entry policy per destination x sending passport. TOURIST entry only —
|
||||
// not permission for religious work, and not a safety assessment.
|
||||
{ id: 'access', label: 'Field Access', file: 'field-access-visas' },
|
||||
// Field-access/visa data is PRIVATE (data-private/ — release governance):
|
||||
// publishing it could accelerate access closures. Tab removed from the
|
||||
// public build; the dataset stays available for internal analysis.
|
||||
]
|
||||
const active = ref('cities')
|
||||
const current = computed(() => TABS.find((t) => t.id === active.value) || TABS[0])
|
||||
|
|
|
|||
14
data-private/README.md
Normal file
14
data-private/README.md
Normal file
|
|
@ -0,0 +1,14 @@
|
|||
# data-private/ — NEVER published
|
||||
|
||||
**The law: nothing in this folder is ever copied into the web-root or any public
|
||||
repo.** It exists for internal analysis only. The build's copy steps read from
|
||||
`data/` — deliberately not from here.
|
||||
|
||||
Classification rationale (release governance): datasets whose publication could
|
||||
help close doors — e.g. field-access/visa patterns — stay here. Public-good
|
||||
datasets (internet gaps, gospel-resource gaps, people-group pairings) live in
|
||||
`data/` and ship.
|
||||
|
||||
| File | Why private |
|
||||
|---|---|
|
||||
| `tables/field-access-visas.json` | Visa/field-access patterns per destination — publication could accelerate access closures |
|
||||
|
|
@ -1,6 +1,6 @@
|
|||
{
|
||||
"generated": "2026-08-01",
|
||||
"method": "IEMV — extraction by the fetch/derive scripts, MODELING + VALIDATION here",
|
||||
"method": "IEMV \u2014 extraction by the fetch/derive scripts, MODELING + VALIDATION here",
|
||||
"tables": [
|
||||
{
|
||||
"name": "people-group-resources",
|
||||
|
|
@ -58,10 +58,6 @@
|
|||
"name": "platform-reachability",
|
||||
"rows": 2625
|
||||
},
|
||||
{
|
||||
"name": "field-access-visas",
|
||||
"rows": 1146
|
||||
},
|
||||
{
|
||||
"name": "gaps-and-opportunities",
|
||||
"rows": 2106,
|
||||
|
|
|
|||
|
|
@ -32,6 +32,8 @@ import { dirname, join, resolve } from 'node:path';
|
|||
const __dirname = dirname(fileURLToPath(import.meta.url));
|
||||
const OUT = join(__dirname, 'out');
|
||||
const TABLES = join(OUT, 'tables');
|
||||
// Tables that must NEVER ship publicly (see data-private/README.md).
|
||||
const PRIVATE_TABLES = new Set(['field-access-visas']);
|
||||
const PROFILES = resolve(__dirname, '..', '..', '..', 'app-profiles');
|
||||
|
||||
const read = (f) => JSON.parse(readFileSync(join(OUT, f), 'utf8'));
|
||||
|
|
@ -64,6 +66,15 @@ function emit(name, rows, columns, meta, assert) {
|
|||
}
|
||||
}
|
||||
if (assert) assert(rows);
|
||||
// RELEASE GOVERNANCE: tables in PRIVATE_TABLES are written to data-private/
|
||||
// (never copied to the web-root, never indexed) — see data-private/README.md.
|
||||
if (PRIVATE_TABLES.has(name)) {
|
||||
const priv = join(TABLES, '..', '..', 'data-private', 'tables');
|
||||
if (!existsSync(priv)) mkdirSync(priv, { recursive: true });
|
||||
writeFileSync(join(priv, `${name}.json`), JSON.stringify({ meta, columns, rows }, null, 1));
|
||||
console.log(`[tables] ${name.padEnd(26)} ${String(rows.length).padStart(5)} rows PRIVATE → data-private/`);
|
||||
return { name, rows: rows.length, private: true };
|
||||
}
|
||||
if (!existsSync(TABLES)) mkdirSync(TABLES, { recursive: true });
|
||||
writeFileSync(join(TABLES, `${name}.json`), JSON.stringify({ meta, columns, rows }, null, 1));
|
||||
console.log(`[tables] ${name.padEnd(26)} ${String(rows.length).padStart(5)} rows ${columns.length} cols`);
|
||||
|
|
@ -1330,7 +1341,7 @@ for (const name of EXTERNAL) {
|
|||
writeFileSync(join(TABLES, 'index.json'), JSON.stringify({
|
||||
generated: '2026-08-01',
|
||||
method: 'IEMV — extraction by the fetch/derive scripts, MODELING + VALIDATION here',
|
||||
tables: built,
|
||||
tables: built.filter((b) => !b.private),
|
||||
}, null, 1));
|
||||
|
||||
console.log(`\n[tables] ${built.length} tables, ${built.reduce((n, b) => n + b.rows, 0)} rows total`);
|
||||
|
|
|
|||
17259
public/assets/tables/field-access-visas.json
vendored
17259
public/assets/tables/field-access-visas.json
vendored
File diff suppressed because it is too large
Load diff
6
public/assets/tables/index.json
vendored
6
public/assets/tables/index.json
vendored
|
|
@ -1,6 +1,6 @@
|
|||
{
|
||||
"generated": "2026-08-01",
|
||||
"method": "IEMV — extraction by the fetch/derive scripts, MODELING + VALIDATION here",
|
||||
"method": "IEMV \u2014 extraction by the fetch/derive scripts, MODELING + VALIDATION here",
|
||||
"tables": [
|
||||
{
|
||||
"name": "people-group-resources",
|
||||
|
|
@ -58,10 +58,6 @@
|
|||
"name": "platform-reachability",
|
||||
"rows": 2625
|
||||
},
|
||||
{
|
||||
"name": "field-access-visas",
|
||||
"rows": 1146
|
||||
},
|
||||
{
|
||||
"name": "gaps-and-opportunities",
|
||||
"rows": 2106,
|
||||
|
|
|
|||
2
public/doxa-maps/key-cities/key-cities.js
generated
2
public/doxa-maps/key-cities/key-cities.js
generated
File diff suppressed because one or more lines are too long
Loading…
Reference in a new issue