Skip to content

The Scorers and Proposals pages are Harbor's (0.23.0) - #29

Merged
adamfortuna merged 1 commit into
mainfrom
quality-pages
Nov 15, 2026
Merged

adamfortuna merged 1 commit into
mainfrom
quality-pages

Conversation

@adamfortuna

@adamfortuna adamfortuna commented Nov 14, 2026 •

Copy link
Copy Markdown
Contributor

Step 7a of moving the Factory's sections into Harbor: Scorers and Proposals. Review policy is not in this.

What a site with no code of its own gets

  • Scorers (/factory/scorers): the list, a scorer's page with its pass rate by week and its last fifty verdicts, and the form.
  • Proposals (/factory/proposals): the list by status, a proposal's page with the change line by line and the failed runs behind it, Apply and Dismiss.
  • A run's page shows its scores, with "Score now" (POST /factory/runs/:id/score), and refreshes while a verdict is pending.
  • The records (Harbor::Scorer, Harbor::ScorerResult, Harbor::Proposal) on scorers, scorer_results and improvement_proposals, created by a migration where they don't exist.
  • The jobs: Harbor::Scorers::SampleJob, Harbor::Scorers::EvaluateJob (the judge is a child run of the run it grades) and Harbor::Proposals::CheckJob (runs as a run made beforehand).

What it does not get: the judge and the drafter

Harbor does not run the model that judges a run, or the agent run that drafts proposals. Both read transcripts, which can carry text written by anyone who could comment on the work, so the model has to be kept to that one file, and how is a site's to decide. An agent session starts a named agent in a checkout of a repository and fetches a fixed set of files, so a judge built on one would see the repository and not the transcript. I did not build a default on it.

  • config.scorer_judge is called with a Harbor::Scorers::Judgement and returns the model's final text (or answers, fails, says it is busy, or answers later).
  • config.proposal_drafter is called with a batch of one scorer's failures on one agent, and hands its run's answer to Harbor::Proposals::Recorder.

Without them the pages work and nothing is judged or drafted: no run is sampled, the Scorers page says there is no judge, the Proposals page offers no "Run the check now", and a judgement or a check started anyway ends as an error naming the setting.

Places for a host

  • config.scorer_class, config.proposal_class, config.scorer_judge_wait, config.site_name.
  • Harbor::Proposals.register_target: a host's own kind of proposal.
  • Partials in app/views/harbor/proposals/ (_proposal_badges, _show_actions, _show_extras, _change; _intro, _index_actions and _guide in place of Harbor's) and app/views/harbor/scorers/ (_self_improvement_note).

README "Scorers" and "Proposals" describe all of it; the CHANGELOG has the upgrade steps from 0.21.

Shared files

On top of 0.22.0 (Automations). Where both touched a file, both are kept: config/routes.rb, app/models/harbor/run.rb, lib/harbor/nav.rb (the two Quality entries), lib/harbor/configuration.rb (one block and six defaults), lib/harbor.rb, README.md, CHANGELOG.md, the dummy schema and the menu expectations in test/host_pages_test.rb, test/section_test.rb and test/nav_test.rb.

quality-pages-on-0.21 is the same change on v0.21.0, as it was built and checked against its host.

Checked

bin/test: 766 runs, 6482 assertions, 0 failures, 0 errors, 0 skips. bundle exec rubocop: no offenses.

… a run's scores and the jobs behind them

Harbor::ScorersController serves /factory/scorers: the list, a scorer's page
with its pass rate by week and its last verdicts, and the form that creates
and edits one. Harbor::ProposalsController serves /factory/proposals: the list
by status, a proposal's page with the change line by line and the failed runs
behind it, Apply, Dismiss and "Run the check now". A run's page shows what the
scorers made of it, with "Score now" (POST /factory/runs/:id/score). The
menu's Scorers and Proposals entries are the engine's own routes. A site with
no code of its own gets all of it.

The records are Harbor::Scorer, Harbor::ScorerResult and Harbor::Proposal, on
the tables scorers, scorer_results and improvement_proposals, which a
migration creates where they don't exist. Harbor::Run has scorer_results,
scorable?, awaiting_verdict? and judge_runs, leaves a judge out of
delegated_runs, and is sampled when it finishes.

Harbor::Scorers::SampleJob offers a finished agent run to the scorers that
apply. Harbor::Scorers::EvaluateJob judges one run with one scorer as a child
run of it. Harbor::Proposals::CheckJob hands a scorer's unreviewed failures,
by agent, over to be drafted from, and Harbor::Proposals::Recorder turns the
drafting run's answer into proposals.

Harbor does not run the judge or the drafting run: both read transcripts, and
keeping a model to one file is a site's to do. config.scorer_judge is called
with a Harbor::Scorers::Judgement and returns the model's final text;
config.proposal_drafter is called with a batch of failures. Without them the
pages work and nothing is judged or drafted: no run is sampled, and a
judgement or a check started by hand ends as an error naming the setting.

A host adds its own kinds of proposal with Harbor::Proposals.register_target,
its own classes with config.scorer_class and config.proposal_class, and its
own markup with partials in app/views/harbor/proposals/ (_proposal_badges,
_show_actions, _show_extras, _change, and _intro, _index_actions and _guide in
place of Harbor's) and app/views/harbor/scorers/ (_self_improvement_note).
0.24.0.
@adamfortuna
adamfortuna merged commit acc25c8 into main Nov 15, 2026
2 checks passed
@adamfortuna
adamfortuna deleted the quality-pages branch November 15, 2026 00:00
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