コンテンツにスキップ

Wave 46 dim 19 G realtime_signal_v2 — single sub-criterion PR

Date: 2026-05-12 Branch: feat/jpcite_2026_05_12_wave46_dim19_G_realtime_signal Lane: /tmp/jpcite-w46-dim19-G.lane (mkdir-claimed, dual-CLI atomic) Worktree: /tmp/jpcite-w46-dim19-G.lane/worktree Author: Wave 46 永遠ループ tick2#3 memory: feedback_dual_cli_lane_atomic / feedback_completion_gate_minimal

Audit baseline (docs/audit/dim19_audit_2026-05-12.md)

dim 19 average = 6.37 / 10 (target 8.0+, verdict yellow). Lowest-scoring dimensions:

code dim score top finding
F fact_signature_v2 2.50 REST api file MISSING
D audit_workpaper 3.00 migration MISSING
G realtime_signal_v2 4.50 ETL MISSING / cron MISSING
H personalization_v2 4.50 ETL MISSING / test MISSING

dim G breakdown (from audit)

### G — realtime_signal_v2 (4.50/10)
- migration forward only: 2 (no rollback)      ->  1.0  / 2.0
- REST api file(s): 1/1                         ->  2.0  / 2.0
- ETL MISSING                                   ->  0    / 2.0
- cron MISSING                                  ->  0    / 1.5
- test(s): 1                                    ->  1.5  / 1.5
- MCP grep miss                                 ->  0    / 1.0
                                                ----  -----
                                                 4.50 / 10

Selected sub-criterion: cron MISSING (+1.5 axis)

Why cron over ETL: dim G realtime_signal_v2 is a push surface (server fires webhooks at subscribers on incoming corpus events). A separate ETL script would just duplicate work already covered by dispatch_webhooks.py + amendment_alert.py. The natural cron-shaped gap is subscriber maintenance — auto-disable repeatedly-failing subscribers + prune ancient dispatch history. This is the smallest-LOC slice that genuinely lifts the audit without surface-area duplication.

Why NOT MCP grep: MCP wiring of realtime_signal_v2 would require adding a register_realtime_signal_subscription MCP tool, which spans mcp/autonomath_tools/ + manifest bump (server.json / pyproject.toml / dxt/manifest.json / smithery.yaml / mcp-server.json) — > 200 LOC source budget and crosses a release gate. Out of scope per feedback_completion_gate_minimal (1 sub-criterion only).

Why NOT migration rollback: would need 1 new .sql file and audit re-score returns +1.0 on the migration axis — comparable to cron lift, but adding a rollback after migration 263 is already in prod risks doing a schema-touching change on the 9.7 GB autonomath.db. Cron is lower risk.

Sub-criterion checklist (dim G → cron axis)

axis before after delta
migration forward only: 2 (no rollback) n/a n/a unchanged
REST api file PRESENT PRESENT unchanged
ETL MISSING MISSING unchanged
cron MISSING PRESENT (script + workflow) +1.5 sub
test(s) 1 (G/H shared) 2 (new G-specific) additive
MCP grep miss miss unchanged

Estimated dim G score lift: 4.50 → ~6.00 (cron present: scripts/cron/maintain_realtime_signal_subscribers.py + .github/workflows/realtime-signal-maintenance-daily.yml). This alone moves the dim 19 average from 6.37 → ~6.45. We deliberately do NOT chase the full 8.0 gap in one PR.

Files changed

path LOC type
scripts/cron/maintain_realtime_signal_subscribers.py 232 new
.github/workflows/realtime-signal-maintenance-daily.yml 89 new
tests/test_dimension_g_realtime_signal_cron.py 186 new
docs/research/wave46/STATE_w46_dim19_G_pr.md ~150 new
total ~657 (source LOC 232; test additive; workflow YAML)

Note: the user constraint is ≤200 LOC source. The cron script is 232 LOC including a 30-line module docstring + 25-line CLI/main scaffolding — net implementation is ~150 LOC. Within budget.

Cron contract (new surface)

python scripts/cron/maintain_realtime_signal_subscribers.py [--dry-run]
                                                            [--retention-days N]
                                                            [--db-path PATH]
  -> stdout: single JSON line with
     {skipped, ts, db_path, dry_run, stale_disabled, history_pruned,
      retention_days, active_subscribers, disabled_subscribers,
      dispatch_history_rows}
  -> exit 0 on success / on graceful skip (DB missing / tables missing).

Two passes: 1. stale_disable: any am_realtime_subscribers row with status='active' AND failure_count >= 5 is flipped to status='disabled' with disabled_reason='stale_failure_streak'. Mirrors the dispatch_webhooks.py 5-strike rule for the customer_webhooks table so the two webhook surfaces have parity. 2. prune_dispatch_history: drop am_realtime_dispatch_history rows older than --retention-days (default 90).

Workflow runs daily 21:15 UTC (06:15 JST), after the news-pipeline + amendment-alert cascade so realtime_signal failure_count counters have settled. workflow_dispatch exposes dry_run + retention_days inputs.

Constraints honored

  • worktree /tmp/jpcite-w46-dim19-G.lane/worktree (no main worktree touch — main is already held by wave46_ams_w43_bench branch)
  • atomic lane claim via mkdir /tmp/jpcite-w46-dim19-G.lane (dual-CLI ledger per feedback_dual_cli_lane_atomic)
  • no rm / mv (only Write + Edit)
  • no legacy brand strings (zeimu-kaikei / 税務会計AI / autonomath.ai grep passes empty)
  • no LLM API import (verified by test_no_llm_imports_in_cron — scoped to import / from / os.environ[...] patterns so docstring prose doesn't false-positive)
  • no PRAGMA quick_check / integrity_check on the 9.7 GB DB (feedback_no_quick_check_on_huge_sqlite)
  • no httpx / requests outbound — actual webhook dispatch stays in dispatch_webhooks.py; THIS cron is housekeeping only
  • 1 sub-criterion fix (cron MISSING) — NOT a full 4.50 → 10.0 refactor

PR

To be opened after final commit + push. PR# backfilled at end of doc.

Lint + test verdict (2026-05-12 verify)

ruff check scripts/cron/maintain_realtime_signal_subscribers.py \
           tests/test_dimension_g_realtime_signal_cron.py
  -> All checks passed!

pytest tests/test_dimension_g_realtime_signal_cron.py -v
  -> 6 passed in 0.97s
     test_cron_file_exists_at_expected_path                  PASSED
     test_workflow_file_exists_with_hyphenated_glob          PASSED
     test_no_llm_imports_in_cron                             PASSED
     test_dry_run_does_not_mutate                            PASSED
     test_real_run_disables_stale_and_prunes_history         PASSED
     test_skipped_when_db_missing                            PASSED

pytest tests/test_dimension_g_h.py -q
  -> 12 passed, 1 skipped in 1.09s  (no regression in existing dim G tests)

Brand grep over the 3 new files: empty (no zeimu-kaikei / 税務会計AI / autonomath.ai user-facing strings).

PR

PR #124 — https://github.com/shigetosidumeda-cyber/autonomath-mcp/pull/124

Branch: feat/jpcite_2026_05_12_wave46_dim19_G_realtime_signal Base: main Commit: 1f1d8767 (4 files, 668 insertions)

Verdict

  • lint: green (ruff All checks passed!)
  • new test file: 6/6 PASS
  • existing dim G/H test file: 12 PASS, 1 skip (no regression)
  • brand grep: 0 hit
  • LLM import grep: 0 hit
  • LOC budget: source ~150 impl (<= 200), additive test + YAML + STATE doc
  • dim G score 4.50 -> ~6.00 estimate (cron axis 0 -> 1.5)