Two sessions. Two LLMs. One recurring pattern — and a hard systemic lesson.
On May 29, 2026, two agent sessions ran against the same ai-agent-skills repository, driven by different LLMs in different agent environments. One methodically rebuilt a broken Knowledge Graph Explorer — and succeeded. The other generated a document collection from scratch — and triggered ten harness contract violations before being halted. The root cause in both cases traces to the same protocol: whether agent-rdf-memory/ was consulted before work began.
The session focused on rebuilding the KG Explorer JavaScript block and SPARQL Workbench for security-ai-agents-jonathan-jaffe-office-hours-kimi-k2.6-1.html. The existing artifact had broken under harness contract validation, and the rebuild addressed all failures methodically.
#kg-canvas { cursor: grab; } and #kg-canvas.kg-active:active { cursor: grabbing; }. The grabbing cursor only appears when zoom is armed AND the user is actively clicking — preventing confusing cursor states on hover.<a> elements with resolver-backed hrefs. Edge labels map predicate short names to full IRIs via a PREDICATE_IRIS lookup table. Replaced broken window.open() onclick handler that conflicted with D3 drag.dragStartX/Y in drag.on('start'). In drag.on('end'), compute Math.hypot(event.x - dragStartX, event.y - dragStartY). <6px → click → open resolver link. ≥6px → drag → keep node pinned.svg.on('.zoom', null)). Container click attaches zoom and adds kg-active class. Document click outside #kg-explorer detaches zoom and removes class. Visual feedback via box-shadow border glow on .kg-active.renderKG() with working render() pattern. Simulation created ONCE with d3.forceSimulation() (no data). render() filters nodes/links then calls simulation.nodes() and simulation.force('link').links(). Handles D3 source/target object mutation by checking typeof === 'object'.https://linkeddata.uriburner.com/DAV/demos/daas/{filename} in GRAPH <iri> { ... } clauses. FROM clause scopes the default graph incorrectly for this context. Verified 8 GRAPH occurrences, 0 FROM occurrences.const kgData = (\{.*?\});\s*\(\(\)=>. Comment lines between the kgData semicolon and the IIFE opening break the regex. Fix: remove all text between }; and (() => { except whitespace.| File | Type | Location |
|---|---|---|
| security-ai-agents-…-kimi-k2.6-1.html | HTML | kimi/webpages/ |
| security-ai-agents-…-kimi-k2.6-1.ttl | Turtle | kimi/rdf/ |
d3.forceSimulation() without data. In render(): filter nodes/links, then simulation.nodes(filteredNodes) and simulation.force('link').links(filteredLinks). NEVER recreate simulation in render() — this destroys all node positions.forceLink() mutates link objects: string IDs become object references after first render. When filtering links, always check typeof l.source === 'object' ? l.source.id : l.source.sparqlGraph (not sparql-graph), sparqlRecipe (not sparql-recipe), sparqlText (not sparql-query), sparqlFormat (not sparql-format), settingsPanel (not kgSettingsPanel), kgControlsToggle, data-mode='Basic' (not 'basic'), data-mode='Advanced', data-density='Core', data-density='Full'. D3 script src must contain d3@7.grep -qE with \s in ERE does not match whitespace on macOS. Workaround: add a standalone comment line # schema:hasPart : so the -A2 grep context picks up a colon-space match.text/x-html+tr and text/x-html-nice-turtle in visible HTML body — not just in select option values or JS strings. Add prose: "SELECT queries use text/x-html+tr. DESCRIBE and CONSTRUCT use text/x-html-nice-turtle."The task was to generate an HTML/MD/RDF document collection synthesizing five source articles: Anthropic's containment framework, Tunguz/Jaffe security-in-AI analysis, and OpenLink's SSI/YouID/NetID-TLS articles. The initial generation produced files — but in the wrong location, missing every required structural component, and with the wrong filename stem.
aria-label. No light/dark theme toggle in nav header bar. Not collapsed by default.html[data-theme='dark'] + @media (prefers-color-scheme: dark) dual implementation with toggle control.id=sparql-explorer, sparqlGraph, sparqlRecipe, sparqlText, sparqlFormat, Turtle/JSON-LD format tabs, and canonical SAMPLE-based entity-type query.<link rel='related'> for TTL and <link rel='alternate'> for MD in <head>. Missing schema:relatedLink and schema:encoding in embedded JSON-LD.agent-governance-ssi-mashup instead of required {slug}-{llm-id}-{n} pattern: agent-governance-ssi-claude-sonnet-1.Claude Generated/webpages/, RDF → Claude Generated/RDF/, MD → Claude Generated/md/.target='_blank' rel='noopener noreferrer'.how-we-contain-claude-anthropic_sonnet4-1.html (May 28) as template per step-kgExplorerReuse. Regenerating from scratch would reintroduce known bugs.validate-harness-contract.py not executed before declaring artifacts complete. Gate is blocking — zero failures required.agent-rdf-memory/ (core.ttl, preferences.ttl, index.ttl) before starting work. Instead it relied on the Claude Code auto-injected MEMORY.md — which is a flat index, not a queryable contract. Every preference step (output routing, template reuse, harness IDs, dark mode CSS, attribution format, and nine more) was available in preferences.ttl but never consulted.
This is the same failure recorded in 2026-05-28-deepseek_v4pro-claude_code.ttl#lesson4 — the DeepSeek session from the previous day. Three different LLMs (DeepSeek V4 Pro, Kimi K2.6, Claude Sonnet 4.6), two different agent environments (Claude Code, OpenCode), one recurring root cause.
| Requirement | Plan |
|---|---|
| KG Explorer template | Copy from how-we-contain-claude-anthropic_sonnet4-1.html (May 28, validated) |
| HTML output path | /Users/kidehen/Documents/LLMs/Claude Generated/webpages/ |
| RDF output path | /Users/kidehen/Documents/LLMs/Claude Generated/RDF/ |
| MD output path | /Users/kidehen/Documents/LLMs/Claude Generated/md/ |
| Filename stem | agent-governance-ssi-claude-sonnet-1 |
| Skills chain | kg-generator → rdf-infographic-skill |
| Validation gate | validate-harness-contract.py — zero failures required before delivery |
| Source articles | 5 (Anthropic containment + Tunguz/Jaffe + 3 OpenLink SSI) |
These two sessions tell a single story. The Kimi K2.6 session succeeded because it was a rebuild — the agent was already inside a contract violation context and worked directly against the harness validator's output. The Claude Sonnet session failed because it was a greenfield generation — the agent operated from its compressed view of the repository (MEMORY.md) rather than reading the actual RDF contracts.
The systemic fix is not per-LLM or per-environment. It is architectural: the agent-rdf-memory/ protocol must be enforced at the harness level (the agent environment's startup hook), not left to the LLM's initiative. The SESSION-START-HOOK.md file in agent-rdf-memory/ is the hook point — making it non-optional closes this gap across all LLMs and all environments.
| Field | Kimi K2.6 + OpenCode | Claude Sonnet 4.6 + Claude Code |
|---|---|---|
| Agent IRI | https://opencode.ai/#kimi-k2-6 | https://claude.ai/code#claude-sonnet-4-6 |
| Task type | Rebuild / repair | Greenfield generation (failed) → planned rebuild |
| Skills used | rdf-infographic-skill | kg-generator, rdf-infographic-skill (planned) |
| Violations | 0 (all fixed) | 10 (rebuild required) |
| Lessons encoded | 11 | 1 (root cause analysis) |
| Artifacts generated | 2 (HTML, TTL) | 3 (non-compliant HTML, MD, TTL — to be replaced) |
| Session RDF | 2026-05-29-kimi-k2_6-opencode.ttl | 2026-05-29-claude-sonnet-claude-code.ttl |