Repository navigation
v0.2.0 — engineering criteria leave the Skills
Engineering criteria leave the Skills, and the checks gain teeth.
67 skills · 29 rules · 19 specs · 1 protocol
Review criteria are canonical Rules now
They used to live inside the Skills that executed them, so they could not be applied before coding, configured per project, or cited afterwards. Nine modeled Rule sets now carry 104 items across architecture, security, reliability, performance, observability, testing, implementation alignment, task quality and technical design quality — with stable identifiers that are never reused, applicability profiles, project parameters and auditable waivers. Execution stays in the Skills, six of which are new.
Severity is graded by what happens if a finding is left unfixed, so 63 of the 104 block a gate rather than all of them.
Research entries
deep-research, policy-research, market-research, competitive-research and product-opportunity-analysis, with an internal assessment behind the package entry, and the Research Report and Opportunity Package contracts they pass between them.
English is the primary language
The repository reverses from Chinese to English. The immutable records stay as written — existing ADRs, released changelog entries and design snapshots — because rewriting them would falsify what they record.
CI blocks instead of advising
markdownlint over its full default rule set, relative links and reference direction between asset layers, orphaned documents, temporary filenames, and temporary documents that are not labelled as one.
Each check has a fixture suite, and scripts/mutation-check.py seeds 43 defects to require every one of those suites to fail when its checker is broken. A suite that asserts findings over fixtures passes just as happily when the checker has stopped looking; that is what the harness is for.
Breaking changes
- Skills renamed and removed
- Review Skills at 2.x, as their criteria leave them for the canonical Rules
- Chinese-first documents rewritten in English
Upgrading
cortex updateFull changelog — 23 entries
Added
- 语言方案反转:仓库主语言从中文切换为英文。
docs/LANGUAGE_SCHEME.md重写为英文并反转原则——英文为默认,中文仅保留于不可变记录(既有 ADR、已发布 CHANGELOG 条目、设计快照)。这三类按rules/adr-management.md「写入后不改」保留原文,改写它们等于伪造时点记录。新增第 6 节「翻译质量门槛」:明确禁止机器翻译,要求「重写而非翻译」——本仓库已为机翻付过一次代价(164 处重复直译标题、27 处误译),反向迁移不能重演。第 7 节列出 E0–E6 分阶段迁移表,每阶段独立可发布;skills/INDEX.md与全部 frontmatter 全程保持英文,因此迁移期间发现与技能匹配不受影响。 - E1 阶段完成:
README.md/AGENTS.md/CONTRIBUTING.md/SECURITY.md/CODE_OF_CONDUCT.md改写为英文。CONTRIBUTING 新增一条硬要求——外部派生技能的许可证兼容性:本仓库为 MIT,派生自 copyleft 或非商业上游(CC BY-NC-SA、AGPL 等)的技能无法以 MIT 再分发,不予接受,须在动手前而非事后核对上游许可证。README 标题变更导致 15 个技能 README 的锚点#-安装与使用失效,已同步更新为#-install-and-use。 - Engineering review criteria move out of the Skills that executed them and into versioned Rule sets. They had lived inside the cognitive review Skills, so they could not be applied before coding, configured per project, or cited afterwards.
specs/rule-modeling.mddefinesRULE_MODEL_V1— stable item identifiers that are never reused, three applicability levels, parameter provenance and the waiver object — and nine Rule sets now carry 102 items across architecture, security, reliability, performance, observability, testing, implementation alignment, task quality and technical design quality. Of those, 53 are baseline and apply wherever the set's scope is present, 42 are gated on a profile and 7 on a declared project parameter. Severity is graded by what happens if a finding is left unfixed, so 63 block the gate rather than all 102: absent evidence such as a missing test or measurement raises future risk rather than causing a present failure, and is minor.rules/workflow-rule-governance.mdconstrains identifier stability, compatibility and the activation evidence each enforcement strength owes — and says when a set should adopt the model at all, which is only when its items must be waived, counted in coverage or cited by another artifact, so requirement and functional design quality deliberately stay checklists. Six review Skills are new (functional design, technical design, tasks, implementation alignment, observability, reliability) and four cognitive reviewers now execute the canonical Rules instead of their own embedded lists.scripts/validate-rules.pyvalidates every modeled document and item, andscripts/test-rule-scenarios.pydecides the 15 items that are both automated and blocking over nine representative shapes drawn from three populations — a library, a layered application and a distributed service. Both run in CI. The four rewritten reviewers went to a major version —review-architecture,review-performance,review-securityandreview-testing, withreview-requirementsalongside them — although theircode-scope → findings-listcontract did not change: what changed was the authority their criteria come from and what completeness now means, which is breaking for a caller relying on the old embedded checklists even though the artifact types still match. Recorded indocs/adr/0012-adopt-profiled-engineering-rules.md. - Five research entries, an internal assessment, and the two contracts they pass between them.
deep-research,policy-research,market-research,competitive-researchandproduct-opportunity-analysisare user-invocable;assess-product-opportunitycarries the recommendation logic and is internal by repository metadata, while the package entry selects the relevant lanes and aggregates their output.specs/research-evidence.mddefines a portable Research Report whose decision-relevant statements trace to a source or to an explicit gap, andspecs/opportunity-package.mdthe decision layer built on it.docs/adr/0013-research-skill-entry-names.mdrecords the narrow naming exception: four of the five names are noun-led and the package entry lacks the usualorchestrate-prefix, which is kept because renaming would break commands already promised to users, and it does not loosen the verb-noun rule for anything else.scripts/test-research-artifacts.pyvalidates 10 positive fixtures and 26 negative cases in CI, including a conflicting report, a stale source and an inaccessible one. Live routing through an authenticated host is not yet verified;docs/references/research-skills-smoke-test.mdseparates what was checked locally from what still waits. - Two criteria for code that has outlived its use, which the Rule sets had no item for.
architecture-quality1.0.1 → 1.1.0 adds ARC-010 and ARC-011, bringing the nine sets to 104 items. ARC-010 requires code no consumer reaches to be removed rather than commented out, disabled behind a permanent flag or kept in case it is wanted again, and fixes what counts as knowing it is unreached: unused-symbol analysis over the built artifact, plus a runtime signal over one full business cycle for anything the analyzer cannot resolve — reflection, a class named in configuration, dynamic dispatch, a consumer in another repository. Its pass condition says outright that a clean analyzer run is not evidence about a symbol the analyzer cannot see, which is the failure that deletes something month-end still calls. ARC-011 requires a deprecation marker to record who removes it, by which release or date, and what a caller migrates to; a marker carrying none of the three is a second implementation kept indefinitely rather than a migration in progress. Both areminorandtool-assisted, graded by the set's own rule that debt raising future cost does not block a gate the way a present failure does.review-architecturepicks them up with no change to its execution, since it runs whichever items the active Rule version carries; 2.0.1 → 2.1.0 adds a worked example for each, because both turn on a distinction a reviewer gets wrong by default — an analyzer reporting nothing is not a pass for what it cannot resolve. Neither owes a fixture test — constraint 8 ofrules/workflow-rule-governance.mdasks that of automated blocking items — but the half of each that is mechanical, deciding the obligation once the evidence is in hand, is pinned inscripts/test-rule-scenarios.pyregardless, over a fourth shape that brings it to 10: a plugin host that loads handlers by name from configuration, where static analysis is weakest. Writing those cases found a hole in ARC-010 as first published: its pass condition let any removal through, so deleting a reflection-reached symbol on the analyzer's word alone would have passed — the exact failure the item was written to prevent. The condition now requires a runtime signal in that direction too. Seven mutations of the decision were seeded and all seven were caught.review-implementation-alignment1.0.0 → 1.1.0 states the boundary rather than taking the items on: delivered code nothing reaches is its own, under ALN-003, but the implementation a change replaced and left behind is ARC-010's, decided by the sibling engineering gate over the same scope. The two read alike and would otherwise be reported twice or by neither.review-codebase1.0.1 → 1.1.0 names both in its tech-debt dimension, which is where a reader first meets them, and routes the decision rather than taking it: neither is settled by reading the code, since one needs a runtime signal and the other needs the fields recorded beside the marker. CONTRIBUTING.mdgains a Checks section. There had been no list: the scripts were named in one sentence inside "Adding a skill", which is the wrong home for a checker that has nothing to do with skills, and a contributor changing a Rule or a script had nothing to go on. The table says which check to run for which kind of change, andmutation-check.pycarries a paragraph of its own, because "run the thing that checks the checks" earns an explanation rather than a line in a table.scripts/mutation-test.shis folded intoscripts/mutation-check.py, which now covers both shapes of perturbation under one frame: a defect seeded into a checker, and an edit made to an already-translated document that the translation verifier must block. Folding it in is how its state was discovered — eleven of its fifteen cases had stopped matchingrules/task-quality.md, which became a modeled Rule set while the cases still quoted its old checklist form. It skipped them and reported4/15, and it was never in CI, so nobody read the number. The anchors are rewritten against the current document, and two were retargeted after the run showed them landing on a soft invariant: a dropped table row and a dropped heading are reported for judgement, not blocked, so the cases now break frontmatter and block count instead — the verifier was right and the expectation was wrong. Forty-three perturbations, all producing the expected verdict, including two controls that must be allowed through.scripts/mutation-check.pymakes the mutation runs repeatable and puts them in CI. They had been throwaway scripts written beside each test and discarded, so the claim that a suite can fail was true on the day and unverifiable afterwards. Twenty-eight defects are seeded — 7 into the link checker, 14 into the document-hygiene checker, 7 into the Rule scenario evaluator — and each must turn its test red. A mutation whose pattern no longer matches is a failure rather than a skip, because a refactor that moves the code takes the coverage with it while the run stays green. Where the same line appears in two functions, a scope marker picks the one under test; without it the first occurrence absorbed the mutation and a branch went untested, which had already happened once. The harness was itself checked against its three failure modes: a no-op mutation, a stale pattern and an unfindable scope.- The link checker's fixtures grow from two seeded defects to seven mutations, matching the other three checks. The tree gains an anchor that must still resolve, an absolute URL and a mail address that are not repository paths, and a guide outside
rules/,specs/andprotocols/linking a Skill directly — the reference-direction rule binds governance assets, not prose, and nothing had been asserting that. All seven are caught: the code-span strip, the fence matched at any indent, the fence closed on its own marker length so a longer one can hold a shorter, the fence skip itself, the absolute-link exclusion, the anchor strip, and the governance gate. - The reachability and filename checks get the fixture tree they had been running without.
tests/fixtures/doc-graphcarries an orphan, a tombstone unlinked on purpose, a directory README that is an entry point rather than an orphan, a backup beside the file it copies, a link shown inside a fence that must not make its target reachable, and two lowercase names —review-security.mdandrelease-notes.md— that the uppercase process-record words must not fire on. Seven mutations were seeded and all seven caught, but three only after the shapes were extended: nothing had distinguished a legitimate lowercase name whose token is on the list, and nothing had exercised the fence skip. A fourth mutation survived because the code it targeted reached nothing — resolving a link to a directory into that directory's index, which changes no reachability when every index and README is already an entry point. It is deleted rather than given a fixture, on the same reasoning ARC-010 states. - The temporary-document patterns are enforced, not just written down.
scripts/check-doc-hygiene.pygains a third check and the CI step covers it, decided the way the rule reads: a body pattern identifies a document as temporary, and constraint 4 then requires such a document to carry a dated or.draftname inside a dedicated directory. The finding is therefore an unlabelled one — the same sentence is compliant indocs/designs/2026-09-17-…and a defect in a Spec. An ADR is exempt because narration is its genre, the changelog because it is narration throughout, and a pattern is exempt where it is shown rather than used: under an anti-pattern heading, marked with a cross, inside a fence, or inside quotation marks. That last one carries most of the weight, sincewrite a rule, not "we decided to follow the convention"quotes what it forbids.scripts/test-doc-hygiene.pypins it over ten shapes, and seven mutations of the decision were seeded and all seven caught — two of them only after the shapes were extended, because a dated name outside a dedicated directory had no fixture and one mutation had been silently rewriting the wrong function. - Eleven review Skills drop their
## Change recordsection, each taking a patch bump.rules/workflow-documentation.mdtreats version narration in a body as a temporary-document marker and sends it to the changelog, and the sections had drifted into exactly that — "Version 2.0.1 removes a stale example pin" and the like. The descriptive bullets beside them restated what the frontmatter and the body already say. One thing they held was recorded nowhere else and is preserved above: why four reviewers took a major version although their artifact types stayed compatible. The rule's own grep list was Chinese-only and caught none of them. workflow-documentation1.0.0 → 1.1.0 enumerates the English grep set the rule had been promising, for both body patterns and conversational residue. Every candidate was measured against the repository before it went in, and two were dropped on the numbers:\bTBD\bfired 19 times, nearly all of them Skills telling an agent to writeTBDwhere a value cannot be inferred, and\bto be built\bfired on a metric whose data source is genuinely pending — a pattern whose hits are mostly legitimate only teaches a reader to skim past the report. The finished set matches two documents across 244. Neither is a violation: the rule's constraint 4 says a body pattern identifies a document as temporary and such a document must then be labelled, so a dated design snapshot citing "the earlier discussion" is compliant, and the other hit quotes the form inside quotation marks. The exception for a pattern shown as a counter-example widens from this rule alone to any Rule or Spec quoting one in a labelled anti-pattern list, which is what four of the six raw hits were.- Enforcement for the documentation criteria that had none.
rules/doc-health-criteria.md§2 andrules/repo-structure-hygiene.md§4 defined what an orphaned document and a stale filename are, but nothing ran them:plan-nextroutes both to "the runtime / linter / CI", and there was no such check.scripts/check-doc-hygiene.pynow decides the part a path and a link graph can prove — reachability from the README or a directory's index, backup suffixes, and process-record words matched only in uppercase so the 26review-*Skills are not swept up. A document markedstatus: deprecatedis exempt, because a tombstone such asdocs/guides/protocols-registry.mdis unlinked on purpose, to catch a bookmark arriving from outside. Eight real orphans were found and cleared; four design snapshots and a smoke record now hang off a newdocs/designs/README.md. Forward-tested against five shapes before wiring, which caught it missingusage.md.bak, since a backup file is not a.mdfile.
Fixed
- Eight dead links under
docs/adr/, and the CI allowlist that excused them. The link job skipped every broken link in that directory, on the stated grounds that older records deliberately reference assets since deleted. Six of the eight were not that: written as../../../specs/skill.mdfromdocs/adr/, they climb past the repository root and never resolved, one of them beside a correctly written link in the same table. Each is downgraded to its label text under the maintenancerules/adr-management.md§4 now permits — no word of any record changed, and no link repointed at a renamed successor. The allowlist is gone, so a broken link anywhere fails the build. - The numbered procedures in
docs/guides/protocols-usage.md, whose rendered numbering did not survive. Each step's code block sat at column zero, and a fence at column zero ends the list, so every following step began a fresh list that restarted at one. Eleven blocks are indented into the item they belong to. markdownlint's own autofix would instead have renumbered the steps to 1./1./1., preserving the broken structure. A table row indocs/guides/research-skills-usage.mdwas also missing its leading pipe. - Two CI guards that could not tell a link from a document showing what a link looks like.
rules/workflow-documentation.mdgrants itself that exception in prose — a rule defining a no-go zone has to display the forms it forbids — but the greps enforcing reference direction and relative links did not honour it, sorules/adr-management.mdhad to carry a fabricated path in its counter-example. Both now share one extractor inscripts/check-markdown-links.py, which skips code spans and fences, matches a fence at any indent (the previous one required column zero, and blocks nested in list items are indented) and closes a fence on its own marker.scripts/test-markdown-links.pyasserts it against a fixture tree; two seeded defects confirmed the test can fail.
Changed
- markdownlint blocks instead of advising. It was added advisory on a stated plan — run the default rule set in full, collect the real violations, then enforce — and the collection is done: 142 findings under the version the action pins, and 1,963 under a newer one, where a single new table rule accounts for 1,821. Ninety-four were cleared by the tool's own autofix, run with ordered-list renumbering held back because its fix turns a list continuing from an earlier one into a fresh list. The rest were fixed by hand: 16 angle-bracket placeholders into code spans, languages onto two fences, three ambiguous adjacent blockquotes joined. Two rules are off rather than obeyed — bold labels used to group a list, which the repository writes that way throughout and five snapshot records can never change, and the top-level heading requirement for a pull request template that opens under GitHub's own heading. The table rule is pinned to
compact, since left at its default it measures each table against whichever style is closest and leaves findings its own fixer cannot resolve when two tie. Zero findings now, under both versions. - The root
.markdownlint.jsonbecomes.markdownlint.yaml, so each decision carries its reason inline.docs/adranddocs/designscarry nested configurations that extend it and switch off the rules whose remedy would restructure prose.tests/fixturesleaves the globs: those files are deliberately malformed inputs for the validators, so linting them measures nothing and an autofix pass could rewrite a test's input. rules/adr-management.md1.0.0 → 1.1.0: markup maintenance on a written ADR is not a content revision. "Not edited after writing" protects the words of the record, not a piece of markup that no longer does anything, so a relative link whose target never resolved may be downgraded to its own label text. Repointing it at the target's successor stays forbidden — it asserts a continuity the decision never claimed — as does rewriting the prose around it.docs/LANGUAGE_SCHEME.md, which quoted the old wording, follows.skills/INDEX.mdis now generated from each skill's own frontmatter byscripts/sync-skills-index.py, and carries thetagsandtriggersthat AGENTS.md §4 ranks on. The registry held neither before, so the first two steps of the documented matching algorithm had no data to rank and it fell through to description similarity without saying so; 18 of 61 descriptions had also drifted from the skills they register. CI now compares the registry with the skills field by field (--check) instead of comparing counts, andscripts/test-skills-index.pygives that comparison a denominator —--checkmeasures the generator's output against a file the same generator wrote, so on its own it cannot see a parsing bug. Contributors regenerate instead of hand-editing;CONTRIBUTING.mdand the PR template say so, andtriggersis now listed among the required frontmatter fields it had always been in practice.- Reference direction between asset layers is stated in
docs/architecture/terminology.md§II and enforced in CI: a Spec, Protocol or Rule names the capability that applies it and never links intoskills/. Twelve such links were removed fromrules/roadmap-quality.md,rules/standards-agent-testing.md,specs/nats-messaging.md,specs/cross-team-contract.mdandspecs/agent-test-modeling.md— a contract that links to one implementation of itself depends on it, and a copy taken into another repository carries a path to a capability that is not there. The deliberate Spec-and-Rule pairing is recorded in the same section, so their mutual references are not re-reported as a dependency cycle. requirement-intake-triage-update-contract.mdmoved fromspecs/to.cortex/contracts/, mirroring the vendored contracts under.cortex/vendor/contracts/, and itsartifact_typechanged fromguidetocontract. It is a contract instance — one outward promise to one named consumer — not a data contract describing a kind of artifact, which is whatspecs/holds.contract_versionstays at 1.0.0 because the promise itself did not change.
Full diff: v0.1.0...v0.2.0