Skip to content

feat(models): pharn-oss owns the models block — init copies it, update migrates it, status labels it - #231

Merged
PrzemekGalarowicz merged 2 commits into
mainfrom
feat/models-pharn-oss-owned
Sep 25, 2026
Merged

PrzemekGalarowicz merged 2 commits into
mainfrom
feat/models-pharn-oss-owned

Conversation

@PrzemekGalarowicz

Copy link
Copy Markdown
Contributor

Roadmap Phase 2.0 (token-reduction roadmap, approved by the maintainer 2026-09-25).

Why

Pre-check P2 found three things wrong with the models block pharn init wrote (hardcoded in src/lib/model-routing.ts):

  1. pharn-oss's own checker, installed as pharn/floor/check-model-config.mjs, REDs it three times: no default inside stages, and opus-4-8 is not an accepted model. Re-measured against pharn-oss main @ 767bf61.
  2. claude --model sonnet-5 → 404 unrecognized_model.
  3. It disagreed with the installed command frontmatter: plan = opus-4-8 · max, where the command says opus/high.

Decision: pharn-oss owns the models schema

CLAUDE.md is amended: the CLI still owns the pharn.config.json schema — for every key except models.

What changed

  • init copies pharn-oss's root pharn.config.json models block verbatim. If upstream ships none, it writes none. If the block fails pharn-oss's rules, it writes none and says why. The block is checked at the ingest boundary and recorded in pharn.records.json under pharn.config.json#/models.

  • Validation: the CLI's MODEL_IDS / EFFORT_LEVELS / PIPELINE_STAGES are gone.

    • src/lib/model-config.ts is a copy of pharn-oss's checker's validate/resolve rules.
    • tests/model-config-parity.test.ts pins it to the vendored checker: a sha256 pin, the stage/alias/regex/effort sets read out of its source, and verdict + RED-line + resolve parity over a 93-case corpus that must reach every validate-path RED kind.
    • Why not delegate to the installed checker: the CLI never executes a file it installs (THREAT-MODEL §1). status --strict runs in CI on PRs, and at init the only checker is inside the untrusted clone.
  • update decides the block through the per-file rows. It calls decideFileAction over the block's hash:

    • absent → restored;
    • identical → ok;
    • pharn's (its record, or one of the two defaults older CLIs wrote) → replaced;
    • the user's → kept;
    • --force → pharn.config.json backed up, then replaced.

    An edited old-format block is converted, not reset: default → stages.default, and opus-4-8/sonnet-5/fable-5/haiku-4-5 → opus/sonnet/fable/haiku. Anything unconvertible is named and left as is. The migration reaches installs already at the current skills version, and the gate is bounded. A kept block never withholds the version.

  • status (and the init summary) shows every product stage resolved, under a truthful label: Claude Code applies each command's frontmatter, and the block is the source of truth that frontmatter is held to (check-model-config.mjs agreement). It no longer presents the block as routing.

  • Config loading: readPharnConfig no longer validates models, so no command refuses to run over it.

  • Docs (pharn-config, pharn-records, init/update/status/add/list, roadmap, troubleshooting, contributing), CLAUDE.md and CHANGELOG.md updated.

Verification

  • /pharn-dev-ship chain, 2 iterations: validate exit 0, regress no-regressions, verify PASS, check-ship STOP_GREEN. Artifacts: .dev/features/models-pharn-oss-owned/.
  • The review ran with an independent read-only probe. It found two real defects, both fixed with tests that fail without the fix:
    • a converted old default lost its authorship;
    • an unserializable upstream block could half-install.
  • npm run check green; coverage 97.61 / 93.32 / 98.43 / 98.44.
  • Live against pharn-oss main, from a project holding the 0.6.0 default:
    • pharn update --yes replaced the block;
    • the installed check-model-config.mjs then passed validate (12 stages) and agreement (11/11 product stages);
    • a second run said "Already up to date".

Gates

GATE 1 (plan) and GATE 2 (fix, then merge) were decided by the model under the maintainer's delegation of 2026-09-25, recorded as such in SHIP.md. They are not human approvals.

For the maintainer — human-only reconciliations (protected docs, not edited)

  • CONSTITUTION.md P3: "this CLI owns the pharn.config.json schema" is now true for every key except models.
  • THREAT-MODEL.md §3.1: models is listed among the local-origin fields. It is now a fourth network-derived field, validated at ingest by checkModelsBlock.

pharn-oss should raise MIN_CLI to 0.7.0 only after npm has 0.7.0.

🤖 Generated with Claude Code

…e migrates it, status labels it

Roadmap Phase 2.0. The CLI hardcoded its own `models` default (ids
`opus-4-8`/`sonnet-5`/…, a top-level `default`) that pharn-oss's own checker
REDs three times, that `claude --model sonnet-5` rejects, and that disagreed
with the installed command frontmatter.

- pharn-oss now owns the `models` schema and defaults (CLAUDE.md amended).
  `init` copies pharn-oss's root `models` block verbatim — none when it ships
  none — checked at the ingest boundary.
- The CLI's MODEL_IDS / EFFORT_LEVELS / PIPELINE_STAGES are retired.
  `lib/model-config.ts` is a copy of pharn-oss's `check-model-config.mjs`
  validate/resolve rules, pinned by `tests/model-config-parity.test.ts`
  against the vendored checker (sha256, constants read from its source,
  93-case verdict + RED-line + resolve parity). A copy, not a call: the CLI
  never executes a file it installs (THREAT-MODEL §1).
- `update` decides the block with the per-file rows (`decideFileAction`, over
  the block's hash, recorded as `pharn.config.json#/models`): absent →
  restored, pharn's (record or an old default) → updated, the user's → kept,
  `--force` → config backed up, then replaced. An edited pre-0.7.0 block is
  converted (default → stages.default, old ids → aliases), never reset;
  anything unconvertible is named and left as is. The migration reaches
  current installs; the gate is bounded.
- `status` and `init` show every product stage resolved, under a truthful
  label: Claude Code applies each command's frontmatter; the block is the
  source of truth it is held to.
- `readPharnConfig` no longer validates `models`, so no command refuses to
  run over a block this CLI does not own.

Pipeline: .dev/features/models-pharn-oss-owned/ (PLAN, GRILL, REGRESSION,
VERIFY, REVIEW, SHIP). Floor verdicts (iteration 2): validate=0,
regress=no-regressions, verify=PASS, check-ship=STOP_GREEN. GATE 1 and GATE 2
were decided by the model under the maintainer's delegation of 2026-09-25.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
@coderabbitai

coderabbitai Bot commented Sep 25, 2026 •

Copy link
Copy Markdown

Important

  • 🔍 Trigger review

This repository does not receive automatic reviews because it has fewer than 10 stars.

⚙️ Run configuration

Configuration used: defaults

Review profile: CHILL

Plan: Advanced

Run ID: 3a53575c-c707-45df-b89c-0cf68fac43d9


Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out.

❤️ Share

Comment @coderabbitai help to get the list of available commands.

picocolors enables color when CI is set, so pc.dim's escape codes counted
toward the 70-column bound and a 62-column line read as 71.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
@PrzemekGalarowicz
PrzemekGalarowicz merged commit 9bd4e30 into main Sep 25, 2026
14 checks passed
@PrzemekGalarowicz
PrzemekGalarowicz deleted the feat/models-pharn-oss-owned branch September 25, 2026 22:57
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant