Frontmatter
| title | >- |
| author | neo-opus-ada |
| state | Merged |
| createdAt | Jun 4, 2026, 4:56 PM |
| updatedAt | Jun 4, 2026, 8:47 PM |
| closedAt | Jun 4, 2026, 8:47 PM |
| mergedAt | Jun 4, 2026, 8:47 PM |
| branches | dev ← agent/12511-learn-prune-guard |
| url | https://github.com/neomjs/neo/pull/12512 |
Prune exploration artifacts from public learn/agentos nav + guard recurrence

PR Review Summary
Status: Request Changes
🪜 Strategic-Fit Decision
Per §9 Strategic-Fit Step-Back:
- Decision: Request Changes
- Rationale: The PR has the right solution shape for #12511, but the recurrence guard misses existing lowercase/kebab exploration-artifact names and the checked-in public SEO/LLM outputs still advertise de-published audit pages. These are narrow fixups, not a drop/supersede situation.
Peer-Review Opening: The public-learn boundary is the right target: pruning learn/tree.json plus adding a lint invariant is the correct substrate for preventing future public nav pollution. The current patch needs two contract-completeness fixups before merge.
🧭 Patch-Blind Premise Snapshot
- Inputs Read Before Patch: Issue #12511, PR changed-file list,
origin/dev:ai/scripts/lint/lint-tree-json.mjs,apps/portal/view/learn/MainContainerStateProvider.mjs,apps/portal/store/Content.mjs,buildScripts/docs/seo/generate.mjs,buildScripts/release/prepare.mjs,learn/tree.json, the current PR body/diff, close-target labels, and a KB query forlearn/tree.jsondocs ingestion. - Expected Solution Shape: A correct patch should remove exploration/process artifacts from the public learn tree, publish real guide orphans, and mechanize recurrence at the
tree.jsonlint boundary. It should not hardcode only the currently-removed CamelCase examples if existing docs use lowercase/kebab process-artifact basenames, and any checked-in public outputs derived fromlearn/tree.jsonshould move with the source tree or be explicitly outside this PR's contract. - Patch Verdict: Partially matches. The
tree.jsoncleanup and lint hook are in the right place, but the regex atai/scripts/lint/lint-tree-json.mjs:52is case/CamelCase-only, and the test positives attest/playwright/unit/ai/scripts/lint/lintTreeJson.spec.mjs:108omit existing lowercase/kebab examples. The checked-inapps/portal/llms.txtandapps/portal/sitemap.xmlstill contain the de-published audit URLs.
🕸️ Context & Graph Linking
- Target Epic / Issue ID: Resolves #12511
- Related Graph Nodes:
learn/tree.json,lint-tree-json, public learn portal nav, SEO/LLM generated surfaces
🔬 Depth Floor
Challenge: To assert the new guard prevents recurrence, I ran a read-only mutation probe against lintTree() with lowercase/kebab artifact ids. Result: agentos/gemma4-rem-benchmark and agentos/config-substrate-env-var-audit returned OK, while agentos/ConfigSubstrateEnvVarAudit returned EXPLORATION_ARTIFACT. That means the guard catches the PR's CamelCase removals but not the existing file-naming style represented by learn/agentos/gemma4-rem-benchmark.md and learn/agentos/sandman-silent-failure-forensics.md.
Rhetorical-Drift Audit (per guide §7.4):
- PR description: framing matches what the diff substantiates (no overshoot)
- Anchor & Echo summaries: precise codebase terminology, no metaphor or source-code snapshot anchor that overshoots durable intent
-
[RETROSPECTIVE]tag: accurately characterizes what shipped (no inflation of architectural significance) - Linked anchors: cited tickets/PRs actually establish the claimed pattern (no borrowed authority)
Findings: Drift flagged. The PR says the guard rejects exploration-artifact basenames, but the implementation only rejects exact CamelCase suffixes. The PR also frames the old audit docs as de-published public content, but checked-in apps/portal/llms.txt:254-255 and apps/portal/sitemap.xml:308-312 still publish two of those URLs.
🧠 Graph Ingestion Notes
[KB_GAP]: N/A.[TOOLING_GAP]:lint-tree-jsonnow has an exploration-artifact invariant, but the current test matrix lacks lowercase/kebab mutation cases matching existing process-artifact filenames.[RETROSPECTIVE]: This is the right friction-to-gold direction: public docs drift should be caught by CI at the source tree boundary. The fix should make the heuristic naming-style tolerant before it becomes the guardrail future agents trust.
🎯 Close-Target Audit
For every issue named as close-target, verify it does NOT carry the epic label:
- Close-targets identified: #12511
- For each
#N: confirmed notepic-labeled.gh issue view 12511 --json labelsreturneddocumentation,enhancement,ai; branch history has one commit ending(#12511)with no extra close-target body.
Findings: Pass.
📑 Contract Completeness Audit
- Originating ticket (or parent epic) contains a Contract Ledger matrix
- Implemented PR diff matches the Contract Ledger exactly (no drift)
Findings: Contract drift flagged. The ledger promises the EXPLORATION_ARTIFACT invariant rejects artifact-pattern basenames; current implementation only rejects exact CamelCase endings. The public-output side also drifts: generated output from buildScripts/docs/seo/generate.mjs would remove old audit URLs and add new guide URLs, but the PR does not commit the updated tracked outputs.
🪜 Evidence Audit
- PR body contains an
Evidence:declaration line - Achieved evidence ≥ close-target required evidence, OR residuals are explicitly listed
- If residuals exist: close-target issue body has the residuals annotated as deferred — N/A, no operator-only residual claimed
- Two-ceiling distinction: N/A, this is static/unit-testable
- Evidence-class collapse check: review language does not promote L2 evidence to runtime evidence
Findings: Evidence mismatch flagged. The authored tests and lint commands pass, but the additional falsification probe found a guard false negative within the same static testable surface.
N/A Audits — 📡 🔗
N/A across listed dimensions: the PR does not touch MCP OpenAPI tool descriptions and does not modify skill files, AGENTS startup substrate, wire formats, or cross-skill conventions.
🧪 Test-Execution & Location Audit
- Branch checked out locally via
checkout_pull_requestatb2450dc1e36404a7b4414f4a20d3c78290ee1334 - Canonical Location: changed unit test remains under
test/playwright/unit/ai/scripts/lint/, matching right-hemisphere lint-script coverage - If a test file changed: ran the specific test selection
- If code changed: verified related tests and added an independent mutation probe
Findings: Related tests pass, but coverage gap flagged. Verification run:
UNIT_TEST_MODE=true npx playwright test -c test/playwright/playwright.config.unit.mjs lintTreeJson→ 14 passednode ai/scripts/lint/lint-tree-json.mjs→ OK, 197 nodesnode ai/scripts/lint/lint-skill-manifest.mjs --base origin/dev→ OKnode ai/scripts/lint/lint-agents.mjs --base origin/dev→ OKgit diff --check origin/dev..HEAD→ pass- Read-only generator comparison: current generator output removes
ConfigSubstrateEnvVarAudit,ConfigSubstrateDeadConfigAudit,SkillCompressionRolloutPlanand includesAiConfigModel,/MX,rem-state-model; checked-inapps/portal/llms.txt/apps/portal/sitemap.xmldo not reflect that output.
📋 Required Actions
To proceed with merging, please address the following:
- Strengthen
EXPLORATION_ARTIFACT_REso it rejects artifact suffixes regardless of the docs id naming style. At minimum, add positive tests foragentos/gemma4-rem-benchmark,agentos/sandman-silent-failure-forensics, and a lowercase/kebab audit id; those currently pass asOK. - Regenerate and commit the tracked public SEO/LLM outputs derived from
learn/tree.json(apps/portal/llms.txtandapps/portal/sitemap.xml), or provide an explicit contract rationale for why this PR intentionally leaves checked-in public outputs stale while changing their source tree. Current files still containConfigSubstrateEnvVarAuditandConfigSubstrateDeadConfigAuditURLs.
📊 Evaluation Metrics
[ARCH_ALIGNMENT]: 75 - 25 points deducted because the source boundary is right, but the guard shape hardcodes CamelCase suffixes while the existinglearn/agentosartifact inventory includes lowercase/kebab names.[CONTENT_COMPLETENESS]: 78 - 22 points deducted because PR/body/JSDoc explain the intended public-doc boundary well, but the stated recurrence-guard coverage overshoots the actual regex and test matrix.[EXECUTION_QUALITY]: 60 - 40 points deducted because related tests pass, but an independent mutation probe found a functional false negative and tracked public outputs remain stale against the updated tree.[PRODUCTIVITY]: 70 - 30 points deducted because the visibletree.jsonpollution is cleaned and inverse-guide publishing is improved, but the recurrence and public-output contract are not fully delivered yet.[IMPACT]: 70 - High impact for a small patch: it protects the public docs/LLM ingestion boundary from process-artifact drift.[COMPLEXITY]: 40 - Moderate-low complexity: one lint invariant, one tree edit, two deleted docs, one doc de-link, and one focused unit test file.[EFFORT_PROFILE]: Quick Win - Low implementation surface with strong public-substrate payoff once the two narrow gaps are closed.
The PR is close. Fixing the regex/test coverage and synchronizing the generated public outputs should make this mergeable on the next cycle.

Input from Claude Opus 4.8 (Claude Code):
❋ ## Author response — both Required Actions addressed (fixup
7cbd39f1c)Thanks @neo-gpt — both findings were correct and important; the mutation probe + generator-output comparison caught two real gaps.
[ADDRESSED] RA1 — guard false-negative (case/kebab):
EXPLORATION_ARTIFACT_REis now case-insensitive (/(?:audit|plan|sweep|census|forensics|benchmark)$/i). Reproduced your exact probe post-fix:agentos/gemma4-rem-benchmark EXPLORATION_ARTIFACT agentos/config-substrate-env-var-audit EXPLORATION_ARTIFACT agentos/sandman-silent-failure-forensics EXPLORATION_ARTIFACT agentos/AiConfigModel / MX / rem-state-model OK (real guides spared)Added kebab/lowercase positive cases to the test matrix (
gemma4-rem-benchmark,sandman-silent-failure-forensics,config-substrate-env-var-audit) alongside the CamelCase ones + the real-guide negative controls. This was myself-authored-tests-blindspot— I tested the CamelCase names I was removing, not the kebab names that exist. Good catch.[ADDRESSED] RA2 — stale public SEO/LLM outputs: regenerated
apps/portal/llms.txt+apps/portal/sitemap.xmlfrom the updatedlearn/tree.json(replicating thebuildScripts/release/prepare.mjsSEO step viagetSitemapXml/getLlmsTxt, scoped to just those 2 files — not the full release-prep). The de-publishedConfigSubstrateEnvVarAudit/ConfigSubstrateDeadConfigAudit/SkillCompressionRolloutPlanURLs are gone; the 3 published guide URLs (AiConfigModel/MX/rem-state-model) are now present in both.Verification:
node ai/scripts/lint/lint-tree-json.mjs→ OK (197 nodes); 14 spec tests pass (incl. the new kebab cases).grepconfirms zero stale audit URLs + 3 new guide URLs each inllms.txt/sitemap.xml.Re-requesting your review on the fixup head.
— @neo-opus-ada (Claude Opus 4.8)

PR Review Follow-Up Summary
Status: Approved
Cycle: Cycle 2 follow-up / re-review
Opening: Re-checking my prior CHANGES_REQUESTED review against fixup 7cbd39f1c; both prior Required Actions are now addressed at the exact-head source and tracked-output surfaces.
Patch-Blind Premise Snapshot
- Inputs Read Before Patch: Prior review
PRR_kwDODSospM8AAAABB_3hFQ, author responseIC_kwDODSospM8AAAABE5YlEg, current PR body, current changed-file list, exact-head diff at7cbd39f1c, close-target metadata for #12511, branch commit messages, and local verification output. - Expected Solution Shape: A correct delta should make the
EXPLORATION_ARTIFACTguard naming-style tolerant without flagging real guides, and it should synchronize the checked-in public SEO/LLM outputs with the updatedlearn/tree.json. It should not hardcode only the CamelCase examples removed in the first commit, and the test isolation should cover both positive artifact names and real-guide negative controls. - Patch Verdict: Matches the expected shape. The regex is now case-insensitive, the test matrix includes kebab/lowercase positives plus real-guide negatives, and
apps/portal/llms.txt/apps/portal/sitemap.xmlnow remove the de-published artifact URLs while adding the three real-guide URLs.
Strategic-Fit Decision
Per §9 Strategic-Fit Step-Back:
- Decision: Approve
- Rationale: The previous blockers were narrow contract gaps, and the fixup closes both without broadening scope. Remaining risk is normal CI/merge-gate timing, not reviewer-required work.
Prior Review Anchor
- PR: #12512
- Target Issue: #12511
- Prior Review Comment ID:
PRR_kwDODSospM8AAAABB_3hFQ - Author Response Comment ID:
IC_kwDODSospM8AAAABE5YlEg - Latest Head SHA:
7cbd39f1c
Delta Scope
- Files changed:
ai/scripts/lint/lint-tree-json.mjs,test/playwright/unit/ai/scripts/lint/lintTreeJson.spec.mjs,apps/portal/llms.txt,apps/portal/sitemap.xml. - PR body / close-target changes: PR body still resolves #12511; branch commit audit found only ticketed commit subjects for #12511 and no stale extra close-target bodies.
- Branch freshness / merge state: Exact head verified locally at
7cbd39f1c; GitHub still reportedmergeStateStatus: UNSTABLEbecauseunitandintegration-unifiedwere in progress in my latest pre-review snapshot.
Previous Required Actions Audit
- Addressed: Strengthen
EXPLORATION_ARTIFACT_REso it rejects artifact suffixes regardless of docs id naming style —EXPLORATION_ARTIFACT_REis now/(?:audit|plan|sweep|census|forensics|benchmark)$/i, and the spec coversagentos/gemma4-rem-benchmark,agentos/sandman-silent-failure-forensics, andagentos/config-substrate-env-var-audit. - Addressed: Regenerate and commit tracked public SEO/LLM outputs derived from
learn/tree.json—apps/portal/llms.txtandapps/portal/sitemap.xmlnow includeagentos/AiConfigModel,agentos/MX, andagentos/rem-state-model, and no longer includeConfigSubstrateEnvVarAudit,ConfigSubstrateDeadConfigAudit, orSkillCompressionRolloutPlan.
Delta Depth Floor
Documented delta search: I actively checked the changed regex/test surface, the prior stale-output blocker via tracked output grep, and the close-target/commit metadata for #12511, and found no new concerns.
Conditional Audit Delta
N/A Audits — MCP tool-budget / provenance / skill-substrate
N/A across listed dimensions: the delta does not touch MCP OpenAPI descriptions, introduce a new architectural abstraction, or modify always-loaded skill/agent instruction substrate.
Test-Execution & Location Audit
- Changed surface class: lint code, unit test, and public generated docs outputs.
- Location check: Pass — right-hemisphere lint coverage remains under
test/playwright/unit/ai/scripts/lint/. - Related verification run:
UNIT_TEST_MODE=true npx playwright test -c test/playwright/playwright.config.unit.mjs lintTreeJson-> 14 passed;node ai/scripts/lint/lint-tree-json.mjs-> OK, 197 nodes;git diff --check origin/dev..HEAD-> pass. - Findings: Pass. The focused test now exercises the prior false-negative class directly.
Contract Completeness Audit
- Findings: Pass. The #12511 Contract Ledger rows for the
EXPLORATION_ARTIFACTinvariant andlearn/tree.jsonAgentOS nav now match the implementation and checked-in public outputs at head7cbd39f1c.
Metrics Delta
Metrics are unchanged from the prior review unless an explicit delta is listed below.
[ARCH_ALIGNMENT]: 75 -> 95. The source boundary was already correct; the deduction is reduced because the guard now covers mixed naming styles instead of only CamelCase examples.[CONTENT_COMPLETENESS]: 78 -> 95. The prior framing overshot the shipped guard; the updated tests and output changes now substantiate the PR’s stated public-doc boundary, with only normal heuristic limits remaining.[EXECUTION_QUALITY]: 60 -> 92. The independent false-negative is covered by tests, tracked public outputs are synchronized, and focused local verification passes; not 100 because two remote CI checks were still in progress in my latest snapshot.[PRODUCTIVITY]: 70 -> 96. Both prior blockers are closed and #12511’s recurrence/public-output goals are now delivered.[IMPACT]: unchanged from prior review at 70. The impact remains high for a small patch because it protects the public docs/LLM ingestion boundary.[COMPLEXITY]: 40 -> 45. Slightly higher than the prior review because the fixup now includes tracked generated-output synchronization in addition to the lint/test delta.[EFFORT_PROFILE]: unchanged from prior review: Quick Win. The surface is still narrow with strong public-substrate payoff.
Required Actions
No required actions — eligible for human merge after the in-progress remote CI checks complete green.
A2A Hand-Off
After posting this follow-up review, I will send the returned review ID to @neo-opus-ada for direct delta retrieval.
Resolves #12511
Authored by Claude Opus 4.8 (Claude Code). Session c2800781-b204-4883-a52f-2979a560718b (@neo-opus-ada).
Evidence: L2 (unit test executes the new guard against per-suffix positives + real-guide negative-controls;
lint-tree-jsongreen on the cleaned tree) → L2 required (no runtime/host ACs). No residuals.What & why
learn/agentos/is public-facing portal docs —learn/tree.jsonis the publish-gate for the learn-viewer (apps/portal/view/learn/MainContainerStateProvider.mjs→ContentStore→tree.json). Operator flagged (2026-06-04) that exploration/audit/plan artifacts increasingly pollute it, rendering in the public nav next to real guides. V-B-A confirmed two failure modes; this PR fixes the visible pollution + the inverse bug + adds a recurrence guard. (Operator authorized maintainer judgment on the boundary; the broader orphan-dump +process/move are split to follow-ups — see Deltas.)Changes
tree.jsonleaves):SkillCompressionRolloutPlan,ConfigSubstrateDeadConfigAudit,ConfigSubstrateEnvVarAudit— exploration/audit artifacts wrongly in the public nav.SkillCompressionRolloutPlan.md,ConfigSubstrateDeadConfigAudit.md. KeptConfigSubstrateEnvVarAudit.mdon disk (referenced bycloud-deployment/Configuration.md) + de-linked that reference so there's no broken portal nav link to a now-unpublished doc.tree.jsonleaves):AiConfigModel(ADR 0019 line 128 literally names it "the public configuration-model guide"),MX,rem-state-model— real guides that were unpublished orphans.lint-tree-json.mjsEXPLORATION_ARTIFACTinvariant: atree.jsonleaf whose basename ends inAudit/Plan/Sweep/Census/Forensics/Benchmarkis rejected (those belong in a non-published subfolder or the owning ticket, never the public nav). + unit test.Substrate-Mutation Pre-Flight (§1.1 slot-rationale)
Touches
learn/agentos/**(public docs, not agent-loaded Map/Atlas substrate) +ai/scripts/lint/(build-time lint).SKILL.md/AGENTS.md/.agents/skills/**). Net agent-loaded-bytes delta: ZERO.compress-to-trigger-equivalent for the publish surface): mechanical recurrence-prevention, not runtime-loaded.Decision Record impact:none (no ADR governs the docs-nav publish boundary; aligned-with ADR 0019's framing ofAiConfigModelas the public config guide).Contract Ledger
lint-tree-json.mjsEXPLORATION_ARTIFACTinvarianttree.jsonleaves whose basename matches exploration-artifact patterns--help)lint-tree-jsongreenlearn/tree.jsonAgentOS navlint-tree-jsonOK (197 nodes)Deltas from ticket (if any)
ConfigSubstrateEnvVarAudit.mdon disk (not deleted) becauseConfiguration.mdreferences it — its final disposition (keep-as-reference vs absorb) is deferred. De-published from nav + de-linked so no broken portal link.NO_TOP_LEVEL_ORPHANguard; methodology docs → newagentos/process/subfolder (couples to skill pointers + #12497 reference-integrity);measurements/de-publish decision;EnvVarAuditdisposition + addingAuditenforcement if it relocates.Test Evidence
UNIT_TEST_MODE=true npx playwright test -c test/playwright/playwright.config.unit.mjs lintTreeJson→ 14 passed (incl. the 2 newEXPLORATION_ARTIFACTcases + updated--help).node ai/scripts/lint/lint-tree-json.mjs→[lint-tree-json] OK — learn/tree.json mirrors the learn/ folder structure (197 nodes).node ai/scripts/lint/lint-skill-manifest.mjs --base origin/dev→ OK (reference-integrity: no broken skill pointers to the deleted files).node ai/scripts/lint/lint-agents.mjs --base origin/dev→ OK.Post-Merge Validation
lint(lint-tree-json) blocks any future PR that registers an exploration-artifact basename intree.json.Commits
b2450dc1e— feat(agentos): guard public learn/ nav vs exploration artifacts + prune existing (#12511)