Skip to content

refactor(models): enforce canonical routing names and target authority #391

Description

@decode2

Outcome

Enforce strict canonical model-routing names and explicit global/project config and profile target authority as the canonical-boundary slice of the #382 chain. This unit adds the canonical boundary and alias denial without changing durable writes or profile materialization.

Chain context

Dependency diagram:

main
  └─ #389 shared types/normalization, sync/async authority, compatibility wrappers
       └─ #396 fail-closed apply and profile safety
            └─ #395 direct export contract/tests plus UI/lifecycle consumers
                 └─ 📍 #391 strict canonical names and target authority
                      └─ durable write
                           └─ materialization

Scope and acceptance criteria

  • Add one shared canonical name validator and use it from saved-config validation and both sync and async metadata discovery.
  • Metadata parsing may trim surrounding YAML whitespace before validation. Saved-config top-level keys have a stricter boundary: each raw key must already equal its canonical trimmed form. A padded saved-config key is invalid and must not be silently canonicalized.
  • Preserve valid unknown names, including internal spaces and supported punctuation. Reject quote characters and C0/C1 control characters at both metadata and saved-config boundaries. C0/C1 rejection includes the control ranges already covered by the package contract, including U+0000 through U+001F and U+007F through U+009F.
  • Validate the complete saved document. Any invalid top-level name or routing entry invalidates the document with its path; valid siblings must not be silently retained while invalid data is discarded.
  • Preserve the existing value contract: JSON null is invalid, the string inherit remains a literal model id, and omission or an empty routing entry retains its current omission semantics.
  • Add one explicit resolver for global and project model-config and profile paths. Deny normalized aliases before any read, apply, or write operation, with platform-appropriate comparison, including the cwd == home case and Windows case behavior.
  • Add only the minimal save-validation bridge needed to delegate to the shared normalizer. Do not redesign the write algorithm.
  • Keep the real saved-config, metadata discovery, and sync and async production paths on the shared authority. Do not add a test-only runtime seam or a fake production caller.
  • Add differential tests proving a padded saved key fails closed before apply or write, existing profile bytes remain unchanged, unrelated profile fields remain byte-identical, and alias denial happens before any config or profile write.
  • Explicitly create every test fixture directory before writing fixtures, including the root/agents directory used by metadata-discovery tests.

Intentionally out of scope

Strict TDD and verification

Strict TDD is required. The RED phase must be an executable assertion-level failure after dependency hydration, not a missing-module or environment error. The current governance snapshot records assertion-level RED and focused GREEN 4/4 for the combined candidate only. It is not issue completion evidence for this canonical-boundary slice. The implementation PR must report its own observed evidence before claiming completion.

Environment prerequisite: use an authorized implementation environment with dependencies hydrated by the repository package manager, pnpm@11.1.1, including @earendil-works/pi-tui.

Run the focused and package-supported commands after the test file exists:

node --experimental-strip-types --test tests/model-routing-authority.test.ts
node --experimental-strip-types --test tests/gentle-ai.test.ts
pnpm test
  • RED: add the smallest assertions for padded saved keys, complete-document rejection, sync and async canonical-name parity, alias denial before writes, and null and inherit preservation. Record the observed assertion failures after dependencies are available.
  • GREEN: implement only the shared validator, strict document boundary, explicit target resolver, and minimal save-validation bridge. Record the focused test result.
  • TRIANGULATE: exercise sync and async discovery, valid unknown internal spaces and punctuation, quote and C0/C1 rejection, global and project selection, cwd == home, Windows path comparison behavior, invalid-source preservation, explicit fixture-directory creation, and the real /gentle:models read and apply path.
  • REFACTOR: remove superseded duplicate validation without changing behavior, then rerun the focused commands and check-only syntax validation.

Review workload forecast and hard stop

Forecast only, measured against the clean immediate main base after #389, #396, and #395 merge: 230 lower / 300 realistic / 370 upper A+D. The hard stop is above 400 A+D. No size:exception is permitted. If the clean diff exceeds 400, stop before publication and return to design for another causal split. Do not line-golf the diff or remove the tests that establish the safety boundary.

Activity

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Metadata

Metadata

Assignees

No one assigned

    Labels

    enhancementNew feature or requeststatus:approvedIssue approved by maintainer; PR may be openedtype:refactorCode refactoring without behavior change

    Type

    No type

    Projects

    No projects

      Milestone

      No milestone

      Relationships

      None yet

      Development

      No branches or pull requests

      Issue actions