docs: separate workflow effectiveness from skill health
Build and publish Eldorado documentation / build (pull_request) Successful in 52s
Build and publish Eldorado documentation / build (pull_request) Successful in 52s
This commit is contained in:
1 parent
386133c8b6
commit
e22d3a5c13
12 files changed
+142
-587
No files matched your search
@@ -19,6 +19,9 @@ const fs = require('node:fs');
|
||||
assert((await page.title()).startsWith('Skills Measurement |'));
|
||||
assert.equal(await page.locator('.strategy-content details').count(), 0);
|
||||
assert.equal(await page.locator('.strategy-content h2').count(), 2);
|
||||
assert.deepEqual((await page.locator('.strategy-content h3').allTextContents()).map(text => text.replaceAll('\u200b', '')), ['Workflow effectiveness', 'Skills effectiveness & health']);
|
||||
assert.equal(await page.locator('.strategy-content ol').count(), 2);
|
||||
assert.equal(await page.locator('.strategy-content ol > li').count(), 16);
|
||||
if (width < 700) await page.getByRole('button', {name:'Toggle navigation bar'}).click();
|
||||
const menu = page.locator('.theme-doc-sidebar-menu .menu__link').filter({visible:true});
|
||||
await menu.first().waitFor({state:'visible'});
|
||||
@@ -41,7 +44,7 @@ const fs = require('node:fs');
|
||||
await page.waitForFunction(() => document.documentElement.dataset.theme === 'dark');
|
||||
await frame.locator('#btn-theme').click();
|
||||
await page.waitForFunction(() => document.documentElement.dataset.theme === 'light');
|
||||
for (const preset of ['blueprint','classic']) {
|
||||
for (const preset of ['signal-flow','blueprint','editorial','classic']) {
|
||||
await frame.locator('#btn-preset').click();
|
||||
await frame.locator(`[data-preset-value="${preset}"]`).click();
|
||||
assert.equal(await frame.locator('html').getAttribute('data-preset'), preset);
|
||||
@@ -51,7 +54,30 @@ const fs = require('node:fs');
|
||||
assert.equal(await download.failure(), null);
|
||||
const path = `${output}/${width}.svg`; await download.saveAs(path);
|
||||
const svg = fs.readFileSync(path, 'utf8');
|
||||
assert(svg.includes('Available choices') && svg.includes('No mandatory collection'));
|
||||
assert(svg.includes('Workflow effectiveness') && svg.includes('Skills effectiveness & health') && svg.includes('No mandatory collection'));
|
||||
const exports = ['svg'];
|
||||
for (const format of ['png','jpeg','webp','svg-light','svg-dark','webm']) {
|
||||
await frame.locator('#btn-export').click();
|
||||
const option = frame.locator(`[data-format="${format}"]`);
|
||||
if (await option.isDisabled()) { exports.push(`${format}:unsupported`); await frame.locator('#btn-export').click(); continue; }
|
||||
const [file] = await Promise.all([page.waitForEvent('download', {timeout:60000}), option.click()]);
|
||||
assert.equal(await file.failure(), null);
|
||||
const target = `${output}/${width}-${format}-${file.suggestedFilename()}`;
|
||||
await file.saveAs(target);
|
||||
const bytes = fs.readFileSync(target); assert(bytes.length > 1000);
|
||||
if (format.startsWith('svg')) assert(bytes.toString().includes('eldorado-skills-typography'));
|
||||
else {
|
||||
const mime = {png:'image/png', jpeg:'image/jpeg', webp:'image/webp', webm:'video/webm'}[format];
|
||||
const dimensions = await page.evaluate(async ({mime,data}) => {
|
||||
const media = document.createElement(mime.startsWith('video') ? 'video' : 'img');
|
||||
const ready = new Promise((resolve,reject) => {media[mime.startsWith('video') ? 'onloadedmetadata' : 'onload'] = resolve; media.onerror = reject;});
|
||||
media.src = `data:${mime};base64,${data}`; await ready;
|
||||
return [media.videoWidth || media.naturalWidth, media.videoHeight || media.naturalHeight];
|
||||
}, {mime, data:bytes.toString('base64')});
|
||||
assert(dimensions.every(n => n > 0));
|
||||
}
|
||||
exports.push(format);
|
||||
}
|
||||
const opener = panel.getByRole('button', {name:/^Expand /});
|
||||
await opener.click();
|
||||
const close = panel.getByRole('button', {name:'Close full-screen diagram', exact:true});
|
||||
@@ -76,7 +102,7 @@ const fs = require('node:fs');
|
||||
assert.equal(new Set(links.map(h => new URL(h).pathname)).size, 18);
|
||||
assert(!await page.evaluate(() => document.documentElement.scrollWidth > innerWidth));
|
||||
assert.deepEqual(errors, []);
|
||||
results.push({width, geometry, links:links.length, title:true, sidebar:true, controls:true, export:true, reference:true});
|
||||
results.push({width, geometry, links:links.length, title:true, sidebar:true, controls:true, exports, reference:true});
|
||||
fs.writeFileSync(`${output}/results.json`, JSON.stringify(results,null,2));
|
||||
await context.close();
|
||||
}
|
||||
|
||||
@@ -40,6 +40,8 @@ const assert=require('node:assert/strict');
|
||||
await panel.scrollIntoViewIfNeeded();await page.screenshot({path:`${out}/${topic}-${width}-${theme}-inline.png`});
|
||||
const open=panel.getByRole('button',{name:/^Expand /});await open.click();const close=panel.getByRole('button',{name:'Close full-screen diagram',exact:true});await close.waitFor({state:'visible'});
|
||||
const expanded=await(await panel.locator('dialog iframe').elementHandle()).contentFrame();await expanded.locator('svg[role="img"]').waitFor();
|
||||
await expanded.waitForFunction(t=>document.documentElement.dataset.theme===t,theme);
|
||||
await panel.locator('dialog').evaluate(n=>n.scrollTop=0);
|
||||
assert((await expanded.url()).includes(width<=1100?`${topic}-mobile/`:`${topic}/`));
|
||||
await page.screenshot({path:`${out}/${topic}-${width}-${theme}-fullscreen.png`});
|
||||
if(width<=700){await page.setViewportSize({width,height:480});assert(await panel.locator('dialog').evaluate(n=>n.scrollHeight>n.clientHeight));await panel.locator('dialog').evaluate(n=>n.scrollTop=n.scrollHeight);await page.screenshot({path:`${out}/${topic}-${width}-${theme}-short-bottom.png`});await page.setViewportSize({width,height:900});}
|
||||
|
||||
@@ -28,6 +28,34 @@ test('all sixteen metric definitions remain in the reference with explicit imple
|
||||
for (const text of ['9 prototype calculations', '7 unimplemented metrics', 'no network collectors', '30 days', '12 months', 'below five people', 'Missing telemetry is unknown']) assert(page.includes(text), text);
|
||||
});
|
||||
|
||||
test('two groups exhaustively classify the sixteen canonical contracts without duplication', () => {
|
||||
const page = read('docs/strategy/measurement/index.mdx');
|
||||
const manifest = JSON.parse(read('research/ai-adoption/measurement-migration.json'));
|
||||
assert.deepEqual([...page.matchAll(/^### (.+)$/gm)].map(m => m[1]), ['Workflow effectiveness', 'Skills effectiveness & health']);
|
||||
const rows = [...page.matchAll(/^\d+\. \[([^\]]+)\]\(\.\/([^/]+)\.mdx\) — \*\*(Prototype calculation|Unimplemented metric)\.\*\*/gm)];
|
||||
assert.equal(rows.length, 16);
|
||||
assert.equal(new Set(rows.map(m => m[2])).size, 16);
|
||||
assert.deepEqual(rows.map(m => m[1]).sort(), manifest.metrics.map(m => m.title).sort());
|
||||
assert.equal(rows.filter(m => m[3] === 'Prototype calculation').length, 9);
|
||||
assert.equal(rows.filter(m => m[3] === 'Unimplemented metric').length, 7);
|
||||
const [workflow, skills] = page.split('### Workflow effectiveness')[1].split('### Skills effectiveness & health');
|
||||
assert.equal([...workflow.matchAll(/^\d+\. /gm)].length, 11);
|
||||
assert.equal([...skills.matchAll(/^\d+\. /gm)].length, 5);
|
||||
for (const slug of ['validated-task-success', 'confirmed-policy-effects', 'cost-per-accepted-outcome', 'workflow-specific-business-acceptance']) assert(workflow.includes(`./${slug}.mdx`));
|
||||
for (const slug of ['skill-selection-precision', 'skill-selection-recall', 'supported-bundle-coverage', 'approved-workflow-adoption', 'skills-within-substantive-review-window']) assert(skills.includes(`./${slug}.mdx`));
|
||||
for (const marker of ['N/A, not zero', 'More adoption does not prove improved work', 'Before/after trends alone are not causal evidence', 'Sandbox/evaluation cases remain excluded']) assert(page.includes(marker), marker);
|
||||
});
|
||||
|
||||
test('workflow task-success contract retains evaluation exclusions and explains conditional skill slices', () => {
|
||||
const page = read('docs/strategy/measurement/validated-task-success.mdx');
|
||||
assert.equal((page.match(/\| Expression \|/g) || []).length, 1);
|
||||
for (const marker of ['sandbox/evaluation tasks', 'Overlapping skill slices must not be summed', 'remains excluded by this contract', 'does not introduce an implemented skill-evaluation metric', 'N/A, not a zero workflow success rate']) assert(page.includes(marker), marker);
|
||||
for (const name of ['baseline', 'skills-adoption', 'skills-maintenance', 'stage-01-skills-adoption']) {
|
||||
const text = read(`docs/strategy/${name}.mdx`);
|
||||
if (name !== 'stage-01-skills-adoption') for (const group of ['Workflow effectiveness', 'Skills effectiveness & health']) assert(text.includes(group), name);
|
||||
}
|
||||
});
|
||||
|
||||
test('published pilot arithmetic matches the executable fixture, including partial cost', () => {
|
||||
const page = read('docs/strategy/skills-adoption.mdx');
|
||||
const fixture = JSON.parse(read('scripts/fixtures/ai-kpi-synthetic.json'));
|
||||
|
||||
@@ -43,7 +43,7 @@ test('domain contracts retain human authority, honest measures and Delivery-firs
|
||||
assert(text('quality').includes('Critical effect blocks'));
|
||||
assert(text('adoption').includes('Delivery first')&&text('adoption').includes('Later order undecided'));
|
||||
assert(text('adoption').includes('No quotas or rankings'));
|
||||
for(const marker of ['Available choices','16 candidate contracts','No mandatory collection','Meaning + applicability','9 prototype / 7 unimplemented'])assert(text('measurement').includes(marker),marker);
|
||||
for(const marker of ['Workflow effectiveness','Skills effectiveness & health','16 optional candidate contracts','No mandatory collection','Before / after is not causality','9 prototype / 7 unimplemented'])assert(text('measurement').includes(marker),marker);
|
||||
assert(text('maintenance').includes('No automatic reinstatement'));
|
||||
});
|
||||
test('topic compositions explain distinct relationships rather than a fixed card count',()=>{
|
||||
@@ -55,7 +55,7 @@ test('topic compositions explain distinct relationships rather than a fixed card
|
||||
has(g,'approve','owner');has(g,'distribute','withdraw');
|
||||
const q=spec('quality');for(const id of ['selection','safety','artifact','outcome'])has(q,id,'gate');has(q,'gate','accept');has(q,'gate','rework');
|
||||
const a=spec('adoption');for(const [x,y] of [['human','agent'],['agent','human'],['agent','learn'],['learn','delivery'],['learn','expand'],['human','expand']])has(a,x,y);
|
||||
const m=spec('measurement');for(const id of ['qualification','outcomes','experience','health']){has(m,'registry',id);has(m,id,'contract');}
|
||||
const m=spec('measurement');for(const [x,y] of [['workflow','compare'],['compare','interpret'],['skills','observe'],['observe','improve'],['interpret','improve']])has(m,x,y);
|
||||
const b=spec('baseline');for(const [x,y] of [['workflow','selection'],['selection','evidence'],['evidence','position'],['position','comparison']])has(b,x,y);
|
||||
const c=spec('maintenance');for(const [x,y] of [['observe','triage'],['triage','change'],['change','validate'],['validate','release'],['release','observe'],['triage','safe'],['safe','observe'],['triage','retire'],['triage','contain'],['contain','change']])has(c,x,y);
|
||||
});
|
||||
Reference in new issue
Block a user