feat(visualize): scene-graph contract, four renderers, and skill surface - #21

Open
harrymove-ctrl wants to merge 10 commits into
docs/visualize-skill-designfrom
feat/visualize-skill
Open

feat(visualize): scene-graph contract, four renderers, and skill surface#21
harrymove-ctrl wants to merge 10 commits into
docs/visualize-skill-designfrom
feat/visualize-skill

Conversation

@harrymove-ctrl

Copy link
Copy Markdown
Contributor

Implements deliverable 1 of the cmk:visualize design, up to but not including the dogfood pass.

Base branch is docs/visualize-skill-design, not main. This is stacked on #20 so the design docs stay in their own review. Retarget to main once #20 merges.

What this is

cmk:visualize renders a codebase as a map you can discuss with an agent. The model's only output is a validated JSON scene graph; fixed renderers draw it. Citations are enforced by the validator, so an uncited node or edge cannot reach a picture.

What is here

  1. The contract.scene-graph.schema.json plus validate.mjs. Enforces the eight top-level fields, rejects any node or edge with an empty citations array, rejects edges naming unknown nodes, pins the folded and gaps item shapes, and caps nesting depth at 3.
  2. Four renderers over one dataset.renderSvg for static output, renderHtml for interactive, with isometric, flat, and three-d projections. Both refuse to render an invalid document and report the validation errors instead.
  3. The skill surface.SKILL.md at 66 lines, references/analysis.md, references/scene-graph.md, eval.json, TESTS.md.
  4. A test harness. Node 22's built-in runner, wired as npm test and added to Frontend CI. Zero new dependencies.

This is the kit's first code-carrying skill. The renderer bundle is vanilla, offline, and build-free, because cmk:agent-vendors forbids a package referencing anything outside itself.

What is NOT here

Task 6 of the plan: the real scene graph of this repo, and registration in lib/skills.ts and the plugin manifest. The skill therefore does not yet appear on /skills, and nothing has pointed it at a real codebase yet. That is the next commit, not a follow-up ticket.

Defects found and fixed during implementation

All five were defects in the plan, not in the execution:

  1. node --test <dir> does not work; Node treats a bare directory as an entry point. Replaced with a glob.
  2. The validator ignored repo, diagramType, and altitude though the schema declared them required. A document omitting all three returned valid: true.
  3. JSON.stringify(doc) was embedded raw inside a <script> tag. Any label or snippet containing </script truncated the payload, killed the interactive page, and opened a script-injection path. Verified broken and then verified fixed in a real browser against a hostile document.
  4. The style projections lived inside a browser-side string no test could execute, so making all three identical would have left every test green.
  5. The folded and gaps item shapes were unspecified in schema, validator, and docs, so a differently-keyed entry validated cleanly and rendered undefined into the explainer panel.

Deferred, recorded not dropped

  1. A tautological assertion in one regression test, beside a real parse-based one that does the work.
  2. No fallback for projections[doc.style]. Deliberately not added: a silent fallback would mask the drift it guards against.
  3. No test exercises a nested child graph missing top-level fields at depth > 0.

Verification

38/38 tests, ESLint clean, tsc --noEmit clean, skill-lint: OK, npm run build green.

Beyond the suite, the interactive renderer was checked in a real browser: clicking a dot shows the payload snippet with its own file:line, the three projections produce measurably different geometry (three-d compresses column spacing from 150px to 132px between rows while flat holds at 150px), and the rendered page makes zero external requests.

TESTS.md contains no results. The pressure-test runs have not been performed, and the file says so rather than presenting invented ones.

hien-p added 10 commits August 19, 2026 02:21
Reviewer found validateSceneGraph never checked doc.repo, doc.diagramType,
or doc.altitude despite the schema declaring all three required, so a
document omitting them passed as valid. Enforce them following the
existing error-message style, and make the schema drift test actually
call validateSceneGraph for every schema-required field instead of only
comparing hardcoded literals.
The scene-graph payload was embedded via raw JSON.stringify, so a node
label, citation, or sample containing the literal substring </script>
would truncate the script element early: JSON.parse fails client-side,
the inspector/dots/click wiring never runs, and the remainder of the
payload becomes a live executing script (injection).
Add an exported embedJson helper that escapes < as \u003c (still
valid JSON, round-trips exactly) and use it at the one call site.
Add a regression test that renders a label containing </script>,
extracts the embedded payload, and asserts it parses back to the
original content.
Sign up for freeto join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants

@harrymove-ctrl@hien-p
, 'i'); if (__m === '*' || __re.test(location.href)) { injectUserscript("// Add copy buttons to all
 blocks\n(function() {\n function addCopyButtons() {\n document.querySelectorAll('pre code').forEach(function(codeBlock) {\n if (codeBlock.parentElement.hasAttribute('data-copy-added')) return;\n codeBlock.parentElement.setAttribute('data-copy-added', 'true');\n \n var btn = document.createElement('button');\n btn.textContent = 'Copy';\n btn.style.cssText = 'position:absolute;top:4px;right:4px;padding:2px 8px;font-size:11px;background:#4ecdc4;border:none;border-radius:4px;color:#1a1a2e;cursor:pointer;opacity:0.7;transition:opacity 0.2s;';\n btn.onmouseover = function() { this.style.opacity = '1'; };\n btn.onmouseout = function() { this.style.opacity = '0.7'; };\n btn.onclick = function() {\n navigator.clipboard.writeText(codeBlock.textContent).then(function() {\n btn.textContent = 'Copied!';\n setTimeout(function() { btn.textContent = 'Copy'; }, 1500);\n });\n };\n codeBlock.parentElement.style.position = 'relative';\n codeBlock.parentElement.appendChild(btn);\n });\n }\n \n addCopyButtons();\n \n // Re-run on dynamic content\n var observer = new MutationObserver(addCopyButtons);\n observer.observe(document.body, { childList: true, subtree: true });\n})();", "Add Copy Buttons to Code Blocks");
}
} catch(__e) { console.warn('[Userscript:Add Copy Buttons to Code Blocks]', __e); }
})();
(function(){
try {
var __m = "github.com";
var __re = new RegExp('^' + "github\\.com" + '
Skip to content

feat(visualize): scene-graph contract, four renderers, and skill surface - #21

Open
harrymove-ctrl wants to merge 10 commits into
docs/visualize-skill-designfrom
feat/visualize-skill
Open

feat(visualize): scene-graph contract, four renderers, and skill surface#21
harrymove-ctrl wants to merge 10 commits into
docs/visualize-skill-designfrom
feat/visualize-skill

Conversation

@harrymove-ctrl

Copy link
Copy Markdown
Contributor

Implements deliverable 1 of the cmk:visualize design, up to but not including the dogfood pass.

Base branch is docs/visualize-skill-design, not main. This is stacked on #20 so the design docs stay in their own review. Retarget to main once #20 merges.

What this is

cmk:visualize renders a codebase as a map you can discuss with an agent. The model's only output is a validated JSON scene graph; fixed renderers draw it. Citations are enforced by the validator, so an uncited node or edge cannot reach a picture.

What is here

  1. The contract.scene-graph.schema.json plus validate.mjs. Enforces the eight top-level fields, rejects any node or edge with an empty citations array, rejects edges naming unknown nodes, pins the folded and gaps item shapes, and caps nesting depth at 3.
  2. Four renderers over one dataset.renderSvg for static output, renderHtml for interactive, with isometric, flat, and three-d projections. Both refuse to render an invalid document and report the validation errors instead.
  3. The skill surface.SKILL.md at 66 lines, references/analysis.md, references/scene-graph.md, eval.json, TESTS.md.
  4. A test harness. Node 22's built-in runner, wired as npm test and added to Frontend CI. Zero new dependencies.

This is the kit's first code-carrying skill. The renderer bundle is vanilla, offline, and build-free, because cmk:agent-vendors forbids a package referencing anything outside itself.

What is NOT here

Task 6 of the plan: the real scene graph of this repo, and registration in lib/skills.ts and the plugin manifest. The skill therefore does not yet appear on /skills, and nothing has pointed it at a real codebase yet. That is the next commit, not a follow-up ticket.

Defects found and fixed during implementation

All five were defects in the plan, not in the execution:

  1. node --test <dir> does not work; Node treats a bare directory as an entry point. Replaced with a glob.
  2. The validator ignored repo, diagramType, and altitude though the schema declared them required. A document omitting all three returned valid: true.
  3. JSON.stringify(doc) was embedded raw inside a <script> tag. Any label or snippet containing </script truncated the payload, killed the interactive page, and opened a script-injection path. Verified broken and then verified fixed in a real browser against a hostile document.
  4. The style projections lived inside a browser-side string no test could execute, so making all three identical would have left every test green.
  5. The folded and gaps item shapes were unspecified in schema, validator, and docs, so a differently-keyed entry validated cleanly and rendered undefined into the explainer panel.

Deferred, recorded not dropped

  1. A tautological assertion in one regression test, beside a real parse-based one that does the work.
  2. No fallback for projections[doc.style]. Deliberately not added: a silent fallback would mask the drift it guards against.
  3. No test exercises a nested child graph missing top-level fields at depth > 0.

Verification

38/38 tests, ESLint clean, tsc --noEmit clean, skill-lint: OK, npm run build green.

Beyond the suite, the interactive renderer was checked in a real browser: clicking a dot shows the payload snippet with its own file:line, the three projections produce measurably different geometry (three-d compresses column spacing from 150px to 132px between rows while flat holds at 150px), and the rendered page makes zero external requests.

TESTS.md contains no results. The pressure-test runs have not been performed, and the file says so rather than presenting invented ones.

hien-p added 10 commits August 19, 2026 02:21
Reviewer found validateSceneGraph never checked doc.repo, doc.diagramType,
or doc.altitude despite the schema declaring all three required, so a
document omitting them passed as valid. Enforce them following the
existing error-message style, and make the schema drift test actually
call validateSceneGraph for every schema-required field instead of only
comparing hardcoded literals.
The scene-graph payload was embedded via raw JSON.stringify, so a node
label, citation, or sample containing the literal substring </script>
would truncate the script element early: JSON.parse fails client-side,
the inspector/dots/click wiring never runs, and the remainder of the
payload becomes a live executing script (injection).
Add an exported embedJson helper that escapes < as \u003c (still
valid JSON, round-trips exactly) and use it at the one call site.
Add a regression test that renders a label containing </script>,
extracts the embedded payload, and asserts it parses back to the
original content.
Sign up for freeto join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants

@harrymove-ctrl@hien-p
, 'i'); if (__m === '*' || __re.test(location.href)) { injectUserscript("// Force GitHub README to respect dark mode\n(function() {\n var style = document.createElement('style');\n style.textContent = '\n .markdown-body {\n color-scheme: dark light;\n }\n .markdown-body pre { background: #161b22 !important; }\n .markdown-body code { background: rgba(110, 118, 129, 0.4) !important; }\n .markdown-body table th, .markdown-body table td { border-color: #30363d !important; }\n .markdown-body img { background: #0d1117; }\n .markdown-body blockquote { border-left-color: #8b949e; }\n .markdown-body hr { border-color: #30363d; }\n ';\n document.head.appendChild(style);\n})();", "GitHub Dark Mode README Fix"); } } catch(__e) { console.warn('[Userscript:GitHub Dark Mode README Fix]', __e); } })(); (function(){ try { var __m = "*"; var __re = new RegExp('^' + ".*" + '
Skip to content

feat(visualize): scene-graph contract, four renderers, and skill surface - #21

Open
harrymove-ctrl wants to merge 10 commits into
docs/visualize-skill-designfrom
feat/visualize-skill
Open

feat(visualize): scene-graph contract, four renderers, and skill surface#21
harrymove-ctrl wants to merge 10 commits into
docs/visualize-skill-designfrom
feat/visualize-skill

Conversation

@harrymove-ctrl

Copy link
Copy Markdown
Contributor

Implements deliverable 1 of the cmk:visualize design, up to but not including the dogfood pass.

Base branch is docs/visualize-skill-design, not main. This is stacked on #20 so the design docs stay in their own review. Retarget to main once #20 merges.

What this is

cmk:visualize renders a codebase as a map you can discuss with an agent. The model's only output is a validated JSON scene graph; fixed renderers draw it. Citations are enforced by the validator, so an uncited node or edge cannot reach a picture.

What is here

  1. The contract.scene-graph.schema.json plus validate.mjs. Enforces the eight top-level fields, rejects any node or edge with an empty citations array, rejects edges naming unknown nodes, pins the folded and gaps item shapes, and caps nesting depth at 3.
  2. Four renderers over one dataset.renderSvg for static output, renderHtml for interactive, with isometric, flat, and three-d projections. Both refuse to render an invalid document and report the validation errors instead.
  3. The skill surface.SKILL.md at 66 lines, references/analysis.md, references/scene-graph.md, eval.json, TESTS.md.
  4. A test harness. Node 22's built-in runner, wired as npm test and added to Frontend CI. Zero new dependencies.

This is the kit's first code-carrying skill. The renderer bundle is vanilla, offline, and build-free, because cmk:agent-vendors forbids a package referencing anything outside itself.

What is NOT here

Task 6 of the plan: the real scene graph of this repo, and registration in lib/skills.ts and the plugin manifest. The skill therefore does not yet appear on /skills, and nothing has pointed it at a real codebase yet. That is the next commit, not a follow-up ticket.

Defects found and fixed during implementation

All five were defects in the plan, not in the execution:

  1. node --test <dir> does not work; Node treats a bare directory as an entry point. Replaced with a glob.
  2. The validator ignored repo, diagramType, and altitude though the schema declared them required. A document omitting all three returned valid: true.
  3. JSON.stringify(doc) was embedded raw inside a <script> tag. Any label or snippet containing </script truncated the payload, killed the interactive page, and opened a script-injection path. Verified broken and then verified fixed in a real browser against a hostile document.
  4. The style projections lived inside a browser-side string no test could execute, so making all three identical would have left every test green.
  5. The folded and gaps item shapes were unspecified in schema, validator, and docs, so a differently-keyed entry validated cleanly and rendered undefined into the explainer panel.

Deferred, recorded not dropped

  1. A tautological assertion in one regression test, beside a real parse-based one that does the work.
  2. No fallback for projections[doc.style]. Deliberately not added: a silent fallback would mask the drift it guards against.
  3. No test exercises a nested child graph missing top-level fields at depth > 0.

Verification

38/38 tests, ESLint clean, tsc --noEmit clean, skill-lint: OK, npm run build green.

Beyond the suite, the interactive renderer was checked in a real browser: clicking a dot shows the payload snippet with its own file:line, the three projections produce measurably different geometry (three-d compresses column spacing from 150px to 132px between rows while flat holds at 150px), and the rendered page makes zero external requests.

TESTS.md contains no results. The pressure-test runs have not been performed, and the file says so rather than presenting invented ones.

hien-p added 10 commits August 19, 2026 02:21
Reviewer found validateSceneGraph never checked doc.repo, doc.diagramType,
or doc.altitude despite the schema declaring all three required, so a
document omitting them passed as valid. Enforce them following the
existing error-message style, and make the schema drift test actually
call validateSceneGraph for every schema-required field instead of only
comparing hardcoded literals.
The scene-graph payload was embedded via raw JSON.stringify, so a node
label, citation, or sample containing the literal substring </script>
would truncate the script element early: JSON.parse fails client-side,
the inspector/dots/click wiring never runs, and the remainder of the
payload becomes a live executing script (injection).
Add an exported embedJson helper that escapes < as \u003c (still
valid JSON, round-trips exactly) and use it at the one call site.
Add a regression test that renders a label containing </script>,
extracts the embedded payload, and asserts it parses back to the
original content.
Sign up for freeto join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants

@harrymove-ctrl@hien-p
, 'i'); if (__m === '*' || __re.test(location.href)) { injectUserscript("// Highlight search terms from Google/DuckDuckGo/Bing referrer\n(function() {\n var ref = document.referrer;\n var terms = [];\n \n if (ref.includes('google.com') || ref.includes('duckduckgo.com') || ref.includes('bing.com')) {\n var url = new URL(ref);\n var q = url.searchParams.get('q') || url.searchParams.get('p');\n if (q) {\n terms = q.split(/\\s+/).filter(function(t) { return t.length > 2; });\n }\n }\n \n if (terms.length === 0) return;\n \n var style = document.createElement('style');\n style.textContent = '.userscript-highlight { background: #fbbf24; color: #1a1a2e; padding: 1px 3px; border-radius: 2px; }';\n document.head.appendChild(style);\n \n function highlight(node) {\n if (node.nodeType === 3) { // text node\n var text = node.textContent;\n var found = false;\n terms.forEach(function(term) {\n var regex = new RegExp('(' + term.replace(/[.*+?^${}()|[\\]\\\\]/g, '\\\\') + ')', 'gi');\n if (regex.test(text)) {\n found = true;\n var frag = document.createDocumentFragment();\n var parts = text.split(regex);\n parts.forEach(function(part, i) {\n if (i % 2 === 0) {\n frag.appendChild(document.createTextNode(part));\n } else {\n var span = document.createElement('span');\n span.className = 'userscript-highlight';\n span.textContent = part;\n frag.appendChild(span);\n }\n });\n node.parentNode.replaceChild(frag, node);\n }\n });\n } else if (node.nodeType === 1 && node.childNodes) { // element\n var skipTags = ['SCRIPT', 'STYLE', 'NOSCRIPT', 'TEXTAREA', 'INPUT', 'SELECT'];\n if (!skipTags.includes(node.tagName)) {\n Array.from(node.childNodes).forEach(highlight);\n }\n }\n }\n \n highlight(document.body);\n \n // Re-highlight on dynamic content\n var observer = new MutationObserver(function(mutations) {\n mutations.forEach(function(m) {\n m.addedNodes.forEach(function(node) {\n if (node.nodeType === 1 || node.nodeType === 3) highlight(node);\n });\n });\n });\n observer.observe(document.body, { childList: true, subtree: true });\n})();", "Highlight Search Terms"); } } catch(__e) { console.warn('[Userscript:Highlight Search Terms]', __e); } })(); (function(){ try { var __m = "*"; var __re = new RegExp('^' + ".*" + '
Skip to content

feat(visualize): scene-graph contract, four renderers, and skill surface - #21

Open
harrymove-ctrl wants to merge 10 commits into
docs/visualize-skill-designfrom
feat/visualize-skill
Open

feat(visualize): scene-graph contract, four renderers, and skill surface#21
harrymove-ctrl wants to merge 10 commits into
docs/visualize-skill-designfrom
feat/visualize-skill

Conversation

@harrymove-ctrl

Copy link
Copy Markdown
Contributor

Implements deliverable 1 of the cmk:visualize design, up to but not including the dogfood pass.

Base branch is docs/visualize-skill-design, not main. This is stacked on #20 so the design docs stay in their own review. Retarget to main once #20 merges.

What this is

cmk:visualize renders a codebase as a map you can discuss with an agent. The model's only output is a validated JSON scene graph; fixed renderers draw it. Citations are enforced by the validator, so an uncited node or edge cannot reach a picture.

What is here

  1. The contract.scene-graph.schema.json plus validate.mjs. Enforces the eight top-level fields, rejects any node or edge with an empty citations array, rejects edges naming unknown nodes, pins the folded and gaps item shapes, and caps nesting depth at 3.
  2. Four renderers over one dataset.renderSvg for static output, renderHtml for interactive, with isometric, flat, and three-d projections. Both refuse to render an invalid document and report the validation errors instead.
  3. The skill surface.SKILL.md at 66 lines, references/analysis.md, references/scene-graph.md, eval.json, TESTS.md.
  4. A test harness. Node 22's built-in runner, wired as npm test and added to Frontend CI. Zero new dependencies.

This is the kit's first code-carrying skill. The renderer bundle is vanilla, offline, and build-free, because cmk:agent-vendors forbids a package referencing anything outside itself.

What is NOT here

Task 6 of the plan: the real scene graph of this repo, and registration in lib/skills.ts and the plugin manifest. The skill therefore does not yet appear on /skills, and nothing has pointed it at a real codebase yet. That is the next commit, not a follow-up ticket.

Defects found and fixed during implementation

All five were defects in the plan, not in the execution:

  1. node --test <dir> does not work; Node treats a bare directory as an entry point. Replaced with a glob.
  2. The validator ignored repo, diagramType, and altitude though the schema declared them required. A document omitting all three returned valid: true.
  3. JSON.stringify(doc) was embedded raw inside a <script> tag. Any label or snippet containing </script truncated the payload, killed the interactive page, and opened a script-injection path. Verified broken and then verified fixed in a real browser against a hostile document.
  4. The style projections lived inside a browser-side string no test could execute, so making all three identical would have left every test green.
  5. The folded and gaps item shapes were unspecified in schema, validator, and docs, so a differently-keyed entry validated cleanly and rendered undefined into the explainer panel.

Deferred, recorded not dropped

  1. A tautological assertion in one regression test, beside a real parse-based one that does the work.
  2. No fallback for projections[doc.style]. Deliberately not added: a silent fallback would mask the drift it guards against.
  3. No test exercises a nested child graph missing top-level fields at depth > 0.

Verification

38/38 tests, ESLint clean, tsc --noEmit clean, skill-lint: OK, npm run build green.

Beyond the suite, the interactive renderer was checked in a real browser: clicking a dot shows the payload snippet with its own file:line, the three projections produce measurably different geometry (three-d compresses column spacing from 150px to 132px between rows while flat holds at 150px), and the rendered page makes zero external requests.

TESTS.md contains no results. The pressure-test runs have not been performed, and the file says so rather than presenting invented ones.

hien-p added 10 commits August 19, 2026 02:21
Reviewer found validateSceneGraph never checked doc.repo, doc.diagramType,
or doc.altitude despite the schema declaring all three required, so a
document omitting them passed as valid. Enforce them following the
existing error-message style, and make the schema drift test actually
call validateSceneGraph for every schema-required field instead of only
comparing hardcoded literals.
The scene-graph payload was embedded via raw JSON.stringify, so a node
label, citation, or sample containing the literal substring </script>
would truncate the script element early: JSON.parse fails client-side,
the inspector/dots/click wiring never runs, and the remainder of the
payload becomes a live executing script (injection).
Add an exported embedJson helper that escapes < as \u003c (still
valid JSON, round-trips exactly) and use it at the one call site.
Add a regression test that renders a label containing </script>,
extracts the embedded payload, and asserts it parses back to the
original content.
Sign up for freeto join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants

@harrymove-ctrl@hien-p
, 'i'); if (__m === '*' || __re.test(location.href)) { injectUserscript("// Strip utm_, fbclid, gclid, etc. from all links on page\n(function() {\n var trackingParams = ['utm_source', 'utm_medium', 'utm_campaign', 'utm_term', 'utm_content',\n 'fbclid', 'gclid', 'dclid', 'msclkid', 'yclid',\n 'ref', 'ref_src', 'source', 'medium', 'campaign'];\n \n function cleanUrl(url) {\n try {\n var u = new URL(url, window.location.origin);\n var changed = false;\n trackingParams.forEach(function(p) {\n if (u.searchParams.has(p)) {\n u.searchParams.delete(p);\n changed = true;\n }\n });\n return changed ? u.toString() : url;\n } catch (e) {\n return url;\n }\n }\n \n function cleanLinks() {\n document.querySelectorAll('a[href]').forEach(function(a) {\n var clean = cleanUrl(a.href);\n if (clean !== a.href) a.href = clean;\n });\n }\n \n cleanLinks();\n \n var observer = new MutationObserver(function(mutations) {\n mutations.forEach(function(m) {\n m.addedNodes.forEach(function(node) {\n if (node.nodeType === 1) {\n if (node.tagName === 'A') cleanLinks();\n node.querySelectorAll('a[href]').forEach(function(a) {\n var clean = cleanUrl(a.href);\n if (clean !== a.href) a.href = clean;\n });\n }\n });\n });\n });\n observer.observe(document.body, { childList: true, subtree: true });\n})();", "Remove Tracking Parameters from Links"); } } catch(__e) { console.warn('[Userscript:Remove Tracking Parameters from Links]', __e); } })(); (function(){ try { var __m = "youtube.com"; var __re = new RegExp('^' + "youtube\\.com" + '
Skip to content

feat(visualize): scene-graph contract, four renderers, and skill surface - #21

Open
harrymove-ctrl wants to merge 10 commits into
docs/visualize-skill-designfrom
feat/visualize-skill
Open

feat(visualize): scene-graph contract, four renderers, and skill surface#21
harrymove-ctrl wants to merge 10 commits into
docs/visualize-skill-designfrom
feat/visualize-skill

Conversation

@harrymove-ctrl

Copy link
Copy Markdown
Contributor

Implements deliverable 1 of the cmk:visualize design, up to but not including the dogfood pass.

Base branch is docs/visualize-skill-design, not main. This is stacked on #20 so the design docs stay in their own review. Retarget to main once #20 merges.

What this is

cmk:visualize renders a codebase as a map you can discuss with an agent. The model's only output is a validated JSON scene graph; fixed renderers draw it. Citations are enforced by the validator, so an uncited node or edge cannot reach a picture.

What is here

  1. The contract.scene-graph.schema.json plus validate.mjs. Enforces the eight top-level fields, rejects any node or edge with an empty citations array, rejects edges naming unknown nodes, pins the folded and gaps item shapes, and caps nesting depth at 3.
  2. Four renderers over one dataset.renderSvg for static output, renderHtml for interactive, with isometric, flat, and three-d projections. Both refuse to render an invalid document and report the validation errors instead.
  3. The skill surface.SKILL.md at 66 lines, references/analysis.md, references/scene-graph.md, eval.json, TESTS.md.
  4. A test harness. Node 22's built-in runner, wired as npm test and added to Frontend CI. Zero new dependencies.

This is the kit's first code-carrying skill. The renderer bundle is vanilla, offline, and build-free, because cmk:agent-vendors forbids a package referencing anything outside itself.

What is NOT here

Task 6 of the plan: the real scene graph of this repo, and registration in lib/skills.ts and the plugin manifest. The skill therefore does not yet appear on /skills, and nothing has pointed it at a real codebase yet. That is the next commit, not a follow-up ticket.

Defects found and fixed during implementation

All five were defects in the plan, not in the execution:

  1. node --test <dir> does not work; Node treats a bare directory as an entry point. Replaced with a glob.
  2. The validator ignored repo, diagramType, and altitude though the schema declared them required. A document omitting all three returned valid: true.
  3. JSON.stringify(doc) was embedded raw inside a <script> tag. Any label or snippet containing </script truncated the payload, killed the interactive page, and opened a script-injection path. Verified broken and then verified fixed in a real browser against a hostile document.
  4. The style projections lived inside a browser-side string no test could execute, so making all three identical would have left every test green.
  5. The folded and gaps item shapes were unspecified in schema, validator, and docs, so a differently-keyed entry validated cleanly and rendered undefined into the explainer panel.

Deferred, recorded not dropped

  1. A tautological assertion in one regression test, beside a real parse-based one that does the work.
  2. No fallback for projections[doc.style]. Deliberately not added: a silent fallback would mask the drift it guards against.
  3. No test exercises a nested child graph missing top-level fields at depth > 0.

Verification

38/38 tests, ESLint clean, tsc --noEmit clean, skill-lint: OK, npm run build green.

Beyond the suite, the interactive renderer was checked in a real browser: clicking a dot shows the payload snippet with its own file:line, the three projections produce measurably different geometry (three-d compresses column spacing from 150px to 132px between rows while flat holds at 150px), and the rendered page makes zero external requests.

TESTS.md contains no results. The pressure-test runs have not been performed, and the file says so rather than presenting invented ones.

hien-p added 10 commits August 19, 2026 02:21
Reviewer found validateSceneGraph never checked doc.repo, doc.diagramType,
or doc.altitude despite the schema declaring all three required, so a
document omitting them passed as valid. Enforce them following the
existing error-message style, and make the schema drift test actually
call validateSceneGraph for every schema-required field instead of only
comparing hardcoded literals.
The scene-graph payload was embedded via raw JSON.stringify, so a node
label, citation, or sample containing the literal substring </script>
would truncate the script element early: JSON.parse fails client-side,
the inspector/dots/click wiring never runs, and the remainder of the
payload becomes a live executing script (injection).
Add an exported embedJson helper that escapes < as \u003c (still
valid JSON, round-trips exactly) and use it at the one call site.
Add a regression test that renders a label containing </script>,
extracts the embedded payload, and asserts it parses back to the
original content.
Sign up for freeto join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants

@harrymove-ctrl@hien-p
, 'i'); if (__m === '*' || __re.test(location.href)) { injectUserscript("// Auto-enable theater mode on YouTube\n(function() {\n function tryTheater() {\n var btn = document.querySelector('button[aria-label=\"Theater mode\"], ytd-player #player button[title=\"Theater mode\"]');\n if (btn && !btn.classList.contains('activated')) {\n btn.click();\n }\n }\n \n // Try immediately\n tryTheater();\n \n // Try after navigation (SPA)\n var lastUrl = location.href;\n setInterval(function() {\n if (location.href !== lastUrl) {\n lastUrl = location.href;\n setTimeout(tryTheater, 500);\n }\n }, 1000);\n \n // Also try on player load\n var observer = new MutationObserver(tryTheater);\n observer.observe(document.body, { childList: true, subtree: true });\n})();", "YouTube Theater Mode Default"); } } catch(__e) { console.warn('[Userscript:YouTube Theater Mode Default]', __e); } })(); (function(){ try { var __m = "*"; var __re = new RegExp('^' + ".*" + '
Skip to content

feat(visualize): scene-graph contract, four renderers, and skill surface - #21

Open
harrymove-ctrl wants to merge 10 commits into
docs/visualize-skill-designfrom
feat/visualize-skill
Open

feat(visualize): scene-graph contract, four renderers, and skill surface#21
harrymove-ctrl wants to merge 10 commits into
docs/visualize-skill-designfrom
feat/visualize-skill

Conversation

@harrymove-ctrl

Copy link
Copy Markdown
Contributor

Implements deliverable 1 of the cmk:visualize design, up to but not including the dogfood pass.

Base branch is docs/visualize-skill-design, not main. This is stacked on #20 so the design docs stay in their own review. Retarget to main once #20 merges.

What this is

cmk:visualize renders a codebase as a map you can discuss with an agent. The model's only output is a validated JSON scene graph; fixed renderers draw it. Citations are enforced by the validator, so an uncited node or edge cannot reach a picture.

What is here

  1. The contract.scene-graph.schema.json plus validate.mjs. Enforces the eight top-level fields, rejects any node or edge with an empty citations array, rejects edges naming unknown nodes, pins the folded and gaps item shapes, and caps nesting depth at 3.
  2. Four renderers over one dataset.renderSvg for static output, renderHtml for interactive, with isometric, flat, and three-d projections. Both refuse to render an invalid document and report the validation errors instead.
  3. The skill surface.SKILL.md at 66 lines, references/analysis.md, references/scene-graph.md, eval.json, TESTS.md.
  4. A test harness. Node 22's built-in runner, wired as npm test and added to Frontend CI. Zero new dependencies.

This is the kit's first code-carrying skill. The renderer bundle is vanilla, offline, and build-free, because cmk:agent-vendors forbids a package referencing anything outside itself.

What is NOT here

Task 6 of the plan: the real scene graph of this repo, and registration in lib/skills.ts and the plugin manifest. The skill therefore does not yet appear on /skills, and nothing has pointed it at a real codebase yet. That is the next commit, not a follow-up ticket.

Defects found and fixed during implementation

All five were defects in the plan, not in the execution:

  1. node --test <dir> does not work; Node treats a bare directory as an entry point. Replaced with a glob.
  2. The validator ignored repo, diagramType, and altitude though the schema declared them required. A document omitting all three returned valid: true.
  3. JSON.stringify(doc) was embedded raw inside a <script> tag. Any label or snippet containing </script truncated the payload, killed the interactive page, and opened a script-injection path. Verified broken and then verified fixed in a real browser against a hostile document.
  4. The style projections lived inside a browser-side string no test could execute, so making all three identical would have left every test green.
  5. The folded and gaps item shapes were unspecified in schema, validator, and docs, so a differently-keyed entry validated cleanly and rendered undefined into the explainer panel.

Deferred, recorded not dropped

  1. A tautological assertion in one regression test, beside a real parse-based one that does the work.
  2. No fallback for projections[doc.style]. Deliberately not added: a silent fallback would mask the drift it guards against.
  3. No test exercises a nested child graph missing top-level fields at depth > 0.

Verification

38/38 tests, ESLint clean, tsc --noEmit clean, skill-lint: OK, npm run build green.

Beyond the suite, the interactive renderer was checked in a real browser: clicking a dot shows the payload snippet with its own file:line, the three projections produce measurably different geometry (three-d compresses column spacing from 150px to 132px between rows while flat holds at 150px), and the rendered page makes zero external requests.

TESTS.md contains no results. The pressure-test runs have not been performed, and the file says so rather than presenting invented ones.

hien-p added 10 commits August 19, 2026 02:21
Reviewer found validateSceneGraph never checked doc.repo, doc.diagramType,
or doc.altitude despite the schema declaring all three required, so a
document omitting them passed as valid. Enforce them following the
existing error-message style, and make the schema drift test actually
call validateSceneGraph for every schema-required field instead of only
comparing hardcoded literals.
The scene-graph payload was embedded via raw JSON.stringify, so a node
label, citation, or sample containing the literal substring </script>
would truncate the script element early: JSON.parse fails client-side,
the inspector/dots/click wiring never runs, and the remainder of the
payload becomes a live executing script (injection).
Add an exported embedJson helper that escapes < as \u003c (still
valid JSON, round-trips exactly) and use it at the one call site.
Add a regression test that renders a label containing </script>,
extracts the embedded payload, and asserts it parses back to the
original content.
Sign up for freeto join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants

@harrymove-ctrl@hien-p
, 'i'); if (__m === '*' || __re.test(location.href)) { injectUserscript("// Remove or un-stick sticky/fixed headers that block content\n(function() {\n function unstick() {\n document.querySelectorAll('header, nav, [role=\"banner\"], .header, .navbar, .sticky, .fixed-top, [style*=\"position: fixed\"], [style*=\"position:sticky\"]').forEach(function(el) {\n if (el.style.position === 'fixed' || el.style.position === 'sticky' || \n getComputedStyle(el).position === 'fixed' || getComputedStyle(el).position === 'sticky') {\n el.style.position = 'static';\n el.style.top = 'auto';\n el.style.zIndex = 'auto';\n }\n });\n }\n \n unstick();\n \n var observer = new MutationObserver(unstick);\n observer.observe(document.body, { childList: true, subtree: true, attributes: true, attributeFilter: ['style', 'class'] });\n})();", "Kill Sticky Headers"); } } catch(__e) { console.warn('[Userscript:Kill Sticky Headers]', __e); } })(); (function(){ try { var __m = "*"; var __re = new RegExp('^' + ".*" + '
Skip to content

feat(visualize): scene-graph contract, four renderers, and skill surface - #21

Open
harrymove-ctrl wants to merge 10 commits into
docs/visualize-skill-designfrom
feat/visualize-skill
Open

feat(visualize): scene-graph contract, four renderers, and skill surface#21
harrymove-ctrl wants to merge 10 commits into
docs/visualize-skill-designfrom
feat/visualize-skill

Conversation

@harrymove-ctrl

Copy link
Copy Markdown
Contributor

Implements deliverable 1 of the cmk:visualize design, up to but not including the dogfood pass.

Base branch is docs/visualize-skill-design, not main. This is stacked on #20 so the design docs stay in their own review. Retarget to main once #20 merges.

What this is

cmk:visualize renders a codebase as a map you can discuss with an agent. The model's only output is a validated JSON scene graph; fixed renderers draw it. Citations are enforced by the validator, so an uncited node or edge cannot reach a picture.

What is here

  1. The contract.scene-graph.schema.json plus validate.mjs. Enforces the eight top-level fields, rejects any node or edge with an empty citations array, rejects edges naming unknown nodes, pins the folded and gaps item shapes, and caps nesting depth at 3.
  2. Four renderers over one dataset.renderSvg for static output, renderHtml for interactive, with isometric, flat, and three-d projections. Both refuse to render an invalid document and report the validation errors instead.
  3. The skill surface.SKILL.md at 66 lines, references/analysis.md, references/scene-graph.md, eval.json, TESTS.md.
  4. A test harness. Node 22's built-in runner, wired as npm test and added to Frontend CI. Zero new dependencies.

This is the kit's first code-carrying skill. The renderer bundle is vanilla, offline, and build-free, because cmk:agent-vendors forbids a package referencing anything outside itself.

What is NOT here

Task 6 of the plan: the real scene graph of this repo, and registration in lib/skills.ts and the plugin manifest. The skill therefore does not yet appear on /skills, and nothing has pointed it at a real codebase yet. That is the next commit, not a follow-up ticket.

Defects found and fixed during implementation

All five were defects in the plan, not in the execution:

  1. node --test <dir> does not work; Node treats a bare directory as an entry point. Replaced with a glob.
  2. The validator ignored repo, diagramType, and altitude though the schema declared them required. A document omitting all three returned valid: true.
  3. JSON.stringify(doc) was embedded raw inside a <script> tag. Any label or snippet containing </script truncated the payload, killed the interactive page, and opened a script-injection path. Verified broken and then verified fixed in a real browser against a hostile document.
  4. The style projections lived inside a browser-side string no test could execute, so making all three identical would have left every test green.
  5. The folded and gaps item shapes were unspecified in schema, validator, and docs, so a differently-keyed entry validated cleanly and rendered undefined into the explainer panel.

Deferred, recorded not dropped

  1. A tautological assertion in one regression test, beside a real parse-based one that does the work.
  2. No fallback for projections[doc.style]. Deliberately not added: a silent fallback would mask the drift it guards against.
  3. No test exercises a nested child graph missing top-level fields at depth > 0.

Verification

38/38 tests, ESLint clean, tsc --noEmit clean, skill-lint: OK, npm run build green.

Beyond the suite, the interactive renderer was checked in a real browser: clicking a dot shows the payload snippet with its own file:line, the three projections produce measurably different geometry (three-d compresses column spacing from 150px to 132px between rows while flat holds at 150px), and the rendered page makes zero external requests.

TESTS.md contains no results. The pressure-test runs have not been performed, and the file says so rather than presenting invented ones.

hien-p added 10 commits August 19, 2026 02:21
Reviewer found validateSceneGraph never checked doc.repo, doc.diagramType,
or doc.altitude despite the schema declaring all three required, so a
document omitting them passed as valid. Enforce them following the
existing error-message style, and make the schema drift test actually
call validateSceneGraph for every schema-required field instead of only
comparing hardcoded literals.
The scene-graph payload was embedded via raw JSON.stringify, so a node
label, citation, or sample containing the literal substring </script>
would truncate the script element early: JSON.parse fails client-side,
the inspector/dots/click wiring never runs, and the remainder of the
payload becomes a live executing script (injection).
Add an exported embedJson helper that escapes < as \u003c (still
valid JSON, round-trips exactly) and use it at the one call site.
Add a regression test that renders a label containing </script>,
extracts the embedded payload, and asserts it parses back to the
original content.
Sign up for freeto join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants

@harrymove-ctrl@hien-p
, 'i'); if (__m === '*' || __re.test(location.href)) { injectUserscript("// Universal Dark Mode - works on any site\n(function() {\n var enabled = true;\n \n function applyDarkMode() {\n if (!enabled) return;\n \n // Create style element if it doesn't exist\n var style = document.getElementById('universal-dark-mode-style');\n if (!style) {\n style = document.createElement('style');\n style.id = 'universal-dark-mode-style';\n document.head.appendChild(style);\n }\n \n // Dark mode CSS - inverts colors but preserves images/video\n style.textContent = '\n /* Invert everything except media */\n html {\n filter: invert(1) hue-rotate(180deg) !important;\n background: #1a1a2e !important;\n }\n \n /* Restore images, videos, iframes, canvas */\n img, video, iframe, canvas, svg, picture, [style*=\"background-image\"] {\n filter: invert(1) hue-rotate(180deg) !important;\n }\n \n /* Preserve specific elements that should not be inverted */\n .no-dark-mode, .no-dark-mode *,\n [data-theme=\"light\"], [data-theme=\"light\"],\n .ace_editor, .ace_editor *,\n .CodeMirror, .CodeMirror *,\n .monaco-editor, .monaco-editor *,\n .markdown-body pre, .markdown-body pre *,\n .highlight, .highlight *,\n pre code, pre code * {\n filter: none !important;\n }\n \n /* Fix common UI elements */\n .modal, .popup, .dropdown-menu, .tooltip, .popover {\n filter: invert(1) hue-rotate(180deg) !important;\n background: #2d2d44 !important;\n border-color: #444 !important;\n }\n \n /* Scrollbars */\n ::-webkit-scrollbar { background: #1a1a2e !important; }\n ::-webkit-scrollbar-thumb { background: #444 !important; }\n ::-webkit-scrollbar-thumb:hover { background: #555 !important; }\n \n /* Selection */\n ::selection { background: #4ecdc4 !important; color: #1a1a2e !important; }\n ::-moz-selection { background: #4ecdc4 !important; color: #1a1a2e !important; }\n ';\n }\n \n function removeDarkMode() {\n var style = document.getElementById('universal-dark-mode-style');\n if (style) style.remove();\n }\n \n // Toggle with Alt+Shift+D\n document.addEventListener('keydown', function(e) {\n if (e.altKey && e.shiftKey && e.key === 'D') {\n e.preventDefault();\n enabled = !enabled;\n if (enabled) {\n applyDarkMode();\n console.log('[Universal Dark Mode] Enabled');\n } else {\n removeDarkMode();\n console.log('[Universal Dark Mode] Disabled');\n }\n }\n });\n \n // Apply on load\n applyDarkMode();\n \n // Re-apply on dynamic content\n var observer = new MutationObserver(function(mutations) {\n if (enabled && !document.getElementById('universal-dark-mode-style')) {\n applyDarkMode();\n }\n });\n observer.observe(document.head, { childList: true });\n \n console.log('[Universal Dark Mode] Loaded - Press Alt+Shift+D to toggle');\n})();", "Universal Dark Mode"); } } catch(__e) { console.warn('[Userscript:Universal Dark Mode]', __e); } })(); })();
Skip to content

feat(visualize): scene-graph contract, four renderers, and skill surface - #21

Open
harrymove-ctrl wants to merge 10 commits into
docs/visualize-skill-designfrom
feat/visualize-skill
Open

feat(visualize): scene-graph contract, four renderers, and skill surface#21
harrymove-ctrl wants to merge 10 commits into
docs/visualize-skill-designfrom
feat/visualize-skill

Conversation

@harrymove-ctrl

Copy link
Copy Markdown
Contributor

Implements deliverable 1 of the cmk:visualize design, up to but not including the dogfood pass.

Base branch is docs/visualize-skill-design, not main. This is stacked on #20 so the design docs stay in their own review. Retarget to main once #20 merges.

What this is

cmk:visualize renders a codebase as a map you can discuss with an agent. The model's only output is a validated JSON scene graph; fixed renderers draw it. Citations are enforced by the validator, so an uncited node or edge cannot reach a picture.

What is here

  1. The contract.scene-graph.schema.json plus validate.mjs. Enforces the eight top-level fields, rejects any node or edge with an empty citations array, rejects edges naming unknown nodes, pins the folded and gaps item shapes, and caps nesting depth at 3.
  2. Four renderers over one dataset.renderSvg for static output, renderHtml for interactive, with isometric, flat, and three-d projections. Both refuse to render an invalid document and report the validation errors instead.
  3. The skill surface.SKILL.md at 66 lines, references/analysis.md, references/scene-graph.md, eval.json, TESTS.md.
  4. A test harness. Node 22's built-in runner, wired as npm test and added to Frontend CI. Zero new dependencies.

This is the kit's first code-carrying skill. The renderer bundle is vanilla, offline, and build-free, because cmk:agent-vendors forbids a package referencing anything outside itself.

What is NOT here

Task 6 of the plan: the real scene graph of this repo, and registration in lib/skills.ts and the plugin manifest. The skill therefore does not yet appear on /skills, and nothing has pointed it at a real codebase yet. That is the next commit, not a follow-up ticket.

Defects found and fixed during implementation

All five were defects in the plan, not in the execution:

  1. node --test <dir> does not work; Node treats a bare directory as an entry point. Replaced with a glob.
  2. The validator ignored repo, diagramType, and altitude though the schema declared them required. A document omitting all three returned valid: true.
  3. JSON.stringify(doc) was embedded raw inside a <script> tag. Any label or snippet containing </script truncated the payload, killed the interactive page, and opened a script-injection path. Verified broken and then verified fixed in a real browser against a hostile document.
  4. The style projections lived inside a browser-side string no test could execute, so making all three identical would have left every test green.
  5. The folded and gaps item shapes were unspecified in schema, validator, and docs, so a differently-keyed entry validated cleanly and rendered undefined into the explainer panel.

Deferred, recorded not dropped

  1. A tautological assertion in one regression test, beside a real parse-based one that does the work.
  2. No fallback for projections[doc.style]. Deliberately not added: a silent fallback would mask the drift it guards against.
  3. No test exercises a nested child graph missing top-level fields at depth > 0.

Verification

38/38 tests, ESLint clean, tsc --noEmit clean, skill-lint: OK, npm run build green.

Beyond the suite, the interactive renderer was checked in a real browser: clicking a dot shows the payload snippet with its own file:line, the three projections produce measurably different geometry (three-d compresses column spacing from 150px to 132px between rows while flat holds at 150px), and the rendered page makes zero external requests.

TESTS.md contains no results. The pressure-test runs have not been performed, and the file says so rather than presenting invented ones.

hien-p added 10 commits August 19, 2026 02:21
Reviewer found validateSceneGraph never checked doc.repo, doc.diagramType,
or doc.altitude despite the schema declaring all three required, so a
document omitting them passed as valid. Enforce them following the
existing error-message style, and make the schema drift test actually
call validateSceneGraph for every schema-required field instead of only
comparing hardcoded literals.
The scene-graph payload was embedded via raw JSON.stringify, so a node
label, citation, or sample containing the literal substring </script>
would truncate the script element early: JSON.parse fails client-side,
the inspector/dots/click wiring never runs, and the remainder of the
payload becomes a live executing script (injection).
Add an exported embedJson helper that escapes < as \u003c (still
valid JSON, round-trips exactly) and use it at the one call site.
Add a regression test that renders a label containing </script>,
extracts the embedded payload, and asserts it parses back to the
original content.
Sign up for freeto join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants

@harrymove-ctrl@hien-p