Compound Refresh Audit the learnings under against the current codebase, apply the maintenance actions the evidence supports, and deliver a complete per-doc report plus committed changes. The report and the corrected document set are the deliverables. The store only compounds value if every doc can be trusted. Mode Read now. It reads the mode off the arguments and defines what each mode may apply unattended, the stale-marking fallback, the question tools, and the bootstrap. Two rules hold in both modes. A failed write is recorded as recommended , and the run continues. And a question is asked…

\n description: \"Date documented (YYYY-MM-DD)\"\n\n problem_type:\n type: enum\n values:\n - build_error\n - test_failure\n - runtime_error\n - performance_issue\n - database_issue\n - security_issue\n - ui_bug\n - integration_issue\n - logic_error\n - developer_experience\n - workflow_issue\n - best_practice\n - documentation_gap\n - architecture_pattern\n - design_pattern\n - tooling_decision\n - convention\n description: \"Primary category — determines track (bug vs knowledge). Prefer the narrowest applicable value; best_practice is the fallback when no narrower knowledge-track value fits.\"\n\n component:\n type: string\n suggested_values:\n - data_model\n - api_layer\n - service_layer\n - background_job\n - database\n - frontend\n - messaging\n - infrastructure\n - observability\n - authentication\n - payments\n - development_workflow\n - testing_framework\n - documentation\n - tooling\n description: \"Component or area involved. Open vocabulary: choose it per the corpus-first rule in yaml-schema.md (corpus value for this area, most-used spelling when the corpus disagrees, suggested_values only when no doc covers the area; corpus values reused as spelled). A newly chosen suggested_values fallback is lowercase, underscore-separated.\"\n\n severity:\n type: enum\n values:\n - critical\n - high\n - medium\n - low\n description: \"Impact severity\"\n\n# --- Track-specific rules ----------------------------------------------------\ntrack_rules:\n bug:\n required:\n symptoms:\n type: array[string]\n min_items: 1\n max_items: 5\n description: \"Observable symptoms such as errors or broken behavior\"\n root_cause:\n type: string\n suggested_values:\n - wrong_api\n - data_integrity\n - concurrency\n - async_timing\n - memory_leak\n - config_error\n - logic_error\n - test_isolation\n - missing_validation\n - missing_permission\n - missing_workflow_step\n - inadequate_documentation\n - missing_tooling\n - incomplete_setup\n description: \"Fundamental technical cause of the problem. Open vocabulary, corpus-first rule as for component, matched by the cause itself rather than the area.\"\n resolution_type:\n type: enum\n values:\n - code_fix\n - migration\n - config_change\n - test_fix\n - dependency_update\n - environment_setup\n - workflow_improvement\n - documentation_update\n - tooling_addition\n - seed_data_update\n description: \"Type of fix applied\"\n\n knowledge:\n optional:\n applies_when:\n type: array[string]\n max_items: 5\n description: \"Conditions or situations where this guidance applies\"\n symptoms:\n type: array[string]\n max_items: 5\n description: \"Observable gaps or friction that prompted this guidance (optional for knowledge track)\"\n root_cause:\n type: string\n suggested_values:\n - wrong_api\n - data_integrity\n - concurrency\n - async_timing\n - memory_leak\n - config_error\n - logic_error\n - test_isolation\n - missing_validation\n - missing_permission\n - missing_workflow_step\n - inadequate_documentation\n - missing_tooling\n - incomplete_setup\n description: \"Underlying cause, if there is a specific one (optional for knowledge track). Open vocabulary, corpus-first rule as for component, matched by the cause itself rather than the area.\"\n resolution_type:\n type: enum\n values:\n - code_fix\n - migration\n - config_change\n - test_fix\n - dependency_update\n - environment_setup\n - workflow_improvement\n - documentation_update\n - tooling_addition\n - seed_data_update\n description: \"Type of change, if applicable (optional for knowledge track)\"\n\n# --- Fields optional for BOTH tracks ----------------------------------------\noptional_fields:\n related_components:\n type: array[string]\n description: \"Other components involved\"\n\n tags:\n type: array[string]\n max_items: 8\n description: \"Search keywords, lowercase and hyphen-separated\"\n\n retire_when:\n type: string\n description: \"The change outside the repo that would retire this learning, and how a refresh can check for it without changing the repo, e.g. \\\"example-org/sdk#1234 closed as fixed in a released sdk version; check the issue and the sdk release notes\\\". Set it only when the guidance holds just while something outside the repo holds: an open upstream bug, a tool or platform version, a dependency's behavior. Omit it otherwise. A verification that needs a repo change, such as removing a workaround and rerunning CI, belongs in the body as the step before removal.\"\n\n# --- Fields optional for bug track only -------------------------------------\nbug_optional_fields:\n framework_version:\n type: string\n description: \"Framework or runtime name and version the bug was observed on, e.g. \\\"rails 7.1.2\\\" or \\\"node 22.4.0\\\". Only relevant for bug-track docs.\"\n\n# --- Backward compatibility --------------------------------------------------\n# Docs created before the track system was introduced may have bug-track\n# fields (symptoms, root_cause, resolution_type) on knowledge-type\n# problem_types. These are valid legacy docs:\n# - Bug-track fields present on a knowledge-track doc are harmless. Do not\n# strip them during refresh unless the doc is being rewritten for other reasons.\n# - When creating NEW docs, follow the track rules above.\n# Docs written before component/root_cause became open vocabulary may carry\n# values from the earlier closed list (rails_*, hotwire_turbo, missing_include,\n# ...) or a rails_version field. They stay valid; the corpus-first rule means a\n# repo whose docs consistently use those values keeps using them.\n\n# --- Validation rules --------------------------------------------------------\nvalidation_rules:\n - \"Determine track from problem_type using the tracks section above\"\n - \"All shared required_fields must be present\"\n - \"Bug-track required fields (symptoms, root_cause, resolution_type) must be present on bug-track docs\"\n - \"Knowledge-track docs have no additional required fields beyond the shared ones\"\n - \"Bug-track fields on existing knowledge-track docs are harmless (see backward compatibility note)\"\n - \"Track-specific optional fields may be included but are not required\"\n - \"Enum fields (problem_type, severity, resolution_type) must match allowed values exactly\"\n - \"Open-vocabulary fields (component, root_cause) follow the corpus-first rule in yaml-schema.md: component is matched by area (the value existing docs under \u003croot>/solutions/ use for that area, most-used spelling when existing docs disagree), root_cause is matched by the cause itself (the value existing docs use for that same cause, most-used spelling when existing docs disagree), suggested_values only when no existing doc covers the area (component) or names the cause (root_cause). Do not coin a near-synonym of a value the corpus already uses\"\n - \"Array fields must respect min_items/max_items when specified\"\n - \"date must match YYYY-MM-DD format\"\n - \"framework_version, if provided, only applies to bug-track docs\"\n - \"retire_when is optional on both tracks; when present it is one string, and a doc without it stays valid\"\n - \"tags should be lowercase and hyphen-separated\"\n - \"Array-of-strings frontmatter items (symptoms, applies_when, tags, related_components, or any future array field) must be wrapped in double quotes when the value starts with a YAML reserved indicator (`, [, *, &, !, |, >, %, @, ?) or contains the substring `: ` — otherwise strict YAML parsers reject the file\"\n","content_type":"application/yaml; charset=utf-8","language":"yaml","size":9756,"content_sha256":"3adbcdcebe83593830769ca7b22103e72df82bda3b626f503d8fa2a6b20e8b97"},{"filename":"references/scope.md","content":"# Scope selection and triage\n\nFind all `.md` files under `\u003croot>/solutions/`, excluding `README.md` files and anything under `_archived/` (if `_archived/` exists, flag it in the report as legacy to clean up). READMEs are excluded as review *candidates* only: whenever an action deletes, renames, moves, consolidates, or replaces a doc a catalog README lists, update that README's rows mechanically as part of the action's cleanup.\n\nWords that describe the run rather than name a doc, category, module, or keyword are not a scope hint: an operation word (`refresh`, `audit`, `check`), a cleanup or drift-only request, or a mode token. Remove them first; the remainder is the hint, and an empty remainder means the whole store.\n\nIf a scope argument was provided, narrow with the first strategy that produces results: subdirectory name → frontmatter (`module`/`component`/`tags`) → filename → content keyword. No matches: ask the user to clarify (interactive) or report the miss and exit (non-interactive).\n\nIf the store is empty, report:\n\n```text\nNo candidate docs found in \u003croot>/solutions/.\nRun /ce-compound after solving problems to start building your knowledge base.\n```\n\nFor a broad sweep (9+ docs), triage before deep investigation: read all frontmatter, cluster by module/category, spot-check whether primary referenced files still exist, and start with the highest-impact cluster (interactive: confirm the starting area with the user; non-interactive: process all clusters in impact order). Review individual learning docs before the pattern docs that depend on them — stale learnings make a pattern look more valid than it is. If the user named a pattern doc, you may start there, but inspect its supporting learnings before changing it.\n\nRender that last line for the active harness: `/ce-compound` by default, `$ce-compound` on Codex or another host documenting dollar-prefixed skill invocation. Print one form only.\n","content_type":"text/markdown; charset=utf-8","language":"markdown","size":1935,"content_sha256":"4946f9e78af90839530ec61cdf92ab4d808742111a7c9290b30a18e59f4441f5"},{"filename":"references/worth-audit.md","content":"# Worth audit\n\nThis adds one test to classification, plus changes to `CODING_STANDARDS.md`. The five outcomes and the investigation roles are unchanged. This audit adds no confirmation in either mode, because each change carries its evidence and version control can restore it.\n\n## The bar\n\n\u003c!-- ce-durable-bar:start -->\nA learning earns its place only when it holds durable project reasoning that is not readily recoverable from the final code, tests, types, comments, or existing documentation, and losing it would plausibly cause recurrence, material risk, or substantial rediscovery. Apply this counterfactual: if the learning document disappeared, would a future engineer reading the final implementation still be likely to repeat the mistake or redo substantial investigation? Completion, effort, and diff size do not establish eligibility.\n\u003c!-- ce-durable-bar:end -->\n\nThis is the bar `ce-compound` applies before writing a learning. This audit applies it to learnings that were written before the bar existed, or that accreted past it.\n\n## Recoverability needs positive evidence\n\nA doc's reasoning is recoverable only when a named in-repo artifact states it in its own text: a test or lint rule whose assertion, comment, or failure message carries the rule, a condition in `CODING_STANDARDS.md`, a code comment beside the mechanism, the project's always-loaded instructions, a skill reference, or another surviving learning. Topical overlap is not coverage; verify the specific reasoning is present and quote it. The unverifiable-is-not-false rule in `references/classify.md` still holds: a claim no artifact corroborates is kept, never treated as recoverable. A doc describing a mechanism that no longer exists is judged by the ordinary Delete gate, not by this audit.\n\nAdd this clause to every investigation subagent prompt, verbatim:\n\n> For each claim the learning makes that a reader would need in order to avoid repeating a mistake or redoing an investigation, search the repository for an in-repo artifact whose own text states that reasoning (a test or lint rule, a `CODING_STANDARDS.md` condition, a code comment, the root agent-instructions file, a skill reference, another learning). Return, per claim: recoverable with the artifact path and the quoted sentence, or not recoverable. Do not infer coverage from a related file name or topic.\n\n## Routing\n\nApply the accuracy classification first, then the worth test to docs that survived it:\n\n- **Every claim recoverable, citations absent or decorative:** Delete, with the citation cleanup the Delete flow already owns. The quoted artifacts are the doc's evidence bullets.\n- **Some claims recoverable:** Update. Cut the recoverable content and keep the measured facts, cross-file invariants, and rejected alternatives nothing else records. Point at the artifact in one line where a reader would otherwise look for the cut material. Narrow the frontmatter to match.\n- **Nothing recoverable:** Keep.\n\nA doc whose only remaining content is a session narrative, a list of what was changed, or a restatement of a contract another file owns has no non-recoverable claim and routes to Delete.\n\nApply these in both modes. Batch broad interactive sweeps as `references/classify.md` already directs. Inbound links still gate a Delete: when another doc substantively cites this one, keep it and report that.\n\n## Standards\n\nRead the `CODING_STANDARDS.md` files that govern the scope. A rule is not a doc, so it gets no Keep or Update outcome; it appears in the report with its evidence.\n\n- **A check now covers the rule's whole class:** remove the rule. Quote the rule and the check.\n- **A check covers part of the class:** narrow the rule to what remains, and quote both.\n- **A doc is really an unenforced rule:** it is a standing always-or-never about a defect a reviewer can see in a diff, it carries no reasoning beyond the rule, and no check covers it. When a check could hold it, leave the doc and record the check under **Recommended**, because this skill writes no checks. When no check could hold it and the bar below is met, add one condition to the `CODING_STANDARDS.md` nearest the code, in that file's style, then route the doc as recoverable. When the repo has no standards file, leave the doc as it is and record no finding: a repo without coding standards has made a valid choice, and `ce-setup` drafts rules from these docs whenever someone runs it. Nothing this skill writes names `ce-setup` or a missing standards file. Only an attended report carries the one line `references/report.md` defines.\n\n\u003c!-- ce-standards-bar:start -->\nA defect class enters `CODING_STANDARDS.md` only when it appeared in a review finding the author fixed, a fix commit, a cleanup that removed it across the codebase, or a solution record, and no check covers it. State the class as a condition in a few sentences that stay true without naming volatile numbers or symbols, and group rules by area.\n\u003c!-- ce-standards-bar:end -->\n\n## Report\n\nThe summary block carries one line, `Worth: N shortened, N deleted; standards: N removed, N narrowed, N added`, or `Worth: off (drift fixes only)`, and each verdict lists the artifacts it rests on.\n","content_type":"text/markdown; charset=utf-8","language":"markdown","size":5188,"content_sha256":"ce1faae7f25324b954cb205535b7dea0d932a669cfd47396540151255cb172db"},{"filename":"references/yaml-schema.md","content":"# YAML Frontmatter Schema\n\n`schema.yaml` in this directory is the canonical contract for `\u003croot>/solutions/` frontmatter written by `ce-compound`.\n\nUse this file as the quick reference for:\n- required fields\n- enum values and open-vocabulary defaults\n- validation expectations\n- category mapping\n- track classification (bug vs knowledge)\n\n## Corpus-First Vocabulary\n\n`component` and `root_cause` are open vocabulary, and the category directories are a default layout, not a fixed one. Repos that already hold learnings usually have their own self-consistent values and directory names, and their retrieval (agent instructions, greps, tooling) is keyed on those. A doc written to this file's defaults instead of the repo's vocabulary is a doc the repo cannot find, which defeats the point of writing it.\n\nSo, before classifying: when `\u003croot>/solutions/` already contains docs, sample their frontmatter (`component`, `root_cause`, `problem_type`, `tags`) and directory names for this area. For `component`, use the value the corpus's existing docs use for this area (the component/directory grouping this change belongs to). For `root_cause`, match by the cause itself rather than the area: use the value existing docs use for this same underlying cause, wherever in the corpus those docs live — an area's typical root_cause does not carry over to a doc whose verified cause is different. For either field, when the corpus has more than one spelling for the same area (component) or the same cause (root_cause), use the spelling the most docs use (tie: the most recently dated doc); use the schema's suggested default only when no existing doc covers the area (component) or names the cause (root_cause). Reuse corpus values as spelled — do not coin a near-synonym of a value the corpus already uses. Directory choice is a separate condition: file the doc in the existing directory that covers this area; use the Category Mapping below only when no existing directory covers it. `problem_type`, `severity`, and `resolution_type` remain closed enums (`problem_type` drives track selection).\n\n## Tracks\n\nThe `problem_type` determines which **track** applies. Each track has different required and optional fields.\n\n| Track | problem_types | Description |\n|-------|--------------|-------------|\n| **Bug** | `build_error`, `test_failure`, `runtime_error`, `performance_issue`, `database_issue`, `security_issue`, `ui_bug`, `integration_issue`, `logic_error` | Defects and failures that were diagnosed and fixed |\n| **Knowledge** | `best_practice`, `documentation_gap`, `workflow_issue`, `developer_experience`, `architecture_pattern`, `design_pattern`, `tooling_decision`, `convention` | Practices, patterns, conventions, decisions, workflow improvements, and documentation. Prefer the narrowest applicable value; `best_practice` is the fallback. |\n\n## Required Fields (both tracks)\n\n- **module**: Module or area affected\n- **date**: ISO date in `YYYY-MM-DD`\n- **problem_type**: One of the values listed in the Tracks table above\n- **component**: Component or area involved — open vocabulary (see Corpus-First Vocabulary). Suggested defaults when the corpus has no value for the area: `data_model`, `api_layer`, `service_layer`, `background_job`, `database`, `frontend`, `messaging`, `infrastructure`, `observability`, `authentication`, `payments`, `development_workflow`, `testing_framework`, `documentation`, `tooling`\n- **severity**: One of `critical`, `high`, `medium`, `low`\n\n## Bug Track Fields\n\nRequired:\n- **symptoms**: YAML array with 1-5 observable symptoms (errors, broken behavior)\n- **root_cause**: Fundamental technical cause — open vocabulary (see Corpus-First Vocabulary). Suggested defaults: `wrong_api`, `data_integrity`, `concurrency`, `async_timing`, `memory_leak`, `config_error`, `logic_error`, `test_isolation`, `missing_validation`, `missing_permission`, `missing_workflow_step`, `inadequate_documentation`, `missing_tooling`, `incomplete_setup`\n- **resolution_type**: One of `code_fix`, `migration`, `config_change`, `test_fix`, `dependency_update`, `environment_setup`, `workflow_improvement`, `documentation_update`, `tooling_addition`, `seed_data_update`\n\n## Knowledge Track Fields\n\nNo additional required fields beyond the shared ones. All fields below are optional:\n\n- **applies_when**: Conditions or situations where this guidance applies\n- **symptoms**: Observable gaps or friction that prompted this guidance\n- **root_cause**: Underlying cause, if there is a specific one\n- **resolution_type**: Type of change, if applicable\n\n## Optional Fields (both tracks)\n\n- **related_components**: Other components involved\n- **tags**: Search keywords, lowercase and hyphen-separated\n- **retire_when**: The change outside the repo that would retire this learning, and how a refresh can check for it without changing the repo. Set it only when the guidance holds just while something outside the repo holds: an open upstream bug, a tool or platform version, a dependency's behavior. Omit it otherwise. A verification that needs a repo change, such as removing a workaround and rerunning CI, belongs in the body as the step before removal. It is one string; quote the whole value when it contains ` #` or `: `.\n\n## Optional Fields (bug track only)\n\n- **framework_version**: Framework or runtime name and version the bug was observed on, e.g. `rails 7.1.2` or `node 22.4.0`\n\n## Backward Compatibility\n\nDocs created before the track system may have `symptoms`/`root_cause`/`resolution_type` on knowledge-type problem_types. These are valid legacy docs:\n\n- Bug-track fields present on a knowledge-track doc are harmless. Do not strip them during refresh unless the doc is being rewritten for other reasons.\n- Docs written before `component`/`root_cause` became open vocabulary may carry values from the earlier closed list or the earlier `rails_version` field (now `framework_version`). They stay valid, and a corpus that consistently uses them keeps using them.\n- When creating **new** docs, follow the track rules above.\n\n## Category Mapping\n\nDefault layout for a repo with no existing learnings. When `\u003croot>/solutions/` already has an established directory taxonomy, place the doc in the existing directory that covers this area (the corpus-first rule above) rather than creating a new directory from this table that nothing else uses.\n\n- `build_error` -> `\u003croot>/solutions/build-errors/`\n- `test_failure` -> `\u003croot>/solutions/test-failures/`\n- `runtime_error` -> `\u003croot>/solutions/runtime-errors/`\n- `performance_issue` -> `\u003croot>/solutions/performance-issues/`\n- `database_issue` -> `\u003croot>/solutions/database-issues/`\n- `security_issue` -> `\u003croot>/solutions/security-issues/`\n- `ui_bug` -> `\u003croot>/solutions/ui-bugs/`\n- `integration_issue` -> `\u003croot>/solutions/integration-issues/`\n- `logic_error` -> `\u003croot>/solutions/logic-errors/`\n- `developer_experience` -> `\u003croot>/solutions/developer-experience/`\n- `workflow_issue` -> `\u003croot>/solutions/workflow-issues/`\n- `best_practice` -> `\u003croot>/solutions/best-practices/`\n- `documentation_gap` -> `\u003croot>/solutions/documentation-gaps/`\n- `architecture_pattern` -> `\u003croot>/solutions/architecture-patterns/`\n- `design_pattern` -> `\u003croot>/solutions/design-patterns/`\n- `tooling_decision` -> `\u003croot>/solutions/tooling-decisions/`\n- `convention` -> `\u003croot>/solutions/conventions/`\n\n## Validation Rules\n\n1. Determine the track from `problem_type` using the Tracks table.\n2. All shared required fields must be present.\n3. Bug-track required fields (`symptoms`, `root_cause`, `resolution_type`) must be present on bug-track docs.\n4. Knowledge-track docs have no additional required fields beyond the shared ones.\n5. Bug-track fields on existing knowledge-track docs are harmless (see Backward Compatibility).\n6. Enum fields (`problem_type`, `severity`, `resolution_type`) must match the allowed values exactly.\n7. Open-vocabulary fields (`component`, `root_cause`) follow the Corpus-First Vocabulary rule above.\n8. Array fields must respect min/max item counts.\n9. `date` must match `YYYY-MM-DD`.\n10. `framework_version`, if present, only applies to bug-track docs.\n11. `retire_when` is optional on both tracks. When present it is one string, and a doc without it stays valid.\n\n## YAML Safety Rules\n\nStrict YAML 1.2 parsers (`yq`, `js-yaml` strict, PyYAML) reject array items\nthat start with a reserved indicator character as unquoted scalars. When\nwriting items for any array-of-strings field (`symptoms`, `applies_when`,\n`tags`, `related_components`, or any future array field), wrap the value in\ndouble quotes if it starts with any of:\n\n`` ` ``, `[`, `*`, `&`, `!`, `|`, `>`, `%`, `@`, `?`\n\nAlso quote if the value contains the substring `\": \"` — that punctuation\nconfuses flow-style parsers.\n\nExample — before (breaks strict YAML):\n\n symptoms:\n - `sudo dscacheutil -flushcache` does not restore in-container mDNS\n\nExample — after (parses cleanly):\n\n symptoms:\n - \"`sudo dscacheutil -flushcache` does not restore in-container mDNS\"\n\nThis rule applies to all array-of-strings frontmatter fields. Scalar string\nfields like `description:` have their own quoting rules (see plugin\n`AGENTS.md` under \"YAML Frontmatter\").\n","content_type":"text/markdown; charset=utf-8","language":"markdown","size":9203,"content_sha256":"b9c7027253398bfeaee503bde228f0b9279a047d01369cca01719b43210efd9a"},{"filename":"scripts/validate-doc-claims.py","content":"#!/usr/bin/env python3\n\"\"\"Validate cited claims in a solution doc against the git tree.\n\nUsage:\n python3 validate-doc-claims.py \u003cdoc-path>\n\nExit codes:\n 0 — nothing flagged\n 1 — one or more flags need adjudication (report on stdout)\n 2 — usage error (bad arguments, missing file)\n\nScope: mechanical grounding checks on a written doc's *body*. Complements\nvalidate-frontmatter.py (parser-safety) — this script checks the body's\ncitations against the repository:\n\n 1. Cited repo-relative paths (backticked, containing at least one '/')\n exist in the working tree, including already-absolute citations that\n fall inside the repo (rewritten to repo-relative before candidacy).\n Tokens containing '../' resolve from the doc's directory (those\n escaping the repo are skipped). Misses tracked at HEAD or the\n upstream default branch still count as real paths and are classified\n (deleted/uncommitted vs stale checkout). Tokens missing everywhere\n are flagged only when path-shaped; slash-delimited identifiers\n (branch names, git refs, provider/model IDs) and slash-prefixed\n URL routes are skipped.\n 2. Cited commit SHAs (7-40 hex chars with at least one digit and one\n a-f letter) resolve to commits, classified by reachability from\n HEAD and the upstream default branch. Session ids, content hashes\n and blob hashes are hex too, so an unresolvable hex word is\n reported in one of two tiers rather than asserted to be fabricated:\n FLAG when the text right before it presents it as a commit (a\n likely fabricated citation), NOTE otherwise (an identifier this\n script cannot classify). Only FLAG affects the exit code. The\n cue vocabulary therefore ranks confidence; it does not decide\n whether an item is surfaced, so a phrasing it misses is reported\n one tier down instead of disappearing.\n 3. Relative markdown link targets resolve from the doc's location.\n 4. Dangling drafting scaffold: \"Learning(s) N\" numbering and\n unresolved {{...}} placeholder tokens. Inline code spans and fenced\n code blocks are masked first, so a {{...}} shown as documented syntax\n (Handlebars, a CI variable, a GitHub ruleset placeholder) is not\n mistaken for a leaked scaffold; only a bare token in prose is flagged.\n\nFlags are adjudication input, NOT hard failures — a doc may legitimately\ncite a path deleted by the very fix it documents. The calling agent\ndecides per flag: fix, annotate as historical, or confirm intentional.\nOnly the summary exit code distinguishes \"clean\" from \"needs a look\".\n\nThe script never touches the network (no fetch); classification uses\nwhatever refs exist locally. Run a best-effort `git fetch --quiet` first\nwhen freshness matters. Pure stdlib (no third-party deps).\n\"\"\"\nimport os\nimport re\nimport subprocess\nimport sys\n\n# Tokens containing these are placeholders/examples, not real citations.\nPLACEHOLDER_CHARS = set(\"\u003c>{}*$\")\nPLACEHOLDER_SUBSTRINGS = (\"path/to\", \"...\", \"…\")\n\nSHA_RE = re.compile(r\"\\b[0-9a-f]{7,40}\\b\")\n# Words that name a commit or a commit operation, so a hex token right after\n# one is a commit citation. Words naming some other git object (\"blob\", \"tree\"),\n# any hash (\"sha\"), and the bare tool name (\"git\", which precedes every object\n# kind equally) are deliberately absent — they are what the flag used to mistake\n# for commits.\nCOMMIT_WORDS = frozenset(\n \"commit commits committed committing revision revisions rev revs \"\n \"revert reverts reverted cherry-pick cherry-picked rebase rebased \"\n \"bisect bisected\".split()\n)\n# A hex token is also a citation when the sentence attributes a change landing\n# in this repository to it: \"landed in \u003csha>\", \"resolved by \u003csha>\". Both halves\n# are needed. The preposition alone attributes without saying what to, so it\n# would read \"recorded at \u003cdigest>\" as a commit; the verb alone does not point\n# at the token. Membership below is that condition, not a tally of phrasings\n# seen so far: a verb belongs when it says a change landed, and does not when\n# it says an identifier was assigned or a value stored.\nCITATION_VERBS = frozenset(\n \"fixed fix fixes landed lands land introduced introduces introduce \"\n \"shipped ships ship merged merges merge resolved resolves resolve \"\n \"reverted reverts broke breaks broken caused causes regressed \"\n \"added adds removed removes released releases\".split()\n)\nCITATION_PREPS = frozenset((\"in\", \"by\", \"at\", \"with\"))\n# The pin form that names a commit is owner/repo@\u003csha>. A bare \"@\" is not it:\n# it also prefixes account names and image tags, whose identifiers are hex too.\nREPO_PIN_RE = re.compile(r\"(?\u003c![\\w./@-])[\\w.-]+/[\\w.-]+@$\")\nBACKTICK_RE = re.compile(r\"`([^`\\n]+)`\")\nMD_LINK_RE = re.compile(r\"\\[[^\\]]*\\]\\(([^)\\s]+)\\)\")\nFENCE_RE = re.compile(r\"^\\s*(`{3,}|~{3,})(.*)$\")\nSCAFFOLD_RES = (\n re.compile(r\"\\bLearnings?\\s+#?\\d\"),\n re.compile(r\"\\{\\{[^}\\n]*\\}\\}\"),\n)\n\n\ndef usage_fail(msg: str) -> \"NoReturn\":\n sys.stderr.write(f\"validate-doc-claims: {msg}\\n\")\n sys.exit(2)\n\n\ndef git(args: list[str], cwd: str) -> tuple[int, str]:\n try:\n result = subprocess.run(\n [\"git\", *args],\n cwd=cwd,\n capture_output=True,\n text=True,\n timeout=30,\n )\n return result.returncode, result.stdout.strip()\n except (OSError, subprocess.TimeoutExpired):\n return 1, \"\"\n\n\ndef split_body(text: str) -> tuple[str, int]:\n \"\"\"Return (body, 1-indexed line number the body starts on).\n\n Skips YAML frontmatter when present so frontmatter fields are not\n scanned as body citations.\n \"\"\"\n lines = text.split(\"\\n\")\n if lines and lines[0].rstrip() == \"---\":\n for i in range(1, len(lines)):\n if lines[i].rstrip() == \"---\":\n return \"\\n\".join(lines[i + 1 :]), i + 2\n return text, 1\n\n\ndef is_path_candidate(token: str, *, known_path: bool = False) -> bool:\n if any(ch.isspace() for ch in token):\n return False\n if not known_path and \"/\" not in token:\n return False\n if \"://\" in token or token.startswith((\"http\", \"#\", \"/\", \"~\")):\n return False\n if token.startswith((\"origin/\", \"upstream/\", \"refs/\")):\n return False # git refs, not repo paths\n if PLACEHOLDER_CHARS & set(token):\n return False\n if any(sub in token for sub in PLACEHOLDER_SUBSTRINGS):\n return False\n return True\n\n\ndef is_path_shaped(token: str, base: str) -> bool:\n \"\"\"Distinguish a path citation from a slash-delimited identifier\n (branch name, provider/model ID) among tokens found nowhere in git.\"\"\"\n segments = token.split(\"/\")\n if re.search(r\"\\.[A-Za-z0-9]{1,8}$\", segments[-1]):\n return True\n if token.endswith(\"/\"):\n return True\n return os.path.isdir(os.path.join(base, segments[0]))\n\n\ndef mask_code(lines: list[str]) -> list[str]:\n \"\"\"Blank out fenced code blocks and inline code spans, preserving line\n count and length. Illustrative {{...}} in quoted code must not read as a\n leaked drafting scaffold; only bare tokens in prose should.\"\"\"\n masked: list[str] = []\n fence: str | None = None # active fence run (e.g. \"```\"), or None\n for line in lines:\n m = FENCE_RE.match(line)\n if fence is None and m:\n fence = m.group(1)\n masked.append(\" \" * len(line))\n continue\n if fence is not None:\n # CommonMark: a closing fence is the same char, at least as long,\n # and followed only by whitespace — an info string (```json) opens\n # but never closes, so it stays block content.\n if (\n m\n and m.group(1)[0] == fence[0]\n and len(m.group(1)) >= len(fence)\n and not m.group(2).strip()\n ):\n fence = None\n masked.append(\" \" * len(line))\n continue\n masked.append(BACKTICK_RE.sub(lambda x: \" \" * len(x.group(0)), line))\n return masked\n\n\ndef cites_a_commit(prefix: str) -> bool:\n \"\"\"True when the text just before a hex word presents it as a commit.\n\n Only the last few words on the same line count: a cue further away\n (\"the git history shows session 7e6861b4\") describes the surroundings,\n not the token. Digits are word characters so a hash named after its\n algorithm (\"SHA256\") stays one non-cue word, and command flags drop out\n first so `git show --format=%H \u003csha>` reads like `git show \u003csha>`.\n \"\"\"\n if REPO_PIN_RE.search(prefix):\n return True # owner/repo@\u003csha> pins a commit\n unflagged = \" \".join(w for w in prefix.split() if not w.startswith(\"-\"))\n words = [\n w.lower() for w in re.findall(r\"[A-Za-z][A-Za-z0-9-]*\", unflagged)[-3:]\n ]\n if any(word in COMMIT_WORDS for word in words):\n return True\n return (\n len(words) >= 2\n and words[-1] in CITATION_PREPS\n and words[-2] in CITATION_VERBS\n )\n\n\ndef normalize_path(token: str) -> str:\n token = token.strip().rstrip(\".,;\")\n token = re.sub(r\":\\d+(-\\d+)?$\", \"\", token) # strip `:line` / `:a-b` refs\n if token.startswith(\"./\"):\n token = token[2:]\n return token\n\n\ndef strip_repo_prefix(token: str, base: str) -> str:\n \"\"\"Rewrite an already-absolute path inside the repo to repo-relative.\n\n Relative tokens, URL routes, and out-of-repo absolute paths are\n unchanged so the existing candidacy guard still drops them. Realpath\n both sides so a host where /tmp is a symlink still matches. A\n successful rewrite is slash-normalized so Windows relpath output\n stays a candidate.\n \"\"\"\n if not os.path.isabs(token):\n return token\n try:\n rel = os.path.relpath(os.path.realpath(token), os.path.realpath(base))\n except ValueError:\n return token\n if rel == \"..\" or rel.startswith(\"..\" + os.sep):\n return token\n return rel.replace(\"\\\\\", \"/\")\n\n\ndef main(argv: list[str]) -> int:\n if len(argv) != 2:\n usage_fail(f\"usage: {os.path.basename(argv[0])} \u003cdoc-path>\")\n\n doc_path = argv[1]\n if not os.path.isfile(doc_path):\n usage_fail(f\"file not found: {doc_path}\")\n\n with open(doc_path) as f:\n text = f.read()\n\n doc_dir = os.path.dirname(os.path.abspath(doc_path))\n body, body_start = split_body(text)\n body_lines = body.split(\"\\n\")\n\n def loc_suffix(needle: str) -> str:\n for i, line in enumerate(body_lines):\n if needle in line:\n return f\" (line {body_start + i})\"\n return \"\"\n\n infos: list[str] = []\n notes: list[str] = []\n flags: list[str] = []\n\n # --- Repo context -----------------------------------------------------\n code, repo_root = git([\"rev-parse\", \"--show-toplevel\"], doc_dir)\n in_git = code == 0 and bool(repo_root)\n upstream: str | None = None\n if in_git:\n code, ref = git([\"rev-parse\", \"--abbrev-ref\", \"origin/HEAD\"], repo_root)\n if code == 0 and ref:\n upstream = ref\n else:\n for candidate in (\"origin/main\", \"origin/master\"):\n code, _ = git(\n [\"rev-parse\", \"--verify\", \"--quiet\", candidate], repo_root\n )\n if code == 0:\n upstream = candidate\n break\n if upstream:\n code, behind = git(\n [\"rev-list\", \"--count\", f\"HEAD..{upstream}\"], repo_root\n )\n if code == 0 and behind.isdigit() and int(behind) > 0:\n infos.append(\n f\"INFO: worktree is {behind} commits behind {upstream} — \"\n \"verify merge-state claims against remote truth (gh pr view), \"\n \"not this checkout\"\n )\n else:\n infos.append(\n \"INFO: no upstream default branch found — \"\n \"path/SHA classification limited to HEAD\"\n )\n else:\n infos.append(\n \"INFO: not a git repository — path and SHA classification skipped \"\n \"(scaffold and link checks still apply)\"\n )\n\n def upstream_has_path(path: str) -> bool:\n if not (in_git and upstream):\n return False\n code, _ = git([\"cat-file\", \"-e\", f\"{upstream}:{path}\"], repo_root)\n return code == 0\n\n def head_has_path(path: str) -> bool:\n if not in_git:\n return False\n code, _ = git([\"cat-file\", \"-e\", f\"HEAD:{path}\"], repo_root)\n return code == 0\n\n # --- 1. Cited repo paths ----------------------------------------------\n checked_paths = 0\n seen_paths: set[str] = set()\n base = repo_root if in_git else os.getcwd()\n for raw in BACKTICK_RE.findall(body):\n token = normalize_path(raw)\n rewritten_abs = False\n if in_git:\n before = token\n token = strip_repo_prefix(token, base)\n rewritten_abs = token != before\n if not is_path_candidate(token, known_path=rewritten_abs):\n continue\n check = token\n if token.startswith(\"../\") or \"/../\" in token:\n # A `../` citation is doc-relative (matching how markdown links\n # resolve), so map it to a repo-root path before checking.\n if not in_git:\n continue\n resolved = os.path.realpath(os.path.join(doc_dir, token))\n check = os.path.relpath(resolved, os.path.realpath(base))\n if check.startswith(\"..\"):\n continue # escapes the repo — not checkable as a repo path\n if check in seen_paths:\n continue\n seen_paths.add(check)\n if os.path.exists(os.path.join(base, check)):\n checked_paths += 1\n continue\n tracked_head = head_has_path(check)\n tracked_upstream = upstream_has_path(check)\n if not (tracked_head or tracked_upstream) and not is_path_shaped(\n check, base\n ):\n continue # branch name / provider ID, not a path citation\n checked_paths += 1\n loc = loc_suffix(raw)\n if tracked_head:\n flags.append(\n f\"FLAG path `{token}`{loc} — tracked at HEAD but missing from \"\n \"the working tree: deleted or uncommitted removal? Annotate as \"\n \"historical (e.g. removed by this fix) or restore it.\"\n )\n elif tracked_upstream:\n flags.append(\n f\"FLAG path `{token}`{loc} — not in working tree but exists at \"\n f\"{upstream}: stale checkout? Annotate or verify against upstream.\"\n )\n else:\n flags.append(\n f\"FLAG path `{token}`{loc} — not found under {base}\"\n + (f\" or {upstream}\" if upstream else \"\")\n + \". Only that location was searched; check other repos or \"\n \"stores before treating the citation as wrong. Fix the \"\n \"citation, or annotate it as historical (e.g. removed by \"\n \"this fix).\"\n )\n\n # --- 2. Cited commit SHAs ----------------------------------------------\n checked_shas = 0\n if in_git:\n # One entry per distinct hex word: the line to report it at, and\n # whether any occurrence of it is presented as a commit. A doc often\n # quotes a token in a transcript before citing it, so a later citing\n # occurrence upgrades the tier and supplies the line.\n seen_shas: dict[str, tuple[int, bool]] = {}\n order: list[str] = []\n for m in SHA_RE.finditer(body):\n sha = m.group(0)\n if not (any(c.isdigit() for c in sha) and any(c in \"abcdef\" for c in sha)):\n continue # dates and decimal ids are not SHAs\n line_start = body.rfind(\"\\n\", 0, m.start()) + 1\n cited = cites_a_commit(body[line_start : m.start()])\n line_no = body_start + body.count(\"\\n\", 0, m.start())\n if sha not in seen_shas:\n seen_shas[sha] = (line_no, cited)\n order.append(sha)\n elif cited and not seen_shas[sha][1]:\n seen_shas[sha] = (line_no, True)\n for sha in order:\n line_no, cited = seen_shas[sha]\n code, _ = git([\"cat-file\", \"-e\", f\"{sha}^{{commit}}\"], repo_root)\n resolved = code == 0\n loc = f\" (line {line_no})\"\n if not resolved:\n if not cited:\n # Nothing here says \"commit\", and hex is also how session\n # ids and content hashes are written. Surface it without\n # claiming to know which it is; the reader adjudicates.\n notes.append(\n f\"NOTE sha {sha}{loc} — an unresolved hex identifier \"\n \"with no commit reference around it. This script cannot \"\n \"tell a session id or content hash from a commit; verify \"\n \"it if it was meant as one.\"\n )\n continue\n checked_shas += 1\n flags.append(\n f\"FLAG sha {sha}{loc} — does not resolve to a commit in this \"\n \"repository. Replace with the PR number, or drop it.\"\n )\n continue\n checked_shas += 1\n in_head = (\n git([\"merge-base\", \"--is-ancestor\", sha, \"HEAD\"], repo_root)[0] == 0\n )\n in_up = (\n upstream is not None\n and git([\"merge-base\", \"--is-ancestor\", sha, upstream], repo_root)[0]\n == 0\n )\n if in_head and (in_up or upstream is None):\n continue\n if in_head and not in_up:\n flags.append(\n f\"FLAG sha {sha}{loc} — reachable from HEAD but not {upstream}: \"\n \"local-only commit whose SHA may be rewritten on merge \"\n \"(rebase/squash). Prefer citing the PR number.\"\n )\n elif in_up:\n flags.append(\n f\"FLAG sha {sha}{loc} — not reachable from HEAD but reachable \"\n f\"from {upstream}: this checkout predates the merge. Add a \"\n \"temporal qualifier or verify the claim via gh.\"\n )\n else:\n flags.append(\n f\"FLAG sha {sha}{loc} — exists but unreachable from HEAD\"\n + (f\" or {upstream}\" if upstream else \"\")\n + \": likely a rebased-away commit. Prefer citing the PR number.\"\n )\n\n # --- 3. Relative markdown links -----------------------------------------\n checked_links = 0\n seen_links: set[str] = set()\n for target in MD_LINK_RE.findall(body):\n if re.match(r\"^[a-z][a-z0-9+.-]*:\", target, re.IGNORECASE):\n continue # URL scheme\n if target.startswith(\"#\"):\n continue # intra-doc anchor\n bare = target.split(\"#\", 1)[0]\n if not bare or bare in seen_links:\n continue\n seen_links.add(bare)\n checked_links += 1\n if not os.path.exists(os.path.normpath(os.path.join(doc_dir, bare))):\n loc = loc_suffix(target)\n flags.append(\n f\"FLAG link ({target}){loc} — relative target does not resolve \"\n \"from the doc's location. Fix the path.\"\n )\n\n # --- 4. Dangling drafting scaffold ---------------------------------------\n for i, line_text in enumerate(mask_code(body_lines)):\n for pattern in SCAFFOLD_RES:\n m = pattern.search(line_text)\n if m:\n flags.append(\n f'FLAG scaffold \"{m.group(0)}\" (line {body_start + i}) — '\n \"drafting-context reference leaked into the doc. Rewrite it \"\n \"as a real path or link.\"\n )\n\n # --- Report ---------------------------------------------------------------\n for info in infos:\n print(info)\n for note in notes:\n print(note)\n for flag in flags:\n print(flag)\n summary = (\n f\"checked {checked_paths} paths, {checked_shas} SHAs, \"\n f\"{checked_links} links; {len(flags)} flags\"\n )\n if notes:\n summary += f\", {len(notes)} notes\"\n print(summary)\n if flags:\n return 1\n print(f\"OK: {doc_path}\")\n return 0\n\n\nif __name__ == \"__main__\":\n sys.exit(main(sys.argv))\n","content_type":"text/x-python; charset=utf-8","language":"python","size":20561,"content_sha256":"24fae245bade400f7cb7a085ee68b08289f4d8b24481155a226ca976a2acf501"},{"filename":"scripts/validate-frontmatter.py","content":"#!/usr/bin/env python3\n\"\"\"Validate ce-compound learning-doc frontmatter for parser-safety issues.\n\nUsage:\n python3 validate-frontmatter.py \u003cdoc-path>\n\nExit codes:\n 0 — frontmatter passes all checks\n 1 — validation failure (diagnostics on stderr)\n 2 — usage error (bad arguments, missing file)\n\nScope: this script catches *parser-safety* issues — frontmatter that strict\nYAML parsers will silently misread. It does NOT validate against the\nschema's required-field or enum-value rules; that's a separate concern. The\nintent is to prevent the silent-data-loss bug class where YAML's quoting\nrules truncate or reframe scalar values without raising.\n\nChecks (regex-based, no YAML parser dependency):\n 1. File starts and ends frontmatter with `---` lines (matched as full\n lines, not substrings — `----` and `---extra` are rejected)\n 2. No top-level scalar value contains ` #` unquoted (silent comment\n truncation — what Codex caught on PR #695)\n 3. No top-level scalar value contains `: ` unquoted (mapping confusion —\n what surfaced in a 2026-04-16 plan doc's `title:` field)\n\nThe script does NOT flag values starting with YAML reserved indicators\n(`` ` ``, `*`, `&`, `!`, etc.) because those produce loud parser errors\ndownstream rather than silent corruption — they're already caught by\nwhatever consumes the doc. This validator's purpose is silent-corruption\nprevention, not lint.\n\nPure-stdlib (no PyYAML or other third-party deps). Runs in \u003c50ms typical.\nDesigned to produce concrete, actionable error messages so the calling\nagent can fix and retry without ambiguity.\n\"\"\"\nimport os\nimport re\nimport sys\n\n\ndef usage_fail(msg: str) -> \"NoReturn\":\n sys.stderr.write(f\"validate-frontmatter: {msg}\\n\")\n sys.exit(2)\n\n\ndef main(argv: list[str]) -> int:\n if len(argv) != 2:\n usage_fail(f\"usage: {os.path.basename(argv[0])} \u003cdoc-path>\")\n\n doc_path = argv[1]\n if not os.path.isfile(doc_path):\n usage_fail(f\"file not found: {doc_path}\")\n\n with open(doc_path) as f:\n text = f.read()\n\n issues: list[str] = []\n\n # Check 1: frontmatter delimiters. Match the delimiter as a complete\n # line whose stripped content is exactly `---` — substring matching\n # (e.g. `text.find(\"\\n---\", 4)`) would falsely accept `----` or\n # `---extra` as a terminator and let malformed docs slip through to\n # downstream parsers that require a strict `---` line.\n lines = text.split(\"\\n\")\n if not lines or lines[0].rstrip() != \"---\":\n sys.stderr.write(\n f\"FAIL: {doc_path}\\n\"\n f\" file does not start with '---' frontmatter delimiter line\\n\"\n )\n return 1\n\n end_idx: int | None = None\n for i in range(1, len(lines)):\n if lines[i].rstrip() == \"---\":\n end_idx = i\n break\n\n if end_idx is None:\n sys.stderr.write(\n f\"FAIL: {doc_path}\\n\"\n f\" frontmatter not closed (no '---' line after the opening delimiter)\\n\"\n )\n return 1\n\n fm_text = \"\\n\".join(lines[1:end_idx])\n\n # Checks 2 & 3: silent-corruption quoting risks on top-level scalar\n # fields. We scan line-by-line and only flag top-level mapping entries\n # (no leading whitespace) whose value isn't already quoted/structured.\n for lineno, line in enumerate(fm_text.split(\"\\n\"), start=2):\n stripped = line.lstrip()\n if not stripped or stripped.startswith(\"#\"):\n continue\n if \":\" not in line:\n continue\n # Top-level mapping keys only — skip nested values, array items\n if line.startswith((\" \", \"\\t\")):\n continue\n # Skip pure list-marker lines like \"- item\" (these can't be top-level\n # in our frontmatter convention, but be defensive)\n if stripped.startswith(\"- \"):\n continue\n\n key, _, val = line.partition(\":\")\n val_stripped = val.strip()\n if not val_stripped:\n # Key with no value on this line — likely a parent of a nested\n # block (`tags:` followed by `- foo`). Nothing to validate here.\n continue\n # Already quoted or structured (block scalar, flow collection)\n if val_stripped[0] in '\"\\'[{|>':\n continue\n\n if re.search(r\"\\s#\", val_stripped):\n issues.append(\n f\"line {lineno}: '{key.strip()}' value contains ' #' — quote it. \"\n \"YAML treats space-then-# as a comment delimiter and silently \"\n \"drops the rest of the value.\"\n )\n if re.search(r\":\\s\", val_stripped):\n issues.append(\n f\"line {lineno}: '{key.strip()}' value contains ': ' — quote it. \"\n \"Strict YAML parsers may treat this as a nested mapping.\"\n )\n\n if issues:\n sys.stderr.write(f\"FAIL: {doc_path}\\n\")\n for issue in issues:\n sys.stderr.write(f\" {issue}\\n\")\n return 1\n\n print(f\"OK: {doc_path}\")\n return 0\n\n\nif __name__ == \"__main__\":\n sys.exit(main(sys.argv))\n","content_type":"text/x-python; charset=utf-8","language":"python","size":5060,"content_sha256":"580815f6b6030f5f3383972283927ff7354649b7b599b008941a9440d5a5e674"}],"content_json":{"type":"doc","content":[{"type":"heading","attrs":{"level":1},"content":[{"text":"Compound Refresh","type":"text"}]},{"type":"paragraph","content":[{"text":"Audit the learnings under ","type":"text"},{"text":"\u003croot>/solutions/","type":"text","marks":[{"type":"code_inline"}]},{"text":" against the current codebase, apply the maintenance actions the evidence supports, and deliver a complete per-doc report plus committed changes. The report and the corrected document set are the deliverables. The store only compounds value if every doc can be trusted.","type":"text"}]},{"type":"heading","attrs":{"level":2},"content":[{"text":"Mode","type":"text"}]},{"type":"paragraph","content":[{"text":"Read ","type":"text","marks":[{"type":"strong"}]},{"text":"references/modes.md","type":"text","marks":[{"type":"code_inline"},{"type":"strong"}]},{"text":" now.","type":"text","marks":[{"type":"strong"}]},{"text":" It reads the mode off the arguments and defines what each mode may apply unattended, the stale-marking fallback, the question tools, and the ","type":"text"},{"text":"CONCEPTS.md","type":"text","marks":[{"type":"code_inline"}]},{"text":" bootstrap.","type":"text"}]},{"type":"paragraph","content":[{"text":"Two rules hold in both modes. A failed write is recorded as ","type":"text"},{"text":"recommended","type":"text","marks":[{"type":"strong"}]},{"text":", and the run continues. And a question is asked through the host's blocking tool, or through the numbered-options fallback that reference defines. It is never silently skipped.","type":"text"}]},{"type":"heading","attrs":{"level":2},"content":[{"text":"Worth","type":"text"}]},{"type":"paragraph","content":[{"text":"Every refresh judges worth as well as accuracy: a lesson should live in one place, in the strongest form that holds it. ","type":"text"},{"text":"Read ","type":"text","marks":[{"type":"strong"}]},{"text":"references/worth-audit.md","type":"text","marks":[{"type":"code_inline"},{"type":"strong"}]},{"text":" before Investigate.","type":"text","marks":[{"type":"strong"}]},{"text":" It adds the bar, the evidence rule, and the routing, including the changes this skill makes to ","type":"text"},{"text":"CODING_STANDARDS.md","type":"text","marks":[{"type":"code_inline"}]},{"text":". When the user asked for drift fixes only, do not read it and do not apply its test; the accuracy refresh is the whole run.","type":"text"}]},{"type":"heading","attrs":{"level":2},"content":[{"text":"Artifact Root","type":"text"}]},{"type":"paragraph","content":[{"text":"Resolve ","type":"text"},{"text":"\u003croot>","type":"text","marks":[{"type":"code_inline"}]},{"text":" when you first compose a ","type":"text"},{"text":"\u003croot>/solutions/","type":"text","marks":[{"type":"code_inline"}]},{"text":" path. Pass the resolved ","type":"text"},{"text":"\u003croot>/solutions/","type":"text","marks":[{"type":"code_inline"}]},{"text":" path to any subagent, not the config. Every subagent spawn omits the ","type":"text"},{"text":"mode","type":"text","marks":[{"type":"code_inline"}]},{"text":" parameter, so the user's permission settings apply.","type":"text"}]},{"type":"paragraph","content":[{"text":"\u003c!-- ce-docs-root:start --> ","type":"text"},{"text":"Resolve the CE artifact root ","type":"text","marks":[{"type":"strong"}]},{"text":"\u003croot>","type":"text","marks":[{"type":"code_inline"},{"type":"strong"}]},{"text":" before composing any artifact path.","type":"text","marks":[{"type":"strong"}]}]},{"type":"bullet_list","content":[{"type":"list_item","content":[{"type":"paragraph","content":[{"text":"Read","type":"text","marks":[{"type":"strong"}]},{"text":" ","type":"text"},{"text":"docs_root","type":"text","marks":[{"type":"code_inline"}]},{"text":" from ","type":"text"},{"text":"\u003crepo-root>/.compound-engineering/config.yaml","type":"text","marks":[{"type":"code_inline"}]},{"text":" only (","type":"text"},{"text":"\u003crepo-root>","type":"text","marks":[{"type":"code_inline"}]},{"text":" = ","type":"text"},{"text":"git rev-parse --show-toplevel","type":"text","marks":[{"type":"code_inline"}]},{"text":"). Do not read it from ","type":"text"},{"text":"config.local.yaml","type":"text","marks":[{"type":"code_inline"}]},{"text":". Unset -> ","type":"text"},{"text":"\u003croot>","type":"text","marks":[{"type":"code_inline"}]},{"text":" is ","type":"text"},{"text":"docs","type":"text","marks":[{"type":"code_inline"}]},{"text":", exactly as before.","type":"text"}]}]},{"type":"list_item","content":[{"type":"paragraph","content":[{"text":"Validate","type":"text","marks":[{"type":"strong"}]},{"text":" a set value: a repo-relative directory whose real, symlink-resolved path stays inside the repo and is neither the repo root nor under ","type":"text"},{"text":".git/","type":"text","marks":[{"type":"code_inline"}]},{"text":". Otherwise stop with an error naming ","type":"text"},{"text":"docs_root","type":"text","marks":[{"type":"code_inline"}]},{"text":" and the value -- never fall back to ","type":"text"},{"text":"docs","type":"text","marks":[{"type":"code_inline"}]},{"text":".","type":"text"}]}]},{"type":"list_item","content":[{"type":"paragraph","content":[{"text":"Use","type":"text","marks":[{"type":"strong"}]},{"text":" ","type":"text"},{"text":"\u003croot>","type":"text","marks":[{"type":"code_inline"}]},{"text":" as the sole artifact location: create it if absent, compose each path as ","type":"text"},{"text":"\u003croot>/\u003csubdir>","type":"text","marks":[{"type":"code_inline"}]},{"text":" with this skill's own subdirectory, and never also read ","type":"text"},{"text":"docs","type":"text","marks":[{"type":"code_inline"}]},{"text":". \u003c!-- ce-docs-root:end -->","type":"text"}]}]}]},{"type":"heading","attrs":{"level":2},"content":[{"text":"Scope","type":"text"}]},{"type":"paragraph","content":[{"text":"Candidates are the ","type":"text"},{"text":".md","type":"text","marks":[{"type":"code_inline"}]},{"text":" files under ","type":"text"},{"text":"\u003croot>/solutions/","type":"text","marks":[{"type":"code_inline"}]},{"text":", excluding ","type":"text"},{"text":"README.md","type":"text","marks":[{"type":"code_inline"}]},{"text":" and anything under ","type":"text"},{"text":"_archived/","type":"text","marks":[{"type":"code_inline"}]},{"text":". A hint that matches nothing never widens the scope. ","type":"text"},{"text":"Read ","type":"text","marks":[{"type":"strong"}]},{"text":"references/scope.md","type":"text","marks":[{"type":"code_inline"},{"type":"strong"}]},{"text":" for the narrowing strategy, what each mode does on a miss, the empty-store message, triage order, and the README-row cleanup each action carries.","type":"text"}]},{"type":"heading","attrs":{"level":2},"content":[{"text":"Investigate","type":"text"}]},{"type":"paragraph","content":[{"text":"Read ","type":"text","marks":[{"type":"strong"}]},{"text":"references/investigate.md","type":"text","marks":[{"type":"code_inline"},{"type":"strong"}]},{"text":" for the staleness dimensions, auto-memory rules, subagent roles, and category-shape notes.","type":"text"}]},{"type":"paragraph","content":[{"text":"Check each learning against the current codebase, then check the set for overlap, supersession, and contradiction. A contradiction misleads actively, so it outranks individual staleness.","type":"text"}]},{"type":"paragraph","content":[{"text":"A knowledge-track learning sometimes points at a guidance file it names or links, such as a skill's ","type":"text"},{"text":"SKILL.md","type":"text","marks":[{"type":"code_inline"}]},{"text":", a runbook, or an instruction file. Compare only guidance the learning names. Never search the guidance layer for one.","type":"text"}]},{"type":"paragraph","content":[{"text":"Every investigation subagent's prompt carries that reference's three ","type":"text"},{"text":"Subagent prompt","type":"text","marks":[{"type":"strong"}]},{"text":" clauses verbatim. Two are search tools and auto-memory. The third is this:","type":"text"}]},{"type":"blockquote","content":[{"type":"paragraph","content":[{"text":"If the learning is knowledge-track and names or links a guidance file (a skill's ","type":"text"},{"text":"SKILL.md","type":"text","marks":[{"type":"code_inline"}]},{"text":", a runbook, a root instruction file), read that file and, when it states a different order or a contradictory rule for the same procedure, return both conflicting quotes plus which side current code follows — or that code witnesses neither. Read only guidance the learning names; do not search for one, and do not edit it.","type":"text"}]}]},{"type":"heading","attrs":{"level":2},"content":[{"text":"Classify","type":"text"}]},{"type":"paragraph","content":[{"text":"Every doc gets exactly one outcome: ","type":"text"},{"text":"Keep","type":"text","marks":[{"type":"strong"}]},{"text":", ","type":"text"},{"text":"Update","type":"text","marks":[{"type":"strong"}]},{"text":", ","type":"text"},{"text":"Consolidate","type":"text","marks":[{"type":"strong"}]},{"text":", ","type":"text"},{"text":"Replace","type":"text","marks":[{"type":"strong"}]},{"text":", or ","type":"text"},{"text":"Delete","type":"text","marks":[{"type":"strong"}]},{"text":". A doc is never archived in place: there is no ","type":"text"},{"text":"_archived/","type":"text","marks":[{"type":"code_inline"}]},{"text":", since version history is the archive.","type":"text"}]},{"type":"paragraph","content":[{"text":"Read ","type":"text","marks":[{"type":"strong"}]},{"text":"references/classify.md","type":"text","marks":[{"type":"code_inline"},{"type":"strong"}]},{"text":" before assigning any of them.","type":"text","marks":[{"type":"strong"}]},{"text":" It defines each outcome's meaning, the Update/Replace boundary, the auto-delete rule and its pre-checks, the relocation and split rules, the retrieval-value test, unverifiable-is-not-false, pattern docs, and what interactive mode asks.","type":"text"}]},{"type":"paragraph","content":[{"text":"Two boundaries hold whatever the evidence says. This skill never changes product code. A claim about current mechanics follows current code, but independently supported guidance does not become false merely because implementation stopped satisfying it: classify the doc from the guidance evidence and report the implementation conflict as a potential product regression. And when a learning contradicts guidance, the refresh reports that; it must never edit a skill, runbook, or instruction file. It also writes no checks. ","type":"text"},{"text":"references/worth-audit.md","type":"text","marks":[{"type":"code_inline"}]},{"text":" governs what it changes in ","type":"text"},{"text":"CODING_STANDARDS.md","type":"text","marks":[{"type":"code_inline"}]},{"text":".","type":"text"}]},{"type":"heading","attrs":{"level":2},"content":[{"text":"Execute","type":"text"}]},{"type":"paragraph","content":[{"text":"Read ","type":"text"},{"text":"references/per-action-flows.md","type":"text","marks":[{"type":"code_inline"}]},{"text":" and follow the section matching each doc's classification, one flow per doc. It defines the criteria, the relocation and split procedures, the replacement subagent contract, and citation cleanup.","type":"text"}]},{"type":"heading","attrs":{"level":2},"content":[{"text":"Vocabulary Capture","type":"text"}]},{"type":"paragraph","content":[{"text":"After the per-doc actions, reconcile the domain terms flagged during investigation with ","type":"text"},{"text":"CONCEPTS.md","type":"text","marks":[{"type":"code_inline"}]},{"text":". ","type":"text"},{"text":"Read ","type":"text","marks":[{"type":"strong"}]},{"text":"references/concepts-vocabulary.md","type":"text","marks":[{"type":"code_inline"},{"type":"strong"}]},{"text":" unconditionally.","type":"text","marks":[{"type":"strong"}]},{"text":" Its qualifying criteria are non-obvious, so a \"nothing qualifies\" judgment reached without reading it is a shortcut, not a result.","type":"text"}]},{"type":"paragraph","content":[{"text":"Edits apply silently in every mode. The report's ","type":"text"},{"text":"CONCEPTS.md","type":"text","marks":[{"type":"code_inline"}]},{"text":" line records what the scan found, including \"scanned, no qualifying terms\".","type":"text"}]},{"type":"heading","attrs":{"level":2},"content":[{"text":"Report","type":"text"}]},{"type":"paragraph","content":[{"text":"Print the full report as markdown.","type":"text","marks":[{"type":"strong"}]},{"text":" It is the deliverable, not an internal summary, and in non-interactive mode it is the only one. Keep it self-contained and never abbreviated, split into ","type":"text"},{"text":"Applied","type":"text","marks":[{"type":"strong"}]},{"text":" and ","type":"text"},{"text":"Recommended","type":"text","marks":[{"type":"strong"}]},{"text":". ","type":"text"},{"text":"Read ","type":"text","marks":[{"type":"strong"}]},{"text":"references/report.md","type":"text","marks":[{"type":"code_inline"},{"type":"strong"}]},{"text":" for the summary block, per-file detail, and what belongs under Recommended.","type":"text"}]},{"type":"heading","attrs":{"level":2},"content":[{"text":"Commit","type":"text"}]},{"type":"paragraph","content":[{"text":"Skip if nothing changed. Otherwise stage ","type":"text"},{"text":"only","type":"text","marks":[{"type":"strong"}]},{"text":" the files this refresh modified, and commit in the repo's convention. ","type":"text"},{"text":"Read ","type":"text","marks":[{"type":"strong"}]},{"text":"references/commit.md","type":"text","marks":[{"type":"code_inline"},{"type":"strong"}]},{"text":" for the per-mode branch decision and the git-failure fallback.","type":"text"}]},{"type":"heading","attrs":{"level":2},"content":[{"text":"Discoverability Check","type":"text"}]},{"type":"paragraph","content":[{"text":"After the report, check that the project's instructions would lead an agent to ","type":"text"},{"text":"\u003croot>/solutions/","type":"text","marks":[{"type":"code_inline"}]},{"text":" before working in a documented area. Do this every time: the store only compounds value when agents can find it. ","type":"text"},{"text":"Read ","type":"text","marks":[{"type":"strong"}]},{"text":"references/discoverability.md","type":"text","marks":[{"type":"code_inline"},{"type":"strong"}]},{"text":" for what the reader must learn, the smallest-addition rule and its tone, the ","type":"text"},{"text":"CONCEPTS.md","type":"text","marks":[{"type":"code_inline"}]},{"text":" variant, consent versus a report line per mode, and folding a late edit into the commit.","type":"text"}]}]},"metadata":{"date":"2026-11-02","name":"ce-compound-refresh","author":"@skillopedia","source":{"stars":25863,"repo_name":"compound-engineering-plugin","origin_url":"https://github.com/EveryInc/compound-engineering-plugin/blob/HEAD/skills/ce-compound-refresh/SKILL.md","repo_owner":"EveryInc","body_sha256":"fabd81b9b8a756af3c18f51be4385fa09aeedfb07a78db1ac4083c16795c567d","cluster_key":"fb4ed57cfdf8051eac3cf17f976a163420664e160f9e03b1c4922efe26c7378b","clean_bundle":{"format":"clean-skill-bundle-v1","source":"EveryInc/compound-engineering-plugin/skills/ce-compound-refresh/SKILL.md","text_bytes":104937,"source_commit":"77cc431daaebea7ee9f33ac530a66eec5404572b","skills_sh_rank":5972,"attachment_count":15,"text_attachments":15,"attachment_storage":"skill_attachments","binary_attachments":0},"cluster_size":1,"skill_md_path":"skills/ce-compound-refresh/SKILL.md","import_metadata":{"date":"2026-11-02","author":"@skillopedia","version":"v1","category":"general","category_label":"General"},"exact_dupes_collapsed_into_this":0},"version":"v1","category":"general","import_tag":"skills-sh-top20k-2026-11","description":"Refresh the repo's captured learnings against the current codebase. Use when auditing stale, overlapping, superseded, or drifted learnings; avoid general refactor, debugging, or code review unless the learnings store is explicit.","argument-hint":"[optional: scope hint — directory, filename, module, or keyword] [mode:non-interactive] "}},"renderedAt":1793661693965}

Compound Refresh Audit the learnings under against the current codebase, apply the maintenance actions the evidence supports, and deliver a complete per-doc report plus committed changes. The report and the corrected document set are the deliverables. The store only compounds value if every doc can be trusted. Mode Read now. It reads the mode off the arguments and defines what each mode may apply unattended, the stale-marking fallback, the question tools, and the bootstrap. Two rules hold in both modes. A failed write is recorded as recommended , and the run continues. And a question is asked…