Skip to content

Kernel: what happens to a Finding that does not gate - #96

Merged
don-petry merged 2 commits into
mainfrom
kernel/non-gating-findings
Oct 15, 2026
Merged

don-petry merged 2 commits into
mainfrom
kernel/non-gating-findings

Conversation

@don-petry

@don-petry don-petry commented Oct 15, 2026 •

Copy link
Copy Markdown
Contributor

Part of the epic "Epic: nine gaps in the Kernel, found in review". Closes #55.

Convergence read only Findings of severity blocking or major, so a minor or info Finding could be open, with no Disposition, when its item merged, against FR-33 and I-15. The Maintainer ruled on 2026-10-14: a Finding that does not gate is an annotation on its Lens's check run, exempt from FR-33 and I-15, and a security Finding gates at any severity.

The rule

A required model Lens's open thread Reading
security, any severity (blocking, major, minor, info) gates: addressing / findings_open; queued, dequeue / gate_open
Any other category, blocking or major gates, as before
Any other category, minor or info does not gate
Category or severity missing, null, or outside the schema thread_unreadable, needs_you; queued, dequeue
  • A Lens that is not required gates only when a required Lens adopts its Finding (FR-32), whatever the category. Its thread may carry nulls.
  • A deterministic Lens gates through its check's conclusion. Code scanning fails by default only on high or higher, so a lower security alert passes it: that is "Code scanning fails on a security alert of any severity" (Code scanning fails on a security alert of any severity #95), recorded in §9.9.
  • A thread's category and severity come from the required Lens's own Finding record in its Run's result.json, joined by surface.key, never from the comment text, which anyone with write access can edit. The join waits on adapters/.
  • Refusing a non-gating Finding posted on a thread waits on harness/ (acceptance criterion 3), recorded in decision 0012, design §3.7, §4.3 and §9.9.

Acceptance criteria

  1. category is required on threads in schemas/facts.schema.json, examples/facts.json, tests/support.py and sim/world.py, with counter-examples for a missing category and one nobody owns. tools/check_authority.py checks that a thread's categories, and the Kernel's CATEGORIES and SEVERITIES, are exactly a Finding's.
  2. test_a_minor_security_finding_gates, test_a_minor_security_finding_opened_while_queued_takes_it_out_of_the_queue, test_a_security_finding_from_a_lens_that_is_not_required_does_not_gate and test_a_required_lens_thread_that_cannot_be_read_defers; test_minor_finding_and_unrequired_lens_do_not_gate still passes. Mutants for reading security by severity, a non-required Lens gating, and each unreadable case: 146 of 146 killed.
  3. Waiting on harness/, as above.
  4. PRD FR-33; design §1.1, §3.3, §3.7, §4.2 item 2, §4.3, I-15 and §9.9; decision 0012; config/apps.json (the reader App reads records.artifacts under the actions: read it already holds).

Read by

A fresh-context review and a separate security pass (Claude), on the first commit; the second commit answers them. Both found that a required Lens's thread with a null category was read as not security, so a minor security Finding could merge; it now defers. AGY (Gemini) to follow; Codex and CodeRabbit are at their usage limits. make verify passes on a git archive export (343 tests), and python3 -m tools.mutants kills 146 of 146.

🤖 Generated with Claude Code

View guided diff Turn on auto-fix

don-petry and others added 2 commits October 15, 2026 15:39
The Maintainer's ruling on the story, option 1: a required Lens's Finding that does not gate, a
minor or info one of any category but security, is an annotation on its Lens's check run. It has no
Disposition and closes when its Lens stops reporting it, as a mechanical Finding does, so FR-33 and
I-15 apply to gating Findings only. A security Finding gates at any severity: severity is never how
a security defect gets merged.

Threads gain category in the facts schema, the example, the counter-examples, tests/support.py and
sim/world.py, in the authority table's terms, with null for a Lens that writes it only as prose. Two
counter-examples refuse a thread without its category and one nobody owns, and check_authority now
holds the thread's categories to the Finding's.

gating_threads stays the one definition of a gating thread, so gates(), the queue's gate_open and
moved_at all read the new rule. A minor or info security Finding sends the item to addressing with
findings_open, and takes a queued item out with gate_open. One from a Lens that is not required
gates only once a required Lens adopts it, whatever its category. Two mutants: one reads security
by severity, one lets an unrequired Lens's security Finding gate.

Refusing a Result that posts a Finding that does not gate on a thread is waiting on harness/,
recorded in decision 0012. PRD FR-33, design §1.1, §3.7, §4.2, §4.3, I-15 and §9.9, and decision
0012 say so.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
From the review and security passes on the Finding that does not gate.

A required model Lens's open thread whose category or severity is missing, null, or a word the
Finding schema does not name is unreadable, not "not security": it could be a security Finding,
which gates at any severity. The Kernel defers, reason thread_unreadable, with the thread's id as
evidence, and the item is the Maintainer's to see. It is read just after the reviews, as an
unreadable review is, and a queued item dequeues on it. It is read on a dependency update too, as
a model Lens's thread gates whatever the class. A thread from a Lens that is not required may
carry neither, and a person's thread gates whatever it says. The null-severity security case that
had gated now defers. CATEGORIES and SEVERITIES join kernel/terms.py, and check_authority holds
them to the Finding schema, and reports a facts schema whose threads carry no category rather than
raising. thread() in tests/support.py keeps a category of None as None. Seven mutants.

A correction to the last commit's message: moved_at does not read gating_threads. It counts a
thread by any writer or Lens's App (moves()), so a security Finding of any severity moved an item
before this story and still does.

The design's facts table and §3.7 say a required Lens's thread takes its category and severity from
that Lens's own Finding record in its Run's result.json, joined by surface.key, never from the
comment text, which anyone with write access can edit. The reader App, which reads facts.threads,
now lists records.artifacts under the actions: read it already holds; the Controller listed it.
Decision 0012 records the join as waiting on adapters/.

FR-33, design §4.2 item 2 and decision 0012 are narrowed to what the Kernel holds: a required model
Lens's thread gates at any severity when it is security; a required deterministic Lens gates
through its check's conclusion. Design §9.9 records that code scanning's default fails only on a
security alert of high or higher, so its threshold must be set to fail on any (issue #95). The
simulator's pr-review no longer opens a thread for a minor Finding that is not security, since the
Harness refuses one, and a human thread in tests/test_simulator.py gains its category.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
@don-petry
don-petry requested a review from a team as a code owner October 15, 2026 21:01
@chatgpt-codex-connector

Copy link
Copy Markdown

Codex Review Summary

This comment shows the latest Codex review activity on this pull request.

Review Status Commit Review trigger
📝 Code Review ⚠️ Failed 2026-10-15T21:01:40.210907Z 88e3530 PR opened
ℹ️ About Codex in GitHub

Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you

  • Open a pull request for review
  • Mark a draft as ready
  • Comment "@codex review" or "@codex security review".

Codex reacts with 👀 while any review is running, comments if it has suggestions, and reacts with 👍 once all reviews finish with no findings.

@chatgpt-codex-connector

Copy link
Copy Markdown

You have reached your Codex usage limits for code reviews. You can see your limits in the Codex usage dashboard.
To continue using code reviews, you can upgrade your account or add credits to your account and enable them for code reviews in your settings.

@coderabbitai

coderabbitai Bot commented Oct 15, 2026

Copy link
Copy Markdown

Warning

Review limit reached

You've used all free OSS reviews for now. Wait for the free limit to reset to keep reviewing this public repository.

Next included review available in 5 minutes.

Check out review usage here.

View limit details

Limit details: You’ve used the included review currently available.

Learn how review limits work.

Review configuration:

⚙️ Run configuration
  • Configuration used: Repository: combsmith/software-factory/.coderabbit.yaml
  • Review profile: CHILL
  • Plan: Advanced
  • Run ID: 64c7b4d7-6a83-4440-80fd-5fd147d18659
📥 Commits

Reviewing files that changed from the base of the PR and between d17651e and 88e3530.

📒 Files selected for processing: 30
  • config/apps.json
  • docs/architecture/software-factory-design.md
  • docs/decisions/0012-lenses-report-findings-and-the-kernel-decides-convergence.md
  • docs/prd/agentic-software-factory.md
  • examples/facts.json
  • examples/invalid/facts.a-category-nobody-owns.json
  • examples/invalid/facts.a-check-without-its-completion-time.json
  • examples/invalid/facts.a-conclusion-in-words.json
  • examples/invalid/facts.a-thread-without-its-category.json
  • examples/invalid/facts.a-time-with-an-impossible-day.json
  • examples/invalid/facts.a-time-with-an-impossible-month.json
  • examples/invalid/facts.carries-prose.json
  • examples/invalid/facts.dismissed-review-without-its-earlier-state.json
  • examples/invalid/facts.no-completeness-for-runs.json
  • examples/invalid/facts.no-completeness-for-timeline.json
  • examples/invalid/facts.no-completeness.json
  • examples/invalid/facts.no-count-of-acts.json
  • examples/invalid/facts.review-without-reviewer.json
  • examples/invalid/facts.time-in-another-format.json
  • kernel/decide.py
  • kernel/derive.py
  • kernel/terms.py
  • schemas/facts.schema.json
  • sim/world.py
  • tests/support.py
  • tests/test_decide.py
  • tests/test_simulator.py
  • tests/test_tools.py
  • tools/check_authority.py
  • tools/mutants.py
  • Autofix · Keep fixing CodeRabbit findings and required CI, and resolving merge conflicts

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.

@sonarqubecloud

Copy link
Copy Markdown

@don-petry
don-petry added this pull request to the merge queue Oct 15, 2026
Merged via the queue into main with commit d63c81a Oct 15, 2026
9 checks passed
@don-petry
don-petry deleted the kernel/non-gating-findings branch October 20, 2026 17:22
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.

Kernel: what happens to a Finding that does not gate

1 participant