Skip to content

feat(cli): add a per-stage accept-all to curate and honor review (#385) - #509

Merged
jasonssdev merged 1 commit into
mainfrom
feat/385-per-stage-accept
Aug 9, 2026
Merged

feat(cli): add a per-stage accept-all to curate and honor review (#385)#509
jasonssdev merged 1 commit into
mainfrom
feat/385-per-stage-accept

Conversation

@jasonssdev

Copy link
Copy Markdown
Owner

Closes #385. Follow-up filed as #508.

A test run needed 74 individual confirmations in the Structure stage alone, while openkos.yaml had carried review: true all along and this verb never read it. Measuring first: cfg.review is honored in 16 sites in main.py and zero in curate.py.

The deeper cause is an asymmetry. curate --auto consents to model spend, never to a per-item write (design rule D3), and its escape hatch is the unattended_hint pointing at the standalone verb — where --auto does write. So suggest-relations --auto has always written 74 relations unattended while curate --auto wrote none.

What ships

curate --accept structure,metadata answers those stages' per-item prompts without asking. review: false does the same for every acceptable stage when no flag is passed.

Identity is excluded structurally — three independent guards

A merge absorbs one concept into another and deletes the absorbed file. One guard is not enough when the failure mode is a silently destroyed concept:

  1. auto_acceptable is a field on the Stage descriptor and Identity keeps the False default. A future writing stage cannot inherit accept-all merely by being added to _STAGES.
  2. --accept identity is refused with exit 2, and review: false only ever populates acceptable stages.
  3. Identity's walk calls _confirm directly rather than through _confirm_item, so the acceptance path cannot reach it at all.

This is load-bearing, not belt-and-braces. Mutating guard 1 alone does not make merges silent; mutating guards 1 and 2 together does, and the test catches it. There is also a fourth surface: the non-TTY write refusal is lifted by accepted_stages membership, so if Identity ever became acceptable it would gain unattended merge authority — concepts deleted by a config line and a pipe, with no prompt anywhere to decline at. That path has its own test, and mutating it produces an exit-1 crash rather than a silent merge.

Other decisions

  • --accept IS write consent, so an accepted stage passes the non-TTY refusal. curate --auto --accept structure writing on a pipe is parity with suggest-relations --auto, not new authority.
  • An explicit --accept narrows rather than widens review: false. A flag that could only ever add would leave an operator no way to re-review one stage without editing the config mid-session.
  • Refusals run before the workspace gate, so curate --accept strcture outside a workspace reports the typo as itself — the ordering list's TYPE and set-volatility's tier already use.

Confidence thresholds are out of scope, and the issue's plan was inverted

#385 proposed auto-accepting above 0.9. That is not implementable on the stages that hurt: EdgeSuggestion carries edge/suggested_type/rationale and TierSuggestion carries type_name/current_default/suggested_tier — neither has confidence. The only confidence in the project lives in adjudication.py, i.e. Identity, the destructive stage. Filed as #508, which has to add confidence to the suggesters first (a prompt change, so it needs a cap-harness A/B, not just a green suite).

Verification

  • Suite 4040 → 4048, all passing. ruff and mypy clean over the whole repo.
  • Mutation-verified, including the composite invariant above and the non-TTY path. One test passed on first write; rather than trust it, it was mutated until it discriminated, which is how the fourth surface was found in the first place.

Disclosure: no review receipt

Same lens defect as PRs #503, #506 and #507: the review agents are configured with only Read/Grep/Glob and cannot run the read-only Git commands the contract requires, so inspection returns incomplete. Shipping without a receipt is the maintainer's standing decision this session.

Closes #385.

A test run needed 74 individual confirmations in the Structure stage
alone, while `openkos.yaml` had carried `review: true` all along and this
verb never read it -- 16 sites in `main.py` already did.

`curate --accept structure,metadata` answers those stages' per-item write
prompts without asking, and `review: false` does the same for every
acceptable stage when no flag is passed.

Identity is excluded structurally, with three independent guards, because
the failure mode is a silently deleted concept:

- `auto_acceptable` is a field on the stage descriptor and Identity keeps
  the `False` default, so a future writing stage cannot inherit
  accept-all merely by being added to `_STAGES`;
- `--accept identity` is refused with exit 2, and `review: false` only
  ever populates the acceptable stages;
- Identity's walk calls `_confirm` directly rather than through
  `_confirm_item`, so the acceptance path cannot reach it at all.

Naming a stage IS per-item write consent, so an accepted stage also
passes the non-TTY write refusal: `curate --auto --accept structure`
writes on a pipe, which is parity with `suggest-relations --auto` rather
than new authority. Identity remains refused on that path.

An unknown stage name is refused the same way, and both refusals run
before the workspace gate so a typo reports as itself rather than as a
missing workspace -- the ordering `list`'s TYPE already uses.

An explicit `--accept` overrides `review` and names the exact set instead
of widening it, so an operator running with `review: false` can still
re-review one stage without editing the config mid-session.

Confidence-threshold auto-acceptance is deliberately out of scope and
filed as #508: `EdgeSuggestion` and `TierSuggestion` expose no confidence
at all, so a threshold is implementable today only on Identity, which may
never be accepted in bulk.

Spec, docs and CHANGELOG updated. Suite 4040 -> 4048.
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.

curate ignores the review mode and offers no batch accept

1 participant