Skip to content

CI check: a new BaseStore must be wired into the app lifespan (no orphan stores) - #2334

Merged
jaylfc merged 2 commits into
devfrom
exec/tsk-n3w5mh
Aug 10, 2026
Merged

CI check: a new BaseStore must be wired into the app lifespan (no orphan stores)#2334
jaylfc merged 2 commits into
devfrom
exec/tsk-n3w5mh

Conversation

@jaylfc

@jaylfc jaylfc commented Aug 9, 2026

Copy link
Copy Markdown
Owner

CARD TITLE (intent, not commit subject): CI check: a new BaseStore must be wired into the app lifespan (no orphan stores)

Autonomous build of board card tsk-n3w5mh.

  • scripts/check_store_wiring.py detects PRs that add a new BaseStore
    subclass without wiring it into tinyagentos/app.py
  • Uses name-level check (class name appears in app.py)
  • Only flags newly added classes; pre-existing orphans are skipped
  • Store-Unwired-Intentionally: , trailer waives and logs
  • .github/workflows/store-wiring-gate.yml runs the check on PRs
  • tests/test_check_store_wiring.py proves FAIL, PASS, existing orphan
    not flagged, trailer waiver, and transitive subclass detection

Files:
.github/workflows/store-wiring-gate.yml | 43 +++
changelog.d/tsk-n3w5mh-store-wiring-gate.md | 11 +
scripts/check_store_wiring.py | 273 ++++++++++++++++++
tests/test_check_store_wiring.py | 415 ++++++++++++++++++++++++++++
4 files changed, 742 insertions(+)

Summary by CodeRabbit

  • New Features

    • Added an automated pull-request check to identify newly introduced stores that are not connected to the application.
    • Added support for documented waiver trailers for intentional exceptions.
  • Documentation

    • Documented the store-wiring check and waiver process.
  • Tests

    • Added coverage for store detection, wiring validation, inheritance, and intentional waivers.

RED-proof at the merge ref (gate-PRs-prove-red rule)

Lead-verified, two independent bad cases, both through the exact workflow entry point:

Bad case 1 - the real defect this gate exists for. Merge ref = dev + this PR, then merge #2333 (adds StrikeStore without wiring):

$ python3 scripts/check_store_wiring.py --base origin/dev
STORE-WIRING FAIL: 1 new BaseStore subclass(es) are not wired into tinyagentos/app.py. Routes reach stores ONLY via request.app.state, so an unwired store is unreachable:
  - StrikeStore in tinyagentos/projects/strike_store.py
exit 1

Bad case 2 - synthetic unwired store (RedTestOrphanStore under tinyagentos/):

STORE-WIRING FAIL: 1 new BaseStore subclass(es) are not wired into tinyagentos/app.py...
  - RedTestOrphanStore in tinyagentos/redtest_store.py
exit 1

Green half: the merge ref alone (no new stores) exits 0 store-wiring-guard: clean. Waiver via PR_BODY env verified working.

- scripts/check_store_wiring.py detects PRs that add a new BaseStore
  subclass without wiring it into tinyagentos/app.py
- Uses name-level check (class name appears in app.py)
- Only flags newly added classes; pre-existing orphans are skipped
- Store-Unwired-Intentionally: <ClassName>, <why> trailer waives and logs
- .github/workflows/store-wiring-gate.yml runs the check on PRs
- tests/test_check_store_wiring.py proves FAIL, PASS, existing orphan
  not flagged, trailer waiver, and transitive subclass detection
@qodo-code-review

Copy link
Copy Markdown

ⓘ Qodo reviews are paused because the subscription is no longer active. Ask your workspace admin to reactivate the subscription to resume reviews. Manage billing

@coderabbitai

coderabbitai Bot commented Aug 9, 2026

Copy link
Copy Markdown

Review Change Stack

📝 Walkthrough

Walkthrough

Adds a pull-request gate that detects newly added BaseStore subclasses, checks name-level wiring in tinyagentos/app.py, supports intentional waiver trailers, and validates the behavior with synthetic Git repository tests.

Changes

Store wiring gate

Layer / File(s) Summary
Store wiring detection
scripts/check_store_wiring.py
Builds transitive class hierarchies, detects newly added BaseStore subclasses, parses Store-Unwired-Intentionally: trailers, and reports unwired classes.
Repository-based validation
tests/test_check_store_wiring.py
Tests direct and transitive subclass detection, Git diff handling, wiring validation, existing unwired stores, waivers, and violation details.
CLI, pull-request execution, and documentation
scripts/check_store_wiring.py, .github/workflows/store-wiring-gate.yml, changelog.d/tsk-n3w5mh-store-wiring-gate.md, .claude/skills/taos-development-skill/SKILL.md
Adds CLI handling and exit statuses. Runs the guard for pull requests targeting master or dev. Documents the gate and waiver behavior.

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

Sequence Diagram(s)

sequenceDiagram
  participant Pull_request
  participant Store_wiring_workflow
  participant check_store_wiring_py
  participant Git_repository
  participant tinyagentos_app_py
  Pull_request->>Store_wiring_workflow: Provide base reference and PR body
  Store_wiring_workflow->>check_store_wiring_py: Run store wiring validation
  check_store_wiring_py->>Git_repository: Read changed files and base revisions
  check_store_wiring_py->>tinyagentos_app_py: Check subclass name references
  tinyagentos_app_py-->>check_store_wiring_py: Return wiring references
  check_store_wiring_py-->>Store_wiring_workflow: Return status and diagnostics
  Store_wiring_workflow-->>Pull_request: Report gate result
Loading
🚥 Pre-merge checks | ✅ 5
✅ Passed checks (5 passed)
Check name Status Explanation
Docstring Coverage ✅ Passed No functions found in the changed files to evaluate docstring coverage. Skipping docstring coverage check.
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.
Description Check ✅ Passed Check skipped - CodeRabbit’s high-level summary is enabled.
Title check ✅ Passed The title clearly summarizes the new CI check that requires newly added BaseStore subclasses to be wired into the app lifespan.
✨ Finishing Touches
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Commit unit tests in branch exec/tsk-n3w5mh

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.

@gitar-bot

gitar-bot Bot commented Aug 9, 2026

Copy link
Copy Markdown

Gitar is working

Gitar

@coderabbitai coderabbitai Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

Actionable comments posted: 5

🤖 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 `@scripts/check_store_wiring.py`:
- Around line 196-202: Update the changed-file filtering loop in
check_store_wiring to handle Git rename and copy statuses (`R` and `C`) instead
of skipping them. Preserve each entry’s preimage path for these statuses, then
evaluate the destination path using the same Python-file and wiring validation
applied to modified files.
- Around line 114-117: Update the class hierarchy collection around the node
base scan to resolve ast.Attribute expressions and imported aliases to the
canonical BaseStore symbol, so declarations such as qualified
base_store.BaseStore are recorded and gated correctly. Preserve existing
ast.Name handling, and add coverage for qualified and aliased BaseStore imports.
- Around line 84-90: Update the class-handling logic in the store-wiring check
so an existing class is skipped only when its base-revision inheritance already
includes BaseStore; continue processing classes whose inheritance changed from
another base to BaseStore. Add a regression test covering this conversion from a
non-BaseStore subclass.
- Around line 170-174: Update the trailer parsing logic around TRAILER so a
waiver is added only when the trailer contains a comma-separated class and a
non-empty reason; reject entries missing the comma or with blank text after it,
while preserving valid waiver handling.

In `@tests/test_check_store_wiring.py`:
- Around line 411-415: Update the test around check_store_wiring to assert that
the returned waived collection is empty, using the existing waived variable
alongside the violation assertions. Keep the existing NewStore violation checks
unchanged.
🪄 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: Path: .coderabbit.yaml

Review profile: CHILL

Plan: Pro Plus

Run ID: e6a6bb45-7d78-44eb-8472-e6077b9baf3e

📥 Commits

Reviewing files that changed from the base of the PR and between 9d80b17 and 3c71a7e.

📒 Files selected for processing (4)
  • .github/workflows/store-wiring-gate.yml
  • changelog.d/tsk-n3w5mh-store-wiring-gate.md
  • scripts/check_store_wiring.py
  • tests/test_check_store_wiring.py

Comment on lines +84 to +90
base_content = _get_file_at_ref(file_path, base_ref, repo_root)
if base_content is not None:
try:
base_tree = ast.parse(base_content)
for node in ast.walk(base_tree):
if isinstance(node, ast.ClassDef) and node.name == class_name:
return False

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

🎯 Functional Correctness | 🟠 Major | ⚡ Quick win

Detect classes converted into BaseStore subclasses.

Line 89 returns False when the class name exists in the base revision. If a PR changes class Foo(Other) to class Foo(BaseStore), the guard skips Foo even though it introduces a new store subclass. Compare the base revision inheritance before skipping the class. Add a regression test for this conversion.

🤖 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 `@scripts/check_store_wiring.py` around lines 84 - 90, Update the
class-handling logic in the store-wiring check so an existing class is skipped
only when its base-revision inheritance already includes BaseStore; continue
processing classes whose inheritance changed from another base to BaseStore. Add
a regression test covering this conversion from a non-BaseStore subclass.

Comment on lines +114 to +117
for base in node.bases:
if isinstance(base, ast.Name):
bases.add(base.id)
classes[node.name] = bases

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

🎯 Functional Correctness | 🟠 Major | ⚡ Quick win

Resolve qualified BaseStore base expressions.

The hierarchy only records ast.Name bases. A valid declaration such as class Foo(base_store.BaseStore): produces no base entry and bypasses the gate. Resolve ast.Attribute bases and imported aliases to the canonical BaseStore symbol. Add coverage for qualified and aliased imports.

🤖 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 `@scripts/check_store_wiring.py` around lines 114 - 117, Update the class
hierarchy collection around the node base scan to resolve ast.Attribute
expressions and imported aliases to the canonical BaseStore symbol, so
declarations such as qualified base_store.BaseStore are recorded and gated
correctly. Preserve existing ast.Name handling, and add coverage for qualified
and aliased BaseStore imports.

Comment on lines +170 to +174
if line.startswith(TRAILER):
classes_str = line[len(TRAILER):].strip()
cls = classes_str.split(",", 1)[0].strip()
if cls:
waived.add(cls)

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

🎯 Functional Correctness | 🟡 Minor | ⚡ Quick win

Require a non-empty waiver reason.

Store-Unwired-Intentionally: Foo currently waives Foo without the required <why> value. Reject trailers with no comma or an empty reason so the waiver remains auditable.

Proposed fix
-            cls = classes_str.split(",", 1)[0].strip()
-            if cls:
-                waived.add(cls)
+            cls, separator, reason = classes_str.partition(",")
+            if cls.strip() and separator and reason.strip():
+                waived.add(cls.strip())
📝 Committable suggestion

‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.

Suggested change
if line.startswith(TRAILER):
classes_str = line[len(TRAILER):].strip()
cls = classes_str.split(",", 1)[0].strip()
if cls:
waived.add(cls)
if line.startswith(TRAILER):
classes_str = line[len(TRAILER):].strip()
cls, separator, reason = classes_str.partition(",")
if cls.strip() and separator and reason.strip():
waived.add(cls.strip())
🤖 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 `@scripts/check_store_wiring.py` around lines 170 - 174, Update the trailer
parsing logic around TRAILER so a waiver is added only when the trailer contains
a comma-separated class and a non-empty reason; reject entries missing the comma
or with blank text after it, while preserving valid waiver handling.

Comment on lines +196 to +202
for status, file_path in changed:
if not file_path.startswith("tinyagentos/") or not file_path.endswith(".py"):
continue
if status.startswith("D"):
continue
if not (status.startswith("A") or status.startswith("M")):
continue

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

🎯 Functional Correctness | 🟠 Major | 🏗️ Heavy lift

Handle renamed and copied Python files.

Git can report a renamed or copied file as R or C. This code skips both statuses. A PR can rename a store module and add an unwired subclass in the same change without validation. Preserve the preimage path for rename or copy entries and evaluate the destination file as a modified file.

🤖 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 `@scripts/check_store_wiring.py` around lines 196 - 202, Update the
changed-file filtering loop in check_store_wiring to handle Git rename and copy
statuses (`R` and `C`) instead of skipping them. Preserve each entry’s preimage
path for these statuses, then evaluate the destination path using the same
Python-file and wiring validation applied to modified files.

Comment on lines +411 to +415
violations, waived = csw.check_store_wiring(base_tip, repo)

assert len(violations) == 1
assert violations[0].class_name == "NewStore"
assert violations[0].file_path == "tinyagentos/metrics_store.py"

Copy link
Copy Markdown

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

Assert the no-waiver result.

waived is unused, and Ruff reports RUF059. Assert that it is empty. This also verifies that an unwired NewStore does not receive an implicit waiver.

Proposed fix
         assert len(violations) == 1
         assert violations[0].class_name == "NewStore"
         assert violations[0].file_path == "tinyagentos/metrics_store.py"
+        assert waived == set()
📝 Committable suggestion

‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.

Suggested change
violations, waived = csw.check_store_wiring(base_tip, repo)
assert len(violations) == 1
assert violations[0].class_name == "NewStore"
assert violations[0].file_path == "tinyagentos/metrics_store.py"
violations, waived = csw.check_store_wiring(base_tip, repo)
assert len(violations) == 1
assert violations[0].class_name == "NewStore"
assert violations[0].file_path == "tinyagentos/metrics_store.py"
assert waived == set()
🧰 Tools
🪛 Ruff (0.16.1)

[warning] 411-411: Unpacked variable waived is never used

Prefix it with an underscore or any other dummy variable pattern

(RUF059)

🤖 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 `@tests/test_check_store_wiring.py` around lines 411 - 415, Update the test
around check_store_wiring to assert that the returned waived collection is
empty, using the existing waived variable alongside the violation assertions.
Keep the existing NewStore violation checks unchanged.

Source: Linters/SAST tools


def _run_git(args: list[str], repo_root: Path) -> str:
result = subprocess.run(
["git", *args], cwd=repo_root, capture_output=True, text=True, check=True,

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

WARNING: _run_git raises unhandled CalledProcessError on git failures

_run_git uses check=True but callers don't catch CalledProcessError. If the git command fails (e.g., invalid base ref, network issue during fetch), the script crashes with a raw traceback instead of a user-friendly error, making CI failures hard to diagnose.


Reply with @kilocode-bot fix it to have Kilo Code address this issue.

for node in ast.walk(base_tree):
if isinstance(node, ast.ClassDef) and node.name == class_name:
return False
except SyntaxError:

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

WARNING: SyntaxError in base file silently produces false positives

_class_def_in_added_lines catches SyntaxError from ast.parse and falls through to the diff check. If the base file has a syntax error, an existing class can be incorrectly flagged as "new" because its definition appears in the diff. Return False instead of falling through.


Reply with @kilocode-bot fix it to have Kilo Code address this issue.

waived.add(class_name)
continue

if not re.search(rf"\b{re.escape(class_name)}\b", app_py_content):

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

WARNING: Name-level wiring check matches in comments and string literals

re.search(rf"\b{re.escape(class_name)}\b", app_py_content) matches the class name anywhere in app.py, including comments and docstrings. A new BaseStore subclass could pass the check without being wired if its name merely appears in a comment (e.g., # TODO: wire FooStore). Consider parsing app.py with ast and checking for actual attribute assignments.


Reply with @kilocode-bot fix it to have Kilo Code address this issue.

@kilo-code-bot

kilo-code-bot Bot commented Aug 9, 2026

Copy link
Copy Markdown

Code Review Summary

Status: No Issues Found | Recommendation: Merge

Files Reviewed (2 files)
  • .claude/skills/taos-development-skill/SKILL.md
  • .github/workflows/store-wiring-gate.yml

Fix these issues in Kilo Cloud

Previous Review Summary (commit 3c71a7e)

Current summary above is authoritative. Previous snapshots are kept for context only.

Previous review (commit 3c71a7e)

Status: 3 Issues Found | Recommendation: Address before merge

Overview

Severity Count
CRITICAL 0
WARNING 3
SUGGESTION 0
Issue Details (click to expand)

WARNING

File Line Issue
scripts/check_store_wiring.py 47 _run_git raises unhandled CalledProcessError on git failures
scripts/check_store_wiring.py 91 SyntaxError in base file silently produces false positives
scripts/check_store_wiring.py 229 Name-level wiring check matches in comments and string literals
Files Reviewed (4 files)
  • .github/workflows/store-wiring-gate.yml
  • changelog.d/tsk-n3w5mh-store-wiring-gate.md
  • scripts/check_store_wiring.py - 3 issues
  • tests/test_check_store_wiring.py

Fix these issues in Kilo Cloud


Reviewed by step-3.7-flash · Input: 57.5K · Output: 5K · Cached: 170.2K

@jaylfc

jaylfc commented Aug 9, 2026

Copy link
Copy Markdown
Owner Author

nemotron-super review

VERDICT: No blocking issues found.

Automated first-pass review by the nemotron-super lane. The lead still reviews before merge.

@coderabbitai coderabbitai Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

Actionable comments posted: 1

🤖 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 @.claude/skills/taos-development-skill/SKILL.md:
- Line 451: Update the waiver example fenced block in SKILL.md to specify the
text language tag, changing the opening fence to ```text while preserving its
Store-Unwired-Intentionally example content.
🪄 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: Path: .coderabbit.yaml

Review profile: CHILL

Plan: Pro Plus

Run ID: 833fb110-90b7-49a4-b4de-6bedf3cde33e

📥 Commits

Reviewing files that changed from the base of the PR and between 3c71a7e and 6a6a9ff.

📒 Files selected for processing (2)
  • .claude/skills/taos-development-skill/SKILL.md
  • .github/workflows/store-wiring-gate.yml
🚧 Files skipped from review as they are similar to previous changes (1)
  • .github/workflows/store-wiring-gate.yml


For a store genuinely constructed elsewhere (tests, CLI, workers), waive it with a PR-body
trailer, which is logged by the gate:
```

Copy link
Copy Markdown

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

Add a language tag to the waiver example.

The fenced block at Line 451 has no language. Add text to satisfy markdownlint rule MD040.

Proposed fix
-```
+```text
 Store-Unwired-Intentionally: <ClassName>, <why>
📝 Committable suggestion

‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.

Suggested change
```
🧰 Tools
🪛 markdownlint-cli2 (0.23.2)

[warning] 451-451: Fenced code blocks should have a language specified

(MD040, fenced-code-language)

🪛 SkillSpector (2.5.1)

[warning] 506: [RA2] Session Persistence: Skill establishes unauthorized persistence across sessions via cron jobs, startup scripts, or state files. Session persistence allows an attacker to maintain access beyond the current interaction.

Remediation: Remove any persistence mechanisms (cron jobs, startup scripts, state files). Skills should not maintain state across sessions without explicit user consent.

(Rogue Agent (RA2))

🤖 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 @.claude/skills/taos-development-skill/SKILL.md at line 451, Update the
waiver example fenced block in SKILL.md to specify the text language tag,
changing the opening fence to ```text while preserving its
Store-Unwired-Intentionally example content.

Source: Linters/SAST tools

@jaylfc
jaylfc merged commit 93616cc into dev Aug 10, 2026
22 checks passed
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