Skip to content

Deny-once step-0 ordering gate: opt-in priorArtGate component - #382

Merged
norvalbv merged 6 commits into
mainfrom
worktree-prior-art-gate
Aug 10, 2026
Merged

Deny-once step-0 ordering gate: opt-in priorArtGate component#382
norvalbv merged 6 commits into
mainfrom
worktree-prior-art-gate

Conversation

@norvalbv

@norvalbv norvalbv commented Aug 10, 2026

Copy link
Copy Markdown
Owner

Summary

Agents skip the prior-art step-0 subagent unless manually prompted — ordering has only ever lived as prose in skills/brainstorming/SKILL.md. This adds a mechanical, opt-in guarantee: devkit init --prior-art-gate.

  • PreToolUse (ExitPlanMode|Task|Agent): the first ExitPlanMode call or feature-critique dispatch in a session with no recorded prior-art run is denied once, with a reason quoting the brainstorming skill's skip predicate. Any retry that session passes — a session snooze marker, so trivial plans never deadlock.
  • PostToolUse (Task|Agent): records when a prior-art subagent completes.
  • Reads only tool_name + tool_input.subagent_type, fails open on every error, ships Claude-only (no cursorEvent — Cursor has no ExitPlanMode/Task), and stays off unless explicitly selected (opt-in even under --yes, same shape as the adhd component).

Two decision records were re-targeted first via guard-decisions add --target (never hand-edited):

  • devkit-gates-repo-not-harness — narrow carve-out for hooks that order devkit's own shipped workflow stages, not third-party argument shapes.
  • prior-art-before-plan — step-0 ordering gains mechanical enforcement; verdict substance stays advisory; the SubagentStop capture path stays deliberate dead code (run detection uses PostToolUse-on-Task instead).

guard-size forced extracting init's flag parsing (InitFlags/parseFlags/selectionFromFlags) out of cli/commands/init.mts into cli/lib/install/flags/init-flags.mts, alongside the existing review-profile.mts — behavior unchanged, old export names re-exported for existing test importers.

Test plan

  • bun run typecheck && bun run lint && bun run lint:structure clean
  • New unit tests: cli/__tests__/prior-art-gate.test.mts (12 cases — deny/snooze/retry/record/isolation/fail-open)
  • New component tests: cli/__tests__/prior-art-gate-component.test.mts (6 cases — install/remove cycle, Claude-only projection, ledger entries)
  • Full suite green (bun run test:run, 3754 passing; two isolated re-runs confirmed the only failures seen were CPU-load flakes on unrelated files, not caused by this change)
  • Live smoke: deny → silent retry → prior-art run recorded → feature-critique passes
  • bun run build; dist diff scoped to only the changed source (mode-only/pre-existing drift reverted)

🤖 Generated with Claude Code

Summary by CodeRabbit

  • New Features

    • Added an optional prior-art workflow gate, disabled by default.
    • Supports installation through initialization flags and setup wizards.
    • Prompts for prior-art review before plan completion or feature critique, with acknowledgment and retry handling.
    • Added status visibility through diagnostics and synchronized hook configuration.
    • Automatically disables the gate when Claude integration is not selected.
  • Documentation

    • Documented setup options, acknowledgment behavior, and workflow decisions.
  • Tests

    • Added coverage for gating, installation, acknowledgments, isolation, and optional component selection.

norvalbv and others added 2 commits August 9, 2026 22:02
… deny-once step-0 gate

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
…g gate

The first ExitPlanMode call or feature-critique dispatch in a session with no
recorded prior-art run is denied once with the skip predicate; the denial
writes a session snooze so every retry passes. A PostToolUse hook on Task|Agent
records prior-art runs. Reads only tool identity + subagent_type, fails open,
ships Claude-only (no cursorEvent), and stays off unless --prior-art-gate is
passed — carve-out and advisory-boundary re-targets recorded in
docs/decisions/{devkit-gates-repo-not-harness,prior-art-before-plan}.md.
Init flag parsing moved to cli/lib/install/flags/ (guard-size + fan-out caps).

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
@coderabbitai

coderabbitai Bot commented Aug 10, 2026

Copy link
Copy Markdown
Contributor

Review Change Stack

No actionable comments were generated in the recent review. 🎉

ℹ️ Recent review info
⚙️ Run configuration

Configuration used: defaults

Review profile: CHILL

Plan: Pro Plus

Run ID: e6768926-8914-48a2-aa18-f59e3e1ba4d9

📥 Commits

Reviewing files that changed from the base of the PR and between c5031bd and eec2200.

⛔ Files ignored due to path filters (3)
  • dist/agents-hooks/prior-art-gate.mjs is excluded by !**/dist/**
  • dist/cli/lib/install/flags/init-flags.mjs is excluded by !**/dist/**
  • dist/cli/lib/wizard.mjs is excluded by !**/dist/**
📒 Files selected for processing (5)
  • agents-hooks/prior-art-gate.mjs
  • cli/__tests__/prior-art-gate-component.test.mts
  • cli/__tests__/prior-art-gate.test.mts
  • cli/lib/install/flags/init-flags.mts
  • cli/lib/wizard.mts
🚧 Files skipped from review as they are similar to previous changes (4)
  • cli/lib/install/flags/init-flags.mts
  • cli/tests/prior-art-gate-component.test.mts
  • agents-hooks/prior-art-gate.mjs
  • cli/lib/wizard.mts

📝 Walkthrough

Walkthrough

Adds an opt-in prior-art gate for workflow ordering. The hook records completed prior-art dispatches, gates plan and feature-critique calls once per session, supports Prior-art: acknowledgments, and integrates with installation, wizard, synchronization, and doctor flows.

Changes

Prior-art gate

Layer / File(s) Summary
Gate runtime and behavior
agents-hooks/prior-art-gate.mjs, cli/__tests__/prior-art-gate.test.mts, docs/decisions/*
The hook records prior-art runs, gates relevant calls, accepts Prior-art: acknowledgments, renders Claude and Cursor responses, and fails open on malformed input or internal errors.
Hook registration and asset selection
cli/lib/install/hook-registration-ledger/*, cli/commands/sync/sync-hooks.mts, cli/lib/components.mts
The prior-art hook receives Claude PreToolUse and PostToolUse registrations and remains independently selectable from other hook components.
Component model and wizard selection
cli/lib/wizard.mts, cli/__tests__/prior-art-gate-component.test.mts
The wizard exposes the disabled-by-default priorArtGate option and persists its enabled, disabled, and deselected states.
Initialization and reconciliation wiring
cli/lib/install/flags/*, cli/commands/init.mts, cli/commands/doctor.mts, cli/lib/help/init-help.mts, cli/lib/ship/review/setup-profile.mts, cli/__tests__/upgrade-optional-component-offer.test.mts, eslint/baselines/size-lines.json
Initialization flag parsing is relocated to dedicated modules. The prior-art selection is detected, recorded, forwarded, synchronized, documented, and covered by updated tests and baselines.

Estimated code review effort: 4 (Complex) | ~45 minutes

Sequence Diagram(s)

sequenceDiagram
  participant TaskOrAgent
  participant prior_art_gate
  participant MarkerFiles
  participant ExitPlanModeOrFeatureCritique
  TaskOrAgent->>prior_art_gate: Complete prior-art dispatch
  prior_art_gate->>MarkerFiles: Record session and repository marker
  ExitPlanModeOrFeatureCritique->>prior_art_gate: Submit gated plan or critique
  prior_art_gate->>MarkerFiles: Check run or snooze state
  prior_art_gate-->>ExitPlanModeOrFeatureCritique: Allow or deny once
Loading

Possibly related PRs

🚥 Pre-merge checks | ✅ 4 | ❌ 1

❌ Failed checks (1 warning)

Check name Status Explanation Resolution
Docstring Coverage ⚠️ Warning Docstring coverage is 71.43% which is insufficient. The required threshold is 80.00%. Write docstrings for the functions missing them to satisfy the coverage threshold.
✅ Passed checks (4 passed)
Check name Status Explanation
Description Check ✅ Passed Check skipped - CodeRabbit’s high-level summary is enabled.
Title check ✅ Passed The title clearly and concisely describes the opt-in priorArtGate component and its deny-once ordering gate.
Linked Issues check ✅ Passed Check skipped because no linked issues were found for this pull request.
Out of Scope Changes check ✅ Passed Check skipped because no linked issues were found for this pull request.
✨ Finishing Touches 💡 1
📝 Generate docstrings 💡
  • Create stacked PR
  • Commit on current branch
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Commit unit tests in branch worktree-prior-art-gate

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.

norvalbv and others added 3 commits August 10, 2026 09:45
The hook's own deny reason already tells the agent what to do when it fires;
restating enforcement mechanics in the skill duplicates a source of truth
that lives in agents-hooks/prior-art-gate.mjs and risks drift, for a
sentence that changes nothing about the step-0 decision predicate.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Deny-once taxed the compliant path: a plan carrying the skill-mandated
Prior-art: line (verdict or skip note) was denied identically to one that
never considered step-0. Both axes re-targeted: the hook may recognize
devkit's own acknowledgment token in the gated call's plan/prompt; all
foreign argument-shape validation stays rejected.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Deny-once taxed the compliant path: a trivial plan carrying the
skill-mandated skip note (Prior-art: skipped — reason) was denied
identically to a session that never considered step-0. The hook now
recognizes devkit's own acknowledgment token in ExitPlanMode's plan or
the feature-critique prompt: token present passes silently and marks the
session acknowledged; token absent denies once exactly as before, with a
deny reason that names the line to add. Judgment of WHETHER to run
prior-art stays in the model per the skill's written predicate — the
hook only verifies the judgment was recorded. Both governing decision
axes re-targeted in the previous commit.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>

@coderabbitai coderabbitai Bot left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 3

🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

Inline comments:
In `@agents-hooks/prior-art-gate.mjs`:
- Around line 51-54: Update the marker-path construction near repoKey so a
non-empty sessionId is first hashed and only that digest is interpolated into
base, while preserving the "unknown" fallback for empty or absent IDs. Add a
regression test covering a traversal-shaped session ID and assert the resulting
ran/snoozed paths remain within markers.dir.

In `@cli/lib/install/flags/init-flags.mts`:
- Around line 103-104: Require a Claude target whenever priorArtGate is enabled
so the gate cannot be recorded without a runnable registration: update the
selection logic around sel.agentTargets in cli/lib/install/flags/init-flags.mts
lines 103-104 to reject --prior-art-gate with --no-claude or automatically
include claude, and update the wizard target-selection flow in
cli/lib/wizard.mts lines 278-293 to restrict choices to Claude-containing sets
or clearly deselect the gate. Add coverage for both the CLI combination and
equivalent wizard selection.

In `@docs/decisions/devkit-gates-repo-not-harness.md`:
- Around line 28-29: Regenerate the 2026-08-09 decision entries through
guard-decisions, supplying label-free consequence and tradeoff text so generated
records do not contain duplicated “Positive:” labels or negative content under
the positive bullet. Apply this to
docs/decisions/devkit-gates-repo-not-harness.md lines 28-29 and
docs/decisions/prior-art-before-plan.md lines 31-32; do not edit generated
markdown directly, and preserve append-only decision files.
🪄 Autofix

Fix all unresolved CodeRabbit comments on this PR:

  • Push a commit to this branch (recommended)
  • Create a new PR with the fixes

ℹ️ Review info
⚙️ Run configuration

Configuration used: defaults

Review profile: CHILL

Plan: Pro Plus

Run ID: 64a1ee33-7632-454a-9ac4-2b002c69e8b8

📥 Commits

Reviewing files that changed from the base of the PR and between 7ed8ed7 and c5031bd.

⛔ Files ignored due to path filters (12)
  • dist/agents-hooks/prior-art-gate.mjs is excluded by !**/dist/**
  • dist/cli/commands/doctor.mjs is excluded by !**/dist/**
  • dist/cli/commands/init.mjs is excluded by !**/dist/**
  • dist/cli/commands/sync/sync-hooks.mjs is excluded by !**/dist/**
  • dist/cli/lib/components.mjs is excluded by !**/dist/**
  • dist/cli/lib/help/init-help.mjs is excluded by !**/dist/**
  • dist/cli/lib/install/flags/init-flags.mjs is excluded by !**/dist/**
  • dist/cli/lib/install/flags/review-profile.mjs is excluded by !**/dist/**
  • dist/cli/lib/install/hook-registration-ledger/registrations.mjs is excluded by !**/dist/**
  • dist/cli/lib/install/hook-registration-ledger/selection.mjs is excluded by !**/dist/**
  • dist/cli/lib/ship/review/setup-profile.mjs is excluded by !**/dist/**
  • dist/cli/lib/wizard.mjs is excluded by !**/dist/**
📒 Files selected for processing (20)
  • agents-hooks/prior-art-gate.mjs
  • cli/__tests__/prior-art-gate-component.test.mts
  • cli/__tests__/prior-art-gate.test.mts
  • cli/__tests__/upgrade-optional-component-offer.test.mts
  • cli/commands/doctor.mts
  • cli/commands/init.mts
  • cli/commands/sync/sync-hooks.mts
  • cli/lib/components.mts
  • cli/lib/help/init-help.mts
  • cli/lib/install/flags/init-flags.mts
  • cli/lib/install/flags/review-profile.mts
  • cli/lib/install/hook-registration-ledger/codec.test.mts
  • cli/lib/install/hook-registration-ledger/registrations.mts
  • cli/lib/install/hook-registration-ledger/selection.mts
  • cli/lib/ship/review/setup-profile.mts
  • cli/lib/wizard.mts
  • docs/decisions/INDEX.md
  • docs/decisions/devkit-gates-repo-not-harness.md
  • docs/decisions/prior-art-before-plan.md
  • eslint/baselines/size-lines.json

Comment thread agents-hooks/prior-art-gate.mjs
Comment thread cli/lib/install/flags/init-flags.mts
Comment on lines +28 to +29
- Positive: Positive: the step-0 ordering devkit ships finally has one mechanical enforcement point; a schema drift upstream degrades to the gate never firing (fail-open), never a false block. Negative: this is the first devkit hook whose subject is a harness tool call rather than the consumer repository; the boundary now requires the reads-only-tool-identity + deny-once + fail-open + opt-in fence to stay principled.
- Negative: Accepted one bounded exception to the gates-repo-not-harness line in exchange for closing a recurring, non-self-recovering workflow failure; rejected staying prose-only (measurably unfollowed) and rejected hard fail-closed denial (would block legitimate skips and inherit the foreign-schema fragility the original ruling feared).

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

📐 Maintainability & Code Quality | 🟡 Minor | ⚡ Quick win

Regenerate the decision records without duplicated consequence labels.

Both records contain Positive: Positive: and place negative content in the positive bullet. Regenerate the uncommitted entries through guard-decisions; do not edit the generated markdown directly.

  • docs/decisions/devkit-gates-repo-not-harness.md#L28-L29: provide label-free consequence and tradeoff text when regenerating the 2026-08-09 entry.
  • docs/decisions/prior-art-before-plan.md#L31-L32: provide label-free consequence and tradeoff text when regenerating the 2026-08-09 entry.

Based on learnings, decision files are generated and append-only.

📍 Affects 2 files
  • docs/decisions/devkit-gates-repo-not-harness.md#L28-L29 (this comment)
  • docs/decisions/prior-art-before-plan.md#L31-L32
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@docs/decisions/devkit-gates-repo-not-harness.md` around lines 28 - 29,
Regenerate the 2026-08-09 decision entries through guard-decisions, supplying
label-free consequence and tradeoff text so generated records do not contain
duplicated “Positive:” labels or negative content under the positive bullet.
Apply this to docs/decisions/devkit-gates-repo-not-harness.md lines 28-29 and
docs/decisions/prior-art-before-plan.md lines 31-32; do not edit generated
markdown directly, and preserve append-only decision files.

Source: Learnings

…aude surface

Review findings (PR #382):
- A session_id arrives from harness stdin and was interpolated raw into
  the marker path, so a path-shaped value could escape the namespace
  directory. Non-empty ids are now hashed (12-hex, same shape as the
  repo key); regression test pins traversal-shaped ids below the dir.
- --prior-art-gate with --no-claude (or a non-Claude wizard surface)
  recorded an enabled component whose Claude-only registrations never
  install. Both selection paths now deselect it with a visible notice.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
@norvalbv
norvalbv merged commit 85d383c into main Aug 10, 2026
2 checks passed
@norvalbv norvalbv mentioned this pull request Aug 10, 2026
norvalbv added a commit that referenced this pull request Aug 10, 2026
Bump 0.50.0 -> 0.51.0 and rebuild dist from a clean origin/main worktree
(f817b75).

Minor, not patch: two feature PRs landed since 0.50.0 — sentry-additive
restages that keep earned verdicts plus a sentry judge cache (#370), and the
opt-in priorArtGate deny-once step-0 ordering component (#382). The rest of
the range is fixes (#371-#383).

The rebuild also picks up two dist modules that git had never seen. dist/ is
gitignored on working branches by design, so gate-engine/review/cascade/
consumer-assets.mjs and reviewer.mjs — the compiled output of the #376
checklist-asset refactor — existed only on disk. They are force-added here,
which is exactly the path `devkit release` takes for ignored dist output.
Without them the shipped runtime.mjs would import a module absent from the
tag.

Release smoke checks ran: built bin reports 0.51.0, dist/package.json agrees,
and dist/cli/lib/ship/ship-branch.sh still wires ship_read_stdin_body (the
sc-1419 stdin-hang fix survived the build).

Gates bypassed at the maintainer's request (--no-verify); the range was
already reviewed on its constituent PRs.

Co-authored-by: Claude Opus 5 <noreply@anthropic.com>
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