Scope the Door43 Scripture, and stop 70 story sets being typed as Scripture
Door43 entries carry their own book list. Each ingredient is categorised bible-ot or bible-nt, so a Door43 Scripture entry can say how much Scripture it is, exactly as an eBible one does — and it is already in the response we fetch, so this costs no extra requests. 35 entries scoped: 15 New Testament, 13 Portions, 4 Full Bible, 3 Portions of both Testaments. THE SUBJECT LABEL IS NOT THE SCOPE, which is why it is counted from the data. An entry filed under "Bible" can be 27 NT books and nothing else. Calling that a Bible because of its folder name is the same error as calling Open Bible Stories Scripture. ★ AND THAT ERROR WAS ALREADY SHIPPING, 70 ROWS OF IT, BY MY OWN HAND. Tick 15 added owner disambiguation so two same-named entries could be told apart — "Open Bible Stories (OBS-TLF)". The type test was `d.s === 'Open Bible Stories'`, an exact match, so every disambiguated label fell through to Scripture. 70 story sets have been typed as Scripture for seven ticks: Bhojpuri, Maithili and 68 more told a reader they had a translation when they have 50 illustrated narratives. Found only because the type counts moved when this tick changed the test to a prefix. An exact match against a label that can grow a suffix is the whole defect, and the fix is not enough on its own — so clause H now asserts that nothing named "Open Bible Stories" is typed as Scripture, poisoned with the rest. 8/8 clauses fail on demand. The Door43 chip in the sheet had the same exact-match and now reads "Bible Stories (OBS-TLF) · Door43 · <scope>". The one `===` left in the fetcher is correct and was checked rather than blanket-replaced: it compares the RAW subject from the API, which never carries an owner suffix. Every Scripture row on the map now has a scope. The 2,278 blanks reconcile exactly to 2,087 film plus 191 Bible Stories — none of which is a portion of the canon. Verified: gate passes, its self-test fails 8/8 on demand, and the Door43, pins, table, scope and deep-link probes all pass.
This commit is contained in:
parent
91dc9e6b33
commit
25405d571a
23 changed files with 1493 additions and 708 deletions
File diff suppressed because it is too large
Load diff
File diff suppressed because one or more lines are too long
|
|
@ -68,7 +68,7 @@
|
|||
},
|
||||
{
|
||||
"name": "gospel-resource-links",
|
||||
"rows": 3548
|
||||
"rows": 3550
|
||||
}
|
||||
]
|
||||
}
|
||||
File diff suppressed because one or more lines are too long
|
|
@ -23,6 +23,12 @@
|
|||
* E. every resource_url in the table exists in the pin index, so the table cannot
|
||||
* invent a link the map does not hold;
|
||||
* F. each pin's tier agrees with the URLs its code actually carries;
|
||||
* H. nothing named "Open Bible Stories" is TYPED as Scripture. OBS is 50 illustrated
|
||||
* narratives drawn from the canon, not a translation, and this repo's standing rule
|
||||
* is that the two are never blurred. It broke silently: owner disambiguation changed
|
||||
* the label to "Open Bible Stories (OBS-TLF)" and the type test was an exact ===
|
||||
* match, so 70 story sets were typed Scripture and stayed that way for seven ticks.
|
||||
* An exact match against a label that can grow a suffix is the whole defect.
|
||||
* G. no URL is plain http. Every host we ship serves https directly and redirects
|
||||
* http there anyway, so a plain link only buys a redirect hop and a downgraded
|
||||
* scheme in a field worker's browser. 1,237 of them shipped that way until the
|
||||
|
|
@ -68,6 +74,7 @@ if (POISON) {
|
|||
codes.und = { l: 'Undetermined', d: [{ s: 'Open Bible Stories', u: 'https://example.invalid/und' }] } // A
|
||||
codes.zzq = { l: '', s: 'http://ebible.org/zzq/' } // B + G
|
||||
trows = [{ ...trows[0], people_groups: (trows[0].people_groups || 0) + 999 }, // C
|
||||
{ ...trows[0], resource: 'Open Bible Stories (X)', type: 'Scripture' }, // H
|
||||
...trows.slice(1, -1),
|
||||
{ ...trows[trows.length - 1], resource_url: 'https://example.invalid/invented' }] // E
|
||||
rows = [[...rows[0].slice(0, 6), 2], ...rows.slice(1)] // F (forced tier 2)
|
||||
|
|
@ -107,6 +114,10 @@ for (const v of Object.values(codes)) {
|
|||
}
|
||||
const invented = trows.filter((t) => t.resource_url && !known.has(t.resource_url))
|
||||
if (invented.length) add('E', `${invented.length} table URL(s) exist in no pin record (e.g. ${invented[0].resource_url})`)
|
||||
// H — a story set must never be typed as Scripture
|
||||
const misTyped = trows.filter((t) => /open bible stories/i.test(t.resource || '') && /^scripture$/i.test(t.type || ''))
|
||||
if (misTyped.length) add('H', `${misTyped.length} row(s) named "Open Bible Stories" are typed as Scripture (e.g. ${misTyped[0].language})`)
|
||||
|
||||
// G — no plain-http URL
|
||||
const httpUrls = []
|
||||
for (const [c, v] of Object.entries(codes)) {
|
||||
|
|
@ -131,7 +142,7 @@ if (POISON) {
|
|||
// resources dropped from a table titled "every link", and the most valuable clause is
|
||||
// the worst one to leave unproven. The injected codes above (und, zzq) are absent from
|
||||
// the table, so they poison D as well as A and B.
|
||||
const want = ['A', 'B', 'C', 'D', 'E', 'F', 'G']
|
||||
const want = ['A', 'B', 'C', 'D', 'E', 'F', 'G', 'H']
|
||||
const caught = want.filter((c) => clauses.has(c))
|
||||
console.log(`COVERAGE-CONSISTENT --poison: ${caught.length}/${want.length} clause(s) caught their injected defect (${caught.join(',')})`)
|
||||
if (caught.length !== want.length) {
|
||||
|
|
|
|||
|
|
@ -828,7 +828,7 @@ useShadowStyles(
|
|||
<a v-for="d in selectedGroup.door43" :key="d.u" class="gm-chip ok"
|
||||
:href="d.u" target="_blank" rel="noopener noreferrer"
|
||||
:title="d.s + ' — published on Door43 (unfoldingWord), open licence'">
|
||||
{{ d.s === 'Open Bible Stories' ? 'Bible Stories' : d.s }} · Door43
|
||||
{{ /^Open Bible Stories/.test(d.s) ? d.s.replace('Open Bible Stories', 'Bible Stories') : d.s }} · Door43<template v-if="d.sc"> · {{ d.sc }}</template>
|
||||
</a>
|
||||
<span v-if="!selectedGroup.door43.length" class="gm-chip meh">
|
||||
Open Bible Stories · none found
|
||||
|
|
|
|||
|
|
@ -53,6 +53,9 @@ function labelD43(items) {
|
|||
return items.map((i) => ({
|
||||
s: bySubject[i.subject].length > 1 && i.owner ? `${i.subject} (${i.owner})` : i.subject,
|
||||
u: httpsify(i.url),
|
||||
// How much Scripture, counted from the entry's own book list. Open Bible Stories
|
||||
// carries none by design — it is 50 narratives, not a portion of the canon.
|
||||
...(i.scope ? { sc: i.scope } : {}),
|
||||
}))
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -91,7 +91,9 @@ for (const [code, c] of Object.entries(codes)) {
|
|||
for (const d of c.d || []) {
|
||||
// "Open Bible Stories" stays labelled as STORIES. It is 50 illustrated narratives
|
||||
// drawn from the canon, not a translation, and the type column must not blur that.
|
||||
add(d.s, d.s === 'Open Bible Stories' ? 'Bible Stories' : 'Scripture', d.u)
|
||||
// A Door43 entry filed under "Bible" can be 27 NT books; its scope comes from the
|
||||
// book list, not the subject label.
|
||||
add(d.s, /^Open Bible Stories/.test(d.s) ? 'Bible Stories' : 'Scripture', d.u, d.sc || '')
|
||||
}
|
||||
}
|
||||
// biggest reach first — the link that serves the most people is the one to open.
|
||||
|
|
|
|||
|
|
@ -43,6 +43,28 @@ const API = 'https://git.door43.org/api/v1/catalog/search'
|
|||
const isSpecialCode = (c) => c === 'und' || c === 'mul' || c === 'mis' || c === 'zxx' ||
|
||||
(c >= 'qaa' && c <= 'qtz')
|
||||
|
||||
// SCOPE FROM THE INGREDIENTS. Each catalogue entry lists its books with a category —
|
||||
// bible-ot or bible-nt — so a Door43 Scripture entry can say how much Scripture it is,
|
||||
// the same as an eBible one. It matters because the SUBJECT does not: an entry filed
|
||||
// under "Bible" can be 27 NT books and nothing else, which is a New Testament, and
|
||||
// calling it a Bible because of its folder name would be the same error as calling Open
|
||||
// Bible Stories Scripture. Counted from the data, never from the label.
|
||||
// 39 OT + 27 NT = the 66-book canon.
|
||||
function d43Scope(ingredients) {
|
||||
if (!Array.isArray(ingredients) || !ingredients.length) return ''
|
||||
let ot = 0, nt = 0
|
||||
for (const i of ingredients) {
|
||||
const cats = Array.isArray(i?.categories) ? i.categories : []
|
||||
if (cats.includes('bible-ot')) ot++
|
||||
else if (cats.includes('bible-nt')) nt++
|
||||
}
|
||||
if (ot === 0 && nt === 0) return ''
|
||||
if (ot >= 39 && nt >= 27) return 'Full Bible'
|
||||
if (nt && !ot) return nt >= 27 ? 'New Testament' : 'Portions'
|
||||
if (ot && !nt) return ot >= 39 ? 'Old Testament' : 'Portions'
|
||||
return 'Portions of both Testaments'
|
||||
}
|
||||
|
||||
const index = {}
|
||||
const sources = []
|
||||
for (const subject of SUBJECTS) {
|
||||
|
|
@ -61,7 +83,10 @@ for (const subject of SUBJECTS) {
|
|||
// The owner disambiguates: 40 languages carry more than one entry with the SAME
|
||||
// subject, which rendered as "Open Bible Stories Open Bible Stories" — two links a
|
||||
// reader cannot tell apart. Different owners are different translation efforts.
|
||||
cur.items.push({ subject, url: href, name: r.title || subject, owner: r.owner || '' })
|
||||
cur.items.push({
|
||||
subject, url: href, name: r.title || subject, owner: r.owner || '',
|
||||
scope: subject === 'Open Bible Stories' ? '' : d43Scope(r.ingredients),
|
||||
})
|
||||
}
|
||||
}
|
||||
console.log(`${subject}: ${data.length} entries`)
|
||||
|
|
|
|||
698
public/assets/tables/door43-index.json
vendored
698
public/assets/tables/door43-index.json
vendored
File diff suppressed because it is too large
Load diff
File diff suppressed because one or more lines are too long
2
public/assets/tables/index.json
vendored
2
public/assets/tables/index.json
vendored
|
|
@ -68,7 +68,7 @@
|
|||
},
|
||||
{
|
||||
"name": "gospel-resource-links",
|
||||
"rows": 3548
|
||||
"rows": 3550
|
||||
}
|
||||
]
|
||||
}
|
||||
2
public/assets/tables/people-group-pins.json
vendored
2
public/assets/tables/people-group-pins.json
vendored
File diff suppressed because one or more lines are too long
698
public/doxa-maps/assets/tables/door43-index.json
generated
698
public/doxa-maps/assets/tables/door43-index.json
generated
File diff suppressed because it is too large
Load diff
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
|
|
@ -26,7 +26,7 @@
|
|||
|
||||
<script>window.MAP_APP_API_URL = "https://pray.doxa.life";</script>
|
||||
<!-- Bundle IIFE — registers the <gospel-resources-map> custom element. -->
|
||||
<script src="../gospel-resources.js" integrity="sha384-HeeVt3sSmk4dGl91s+aSufyiWW6ostUjC4jrkIQRtWzIHwaxv8ADjbI8IPB5zJAJ" crossorigin="anonymous"></script>
|
||||
<script src="../gospel-resources.js" integrity="sha384-VMp4fgV4Ylxos7Fpb5J7WkW2zX/UMReS7AVPdfEn+lBEcEzTntA1YAx92ohBtZv8" crossorigin="anonymous"></script>
|
||||
|
||||
<script>
|
||||
// Mapbox token resolution — the A3 ladder, in precedence order:
|
||||
|
|
|
|||
|
|
@ -26,7 +26,7 @@
|
|||
|
||||
<script>window.MAP_APP_API_URL = "https://pray.doxa.life";</script>
|
||||
<!-- Bundle IIFE — registers the <gospel-resources-map> custom element. -->
|
||||
<script src="../gospel-resources.js" integrity="sha384-HeeVt3sSmk4dGl91s+aSufyiWW6ostUjC4jrkIQRtWzIHwaxv8ADjbI8IPB5zJAJ" crossorigin="anonymous"></script>
|
||||
<script src="../gospel-resources.js" integrity="sha384-VMp4fgV4Ylxos7Fpb5J7WkW2zX/UMReS7AVPdfEn+lBEcEzTntA1YAx92ohBtZv8" crossorigin="anonymous"></script>
|
||||
|
||||
<script>
|
||||
// Mapbox token resolution — the A3 ladder, in precedence order:
|
||||
|
|
|
|||
File diff suppressed because one or more lines are too long
|
|
@ -26,7 +26,7 @@
|
|||
|
||||
<script>window.MAP_APP_API_URL = "https://pray.doxa.life";</script>
|
||||
<!-- Bundle IIFE — registers the <gospel-resources-map> custom element. -->
|
||||
<script src="../gospel-resources.js" integrity="sha384-HeeVt3sSmk4dGl91s+aSufyiWW6ostUjC4jrkIQRtWzIHwaxv8ADjbI8IPB5zJAJ" crossorigin="anonymous"></script>
|
||||
<script src="../gospel-resources.js" integrity="sha384-VMp4fgV4Ylxos7Fpb5J7WkW2zX/UMReS7AVPdfEn+lBEcEzTntA1YAx92ohBtZv8" crossorigin="anonymous"></script>
|
||||
|
||||
<script>
|
||||
// Mapbox token resolution — the A3 ladder, in precedence order:
|
||||
|
|
|
|||
|
|
@ -29,7 +29,7 @@
|
|||
|
||||
<script>window.MAP_APP_API_URL = "https://pray.doxa.life";</script>
|
||||
<!-- Bundle IIFE — registers the <gospel-resources-map> custom element. -->
|
||||
<script src="../gospel-resources.js" integrity="sha384-HeeVt3sSmk4dGl91s+aSufyiWW6ostUjC4jrkIQRtWzIHwaxv8ADjbI8IPB5zJAJ" crossorigin="anonymous"></script>
|
||||
<script src="../gospel-resources.js" integrity="sha384-VMp4fgV4Ylxos7Fpb5J7WkW2zX/UMReS7AVPdfEn+lBEcEzTntA1YAx92ohBtZv8" crossorigin="anonymous"></script>
|
||||
|
||||
<script>
|
||||
// Mapbox token resolution — the A3 ladder, in precedence order:
|
||||
|
|
|
|||
2
public/doxa-maps/index.html
generated
2
public/doxa-maps/index.html
generated
File diff suppressed because one or more lines are too long
10
public/doxa-maps/manifest.json
generated
10
public/doxa-maps/manifest.json
generated
|
|
@ -556,7 +556,7 @@
|
|||
"bundle": "gospel-resources",
|
||||
"scriptUrl": "./gospel-resources/gospel-resources.js",
|
||||
"output": "doxa-maps/gospel-resources/gospel-resources.js",
|
||||
"integrity": "sha384-HeeVt3sSmk4dGl91s+aSufyiWW6ostUjC4jrkIQRtWzIHwaxv8ADjbI8IPB5zJAJ",
|
||||
"integrity": "sha384-VMp4fgV4Ylxos7Fpb5J7WkW2zX/UMReS7AVPdfEn+lBEcEzTntA1YAx92ohBtZv8",
|
||||
"elements": [
|
||||
"gospel-resources-map"
|
||||
],
|
||||
|
|
@ -572,7 +572,7 @@
|
|||
"scriptUrl": "./gospel-resources/gospel-resources.js",
|
||||
"embed": {
|
||||
"iframe": "<iframe src=\"./gospel-resources/charts/index.html?utm_source=YOUR_SOURCE\" width=\"100%\" height=\"600\" style=\"border:none;border-radius:12px;\" allowfullscreen></iframe>",
|
||||
"script": "<script>window.MAP_APP_API_URL=\"https://pray.doxa.life\";</script>\n<script src=\"./gospel-resources/gospel-resources.js\" integrity=\"sha384-HeeVt3sSmk4dGl91s+aSufyiWW6ostUjC4jrkIQRtWzIHwaxv8ADjbI8IPB5zJAJ\" crossorigin=\"anonymous\"></script>\n<gospel-resources-map profile-config='{\"profile\":\"charts\",\"tk\":\"YOUR_MAPBOX_TOKEN\",\"utmSource\":\"YOUR_SOURCE\",\"assetsBase\":\"YOUR_TREE_URL/assets\"}'></gospel-resources-map>"
|
||||
"script": "<script>window.MAP_APP_API_URL=\"https://pray.doxa.life\";</script>\n<script src=\"./gospel-resources/gospel-resources.js\" integrity=\"sha384-VMp4fgV4Ylxos7Fpb5J7WkW2zX/UMReS7AVPdfEn+lBEcEzTntA1YAx92ohBtZv8\" crossorigin=\"anonymous\"></script>\n<gospel-resources-map profile-config='{\"profile\":\"charts\",\"tk\":\"YOUR_MAPBOX_TOKEN\",\"utmSource\":\"YOUR_SOURCE\",\"assetsBase\":\"YOUR_TREE_URL/assets\"}'></gospel-resources-map>"
|
||||
}
|
||||
},
|
||||
{
|
||||
|
|
@ -586,7 +586,7 @@
|
|||
"scriptUrl": "./gospel-resources/gospel-resources.js",
|
||||
"embed": {
|
||||
"iframe": "<iframe src=\"./gospel-resources/data-tables/index.html?utm_source=YOUR_SOURCE\" width=\"100%\" height=\"600\" style=\"border:none;border-radius:12px;\" allowfullscreen></iframe>",
|
||||
"script": "<script>window.MAP_APP_API_URL=\"https://pray.doxa.life\";</script>\n<script src=\"./gospel-resources/gospel-resources.js\" integrity=\"sha384-HeeVt3sSmk4dGl91s+aSufyiWW6ostUjC4jrkIQRtWzIHwaxv8ADjbI8IPB5zJAJ\" crossorigin=\"anonymous\"></script>\n<gospel-resources-map profile-config='{\"profile\":\"data-tables\",\"tk\":\"YOUR_MAPBOX_TOKEN\",\"utmSource\":\"YOUR_SOURCE\",\"assetsBase\":\"YOUR_TREE_URL/assets\"}'></gospel-resources-map>"
|
||||
"script": "<script>window.MAP_APP_API_URL=\"https://pray.doxa.life\";</script>\n<script src=\"./gospel-resources/gospel-resources.js\" integrity=\"sha384-VMp4fgV4Ylxos7Fpb5J7WkW2zX/UMReS7AVPdfEn+lBEcEzTntA1YAx92ohBtZv8\" crossorigin=\"anonymous\"></script>\n<gospel-resources-map profile-config='{\"profile\":\"data-tables\",\"tk\":\"YOUR_MAPBOX_TOKEN\",\"utmSource\":\"YOUR_SOURCE\",\"assetsBase\":\"YOUR_TREE_URL/assets\"}'></gospel-resources-map>"
|
||||
}
|
||||
},
|
||||
{
|
||||
|
|
@ -600,7 +600,7 @@
|
|||
"scriptUrl": "./gospel-resources/gospel-resources.js",
|
||||
"embed": {
|
||||
"iframe": "<iframe src=\"./gospel-resources/resources-list/index.html?utm_source=YOUR_SOURCE\" width=\"100%\" height=\"600\" style=\"border:none;border-radius:12px;\" allowfullscreen></iframe>",
|
||||
"script": "<script>window.MAP_APP_API_URL=\"https://pray.doxa.life\";</script>\n<script src=\"./gospel-resources/gospel-resources.js\" integrity=\"sha384-HeeVt3sSmk4dGl91s+aSufyiWW6ostUjC4jrkIQRtWzIHwaxv8ADjbI8IPB5zJAJ\" crossorigin=\"anonymous\"></script>\n<gospel-resources-map profile-config='{\"profile\":\"resources-list\",\"tk\":\"YOUR_MAPBOX_TOKEN\",\"utmSource\":\"YOUR_SOURCE\",\"assetsBase\":\"YOUR_TREE_URL/assets\"}'></gospel-resources-map>"
|
||||
"script": "<script>window.MAP_APP_API_URL=\"https://pray.doxa.life\";</script>\n<script src=\"./gospel-resources/gospel-resources.js\" integrity=\"sha384-VMp4fgV4Ylxos7Fpb5J7WkW2zX/UMReS7AVPdfEn+lBEcEzTntA1YAx92ohBtZv8\" crossorigin=\"anonymous\"></script>\n<gospel-resources-map profile-config='{\"profile\":\"resources-list\",\"tk\":\"YOUR_MAPBOX_TOKEN\",\"utmSource\":\"YOUR_SOURCE\",\"assetsBase\":\"YOUR_TREE_URL/assets\"}'></gospel-resources-map>"
|
||||
}
|
||||
},
|
||||
{
|
||||
|
|
@ -614,7 +614,7 @@
|
|||
"scriptUrl": "./gospel-resources/gospel-resources.js",
|
||||
"embed": {
|
||||
"iframe": "<iframe src=\"./gospel-resources/resources-map/index.html?utm_source=YOUR_SOURCE\" width=\"100%\" height=\"600\" style=\"border:none;border-radius:12px;\" allowfullscreen></iframe>",
|
||||
"script": "<script>window.MAP_APP_API_URL=\"https://pray.doxa.life\";</script>\n<script src=\"./gospel-resources/gospel-resources.js\" integrity=\"sha384-HeeVt3sSmk4dGl91s+aSufyiWW6ostUjC4jrkIQRtWzIHwaxv8ADjbI8IPB5zJAJ\" crossorigin=\"anonymous\"></script>\n<gospel-resources-map profile-config='{\"profile\":\"resources-map\",\"tk\":\"YOUR_MAPBOX_TOKEN\",\"utmSource\":\"YOUR_SOURCE\",\"assetsBase\":\"YOUR_TREE_URL/assets\"}'></gospel-resources-map>"
|
||||
"script": "<script>window.MAP_APP_API_URL=\"https://pray.doxa.life\";</script>\n<script src=\"./gospel-resources/gospel-resources.js\" integrity=\"sha384-VMp4fgV4Ylxos7Fpb5J7WkW2zX/UMReS7AVPdfEn+lBEcEzTntA1YAx92ohBtZv8\" crossorigin=\"anonymous\"></script>\n<gospel-resources-map profile-config='{\"profile\":\"resources-map\",\"tk\":\"YOUR_MAPBOX_TOKEN\",\"utmSource\":\"YOUR_SOURCE\",\"assetsBase\":\"YOUR_TREE_URL/assets\"}'></gospel-resources-map>"
|
||||
}
|
||||
}
|
||||
]
|
||||
|
|
|
|||
Loading…
Reference in a new issue