Split generic voice linter engine from Kai's rule profile #830

Closed
opened 2026-07-31 09:54:00 +00:00 by coilyco-ops · 1 comment
Member

Outcome

Keep the executable voice-lint engine in AOS while moving Kai-specific rules and policy into AOS-Kai.

Current boundary problem

.agents/composed/writing-voice-guide-linter is implemented and shipped from AOS, but its rule set is explicitly Kai-specific. It checks Kai's pronouns, private email policy, and personal prose conventions. That makes a public reusable engine own personal runtime configuration.

The voice-skill cutover landed a generic adaptation method in AOS at 9e88abd7 and Kai-specific writing skills in AOS-Kai at 7839a81. The linter should follow the same layer split.

Scope

  • Define a generic linter engine and rule-profile contract in AOS.
  • Remove Kai-specific values, descriptions, and defaults from the generic AOS surface.
  • Add an AOS-Kai skill or profile that owns Kai's rules and invokes the generic engine.
  • Preserve the current deterministic checks for em dashes, italics, prose semicolons, prose tables, pronoun review, and the restricted email address.
  • Keep profile configuration at the lowest layer that fully determines it. The generic engine must not fetch runtime configuration from AOS-Kai or Lore.
  • Update role bindings, skill descriptions, docs, and cross-links to match the final ownership.
  • Preserve direct file and directory linting plus strict nonzero exit behavior.

Acceptance

  • AOS can lint against a non-Kai fixture profile without containing Kai-specific policy.
  • AOS-Kai owns and validates the complete Kai rule profile.
  • The Kai wrapper produces equivalent findings for representative current-rule fixtures.
  • The generic engine has schema and behavior tests for custom profiles.
  • No operational writing or linter configuration is loaded from Lore.
  • Both repositories pass their complete pre-commit suites.

Execution

This is a headless cross-repo refactor. Land AOS first, then AOS-Kai, so no committed consumer points at an unavailable generic surface.

## Outcome Keep the executable voice-lint engine in AOS while moving Kai-specific rules and policy into AOS-Kai. ## Current boundary problem `.agents/composed/writing-voice-guide-linter` is implemented and shipped from AOS, but its rule set is explicitly Kai-specific. It checks Kai's pronouns, private email policy, and personal prose conventions. That makes a public reusable engine own personal runtime configuration. The voice-skill cutover landed a generic adaptation method in AOS at `9e88abd7` and Kai-specific writing skills in AOS-Kai at `7839a81`. The linter should follow the same layer split. ## Scope * Define a generic linter engine and rule-profile contract in AOS. * Remove Kai-specific values, descriptions, and defaults from the generic AOS surface. * Add an AOS-Kai skill or profile that owns Kai's rules and invokes the generic engine. * Preserve the current deterministic checks for em dashes, italics, prose semicolons, prose tables, pronoun review, and the restricted email address. * Keep profile configuration at the lowest layer that fully determines it. The generic engine must not fetch runtime configuration from AOS-Kai or Lore. * Update role bindings, skill descriptions, docs, and cross-links to match the final ownership. * Preserve direct file and directory linting plus strict nonzero exit behavior. ## Acceptance * AOS can lint against a non-Kai fixture profile without containing Kai-specific policy. * AOS-Kai owns and validates the complete Kai rule profile. * The Kai wrapper produces equivalent findings for representative current-rule fixtures. * The generic engine has schema and behavior tests for custom profiles. * No operational writing or linter configuration is loaded from Lore. * Both repositories pass their complete pre-commit suites. ## Execution This is a headless cross-repo refactor. Land AOS first, then AOS-Kai, so no committed consumer points at an unavailable generic surface.
Author
Member

Both halves landed, AOS first as the execution note asks.

  • AOS - #1209, merged. The engine takes --profile <json> and holds no house style. id, pattern, hint, optional scope of span or line, optional regex flags.
  • AOS-Kai - 1292457 on main. kai-voice-guide-linter owns the profile, and director and exec gain a kai-voice-* selector, matching where AOS binds the engine. creator already carried *voice*.

Acceptance

  • AOS lints against a non-Kai fixture profile without Kai policy - tests/fixtures/voice-profile-example.json, and a test asserts Kai, she/her, coilysiren, gmail, em-dash, and the em-dash character itself do not appear in the engine source.
  • AOS-Kai owns and validates the complete profile - 12 tests: valid JSON, every pattern compiles, and each of the eight preserved rules is present by id.
  • Equivalent findings on representative fixtures - tested, not asserted. A fixture carrying every rule plus a fenced block produces the same ten findings under the profile as under the pre-split RULES list, and the test keeps its own copy of that list so the comparison stays real now the original is gone.
  • Schema and behaviour tests for custom profiles - 15 in AOS, including a parametrized set for every way a profile can be untrustworthy.
  • Profile config at the lowest layer that determines it - the engine reads a path it is handed and fetches nothing from AOS-Kai or Lore.
  • Direct file and directory linting, strict nonzero exit - preserved and tested.
  • Both suites pass - AOS 659 tests and full pre-commit. AOS-Kai pre-commit and 102 tests, with one pre-existing failure (test_committed_hardware_provider_resolves_through_agent_compose) that reproduces identically on stashed main.

One thing worth naming

coilysiren@gmail.com was tracked in the public agentic-os repo, inside the very rule that calls it leakable. It now lives only in the private repo. That was not in the issue's scope list and is the most concrete thing this refactor fixed.

Preserved by design

prose-table became a line-scoped rule rather than a hardcoded special case. The old code already treated it that way with a continue, so a punctuation-dense row reported once instead of under every span rule it matched. That is a profile capability now rather than engine behaviour, and both halves are tested.

Both halves landed, AOS first as the execution note asks. * **AOS** - #1209, merged. The engine takes `--profile <json>` and holds no house style. `id`, `pattern`, `hint`, optional `scope` of span or line, optional regex flags. * **AOS-Kai** - `1292457` on `main`. `kai-voice-guide-linter` owns the profile, and `director` and `exec` gain a `kai-voice-*` selector, matching where AOS binds the engine. `creator` already carried `*voice*`. ## Acceptance * **AOS lints against a non-Kai fixture profile without Kai policy** - `tests/fixtures/voice-profile-example.json`, and a test asserts `Kai`, `she/her`, `coilysiren`, `gmail`, `em-dash`, and the em-dash character itself do not appear in the engine source. * **AOS-Kai owns and validates the complete profile** - 12 tests: valid JSON, every pattern compiles, and each of the eight preserved rules is present by id. * **Equivalent findings on representative fixtures** - tested, not asserted. A fixture carrying every rule plus a fenced block produces the same ten findings under the profile as under the pre-split `RULES` list, and the test keeps its own copy of that list so the comparison stays real now the original is gone. * **Schema and behaviour tests for custom profiles** - 15 in AOS, including a parametrized set for every way a profile can be untrustworthy. * **Profile config at the lowest layer that determines it** - the engine reads a path it is handed and fetches nothing from AOS-Kai or Lore. * **Direct file and directory linting, strict nonzero exit** - preserved and tested. * **Both suites pass** - AOS 659 tests and full pre-commit. AOS-Kai pre-commit and 102 tests, with one pre-existing failure (`test_committed_hardware_provider_resolves_through_agent_compose`) that reproduces identically on stashed main. ## One thing worth naming `coilysiren@gmail.com` was tracked in the **public** agentic-os repo, inside the very rule that calls it leakable. It now lives only in the private repo. That was not in the issue's scope list and is the most concrete thing this refactor fixed. ## Preserved by design `prose-table` became a line-scoped rule rather than a hardcoded special case. The old code already treated it that way with a `continue`, so a punctuation-dense row reported once instead of under every span rule it matched. That is a profile capability now rather than engine behaviour, and both halves are tested.
Sign in to join this conversation.
No project
No assignees
1 participant
Notifications
Due date
The due date is invalid or out of range. Please use the format "yyyy-mm-dd".

No due date set.

Dependencies

No dependencies set

Reference
coilyco-flight-deck/agentic-os#830
No description provided.