feat(scoring): Phase 4.5e PR 6 — Form-4 10b5-1 negation guard (residual footgun #1)#303
Merged
Conversation
…al footgun #1) Closes the residual of footgun #1 from `compute/scoring/form4_signals.py` module docstring + the PR 4-eq Mode B verdict (2026-05-23, pre-approved "harden detect_10b5_1_plan with a negation guard against FP matches on phrases like '10b5-1 plan terminated'"). PR 6 implements the engineering of the approved mitigation. **Architecture** — post-detector wrapper: - `compute/scoring/form4_insider.py` gains `_NEGATION_PATTERNS` (11 tokens) + `_NEGATION_REGEX` (compiled bidirectional regex; case-insensitive; accepts both `10b5-1` and `10b-5-1` spellings; ±5 word-token window) + `_has_negation()` helper + thread-safe module-level counter - `_detect_10b5_1_on_transaction` modified: detector returns True → check `_has_negation(resolved_text)` → on match return False and bump the counter; detector returns False or None → pass through unchanged. Guard never fabricates a positive signal (only downgrades True → False). **Schema** `0.10.10 → 0.10.11-phase4.6` (PATCH — additive Metadata field). Triple touched: Pydantic + TypeScript + snapshot regenerated; verified clean via `python -m compute.output.schema_check`. **Rule 18 observability**: new `Metadata.form4_negation_guard_downgrade_count: int | None`. Counter is module-level + thread-safe (`threading.Lock` around an int) for the `EDGAR_MAX_WORKERS=8` parallel Form-4 fetch loop. `compute/main.py` resets before the `ThreadPoolExecutor` block and reads on the success path. `None` semantics mirrors `form4_wall_clock_seconds`: None when `FORM4_FETCH_SKIP=1` OR outer try/except fired. **Methodology** — pre-approved (no fresh consultation needed). Expected delta firing-rate per Cohen 2008 §III + Jagolinzer 2009 §3.2: `insider_sell_cluster` +5% to +10% relative on a universe-baseline cron (absolute << 1%; most 10b5-1 disclosures are affirmative). Bias direction reversed: was conservative (over-excluded legit opportunistic trades); now closer to ground truth (terminated + former plans no longer fire). **Tests** — 33 new tests in `tests/test_scoring/test_form4_negation_guard.py`: 13 pattern coverage (parametrized) + 5 negative paths + 2 ±5-token window boundary + 2 spelling variants + 5 `_detect_10b5_1_on_transaction` integration with mocked footnotes_dict + 2 thread-safety (incl. 100 concurrent bumps / 8 workers) + 2 Hypothesis properties (idempotence + monotonicity) + 2 manifest pins. Suite 1366 → 1399; zero regressions; ruff clean. `tests/test_config.py` schema pin bumped with PR 6 rationale. **Defense layer unchanged** at 33 declared boolean flags (PR hardens an existing input filter; no new flag). Cluster + C-suite weights UNCHANGED (5.0 / 3.0; promotion to 7.0 still gated on Q3 2026-08-19 audit per PR 4-eq verdict). **Closes**: residual of footgun #1 (Form-4 10b5-1 contamination) from `compute/scoring/form4_signals.py` module docstring. 🤖 Generated with [Claude Code](https://claude.com/claude-code) Co-Authored-By: Claude <noreply@anthropic.com>
|
The latest updates on your projects. Learn more about Vercel for GitHub.
|
quantrank-reviewer (opus) flagged 3 non-blocking WARNs on the initial PR 6 commit. 2 addressed inline; 1 deferred to follow-up. - WARN-2 FIXED: `_NEGATION_REGEX` BEFORE branch gains an inline NOTE block explaining `no` is intentionally BEFORE-only (post- mention "10b5-1 plan, no shares sold" reads as affirmative disclosure + non-negation use of `no` → FP risk too high). AFTER branch carries a cross-reference comment so the asymmetry is self-documenting at the regex. - WARN-3 FIXED: new `test_M3_negation_patterns_each_appear_in_compiled_regex` drift-detector — every token in `_NEGATION_PATTERNS` must appear somewhere in `_NEGATION_REGEX.pattern` source string. Catches drift in both directions (add to frozenset without updating regex; remove from regex without updating frozenset). Carve-outs handle the `cancelled` ↔ `canceled` collapse to `cancell?ed` and the multi-word `not in effect` `\s+` split. Tests 33 → 34; full suite 1399 → 1400. - WARN-1 DEFERRED in `PHASE_STATUS_INFLIGHT.md` PR #303 entry: `_NEGATION_REGEX` anchor matches only 2 of upstream `detect_10b5_1_plan`'s 6 substrings. Bias direction remains safe (over-includes legit trades in cohort, never under-excludes). Fix path noted; gated on cron Run #72+ empirical data showing whether the gap is material. 🤖 Generated with [Claude Code](https://claude.com/claude-code) Co-Authored-By: Claude <noreply@anthropic.com>
dackclup
pushed a commit
that referenced
this pull request
May 29, 2026
Full .md consistency sweep (docs-reviewer audit, all facts re-verified against compute/config.py + filesystem before applying). 13 MUST-FIX + 6 SHOULD-FIX text reconciles — no contradictions remain across the canonical docs: - Schema 0.10.10 -> 0.10.11-phase4.6 current-state in CLAUDE.md / PHASE_STATUS.md / CONTEXT.md / WORKFLOW.md / SKILL.md (PR #303 merged; was still showing the pre-bump value + a stale "in flight" framing). - Agent count 18 -> 19 (+ 4-opus/14-sonnet -> 15-sonnet, 6 -> 7 coordination flows) in PHASE_STATUS.md subagent row + CONTEXT.md roster/mapping rows (PR #304 added expert-user-explorer; PR #307 added Flow 7). - Skill count 42/38 -> 45 in .claude/agents/README.md + .claude/skills/README.md. - Cleared stale "in flight (this PR)" blocks for PRs now merged (CLAUDE.md + AGENTS.md + PHASE_STATUS.md); moved #303-#310 into the Recently-merged lists; flipped 5 PHASE_STATUS_INFLIGHT.md headers (in flight -> merged + SHA). - METHODOLOGY.md annotate line: fixed the math (was "7+5+23"=35; the proposed "7+5+26"=38 was also wrong) to the authoritative "33 declared = 7 vetoes + 26 annotates; 5 numerical guards separate". LIVE current-state facts only; dated/PR-attributed HISTORICAL narrative left intact (append-only record). ruff check . clean (whole-repo, per the lesson). Docs-only; no code/schema change. https://claude.ai/code/session_0144kHrCYNaamMPH57b7xdM7
dackclup
added a commit
that referenced
this pull request
May 29, 2026
) Full .md cross-doc consistency sweep after the 6-PR session (#303-#310): schema 0.10.10→0.10.11 current-state, agent roster 18→19 (4-opus/15-sonnet, 7 flows), skill count →45, cleared stale "in flight" blocks + flipped 5 INFLIGHT headers to merged, fixed METHODOLOGY annotate math (7 vetoes + 26 annotates = 33 declared). All facts re-verified against config.py + filesystem; LIVE current-state only, historical narrative untouched. Docs-only. https://claude.ai/code/session_0144kHrCYNaamMPH57b7xdM7
This was referenced May 31, 2026
dackclup
pushed a commit
that referenced
this pull request
Jun 2, 2026
…In-flight entries - CLAUDE.md §Phase status: new "Recently merged" block (PR #331–#373, 2026-05-31→2026-06-02, 43 PRs covering $impeccable full-frontend pass + financial-engineer subagent + PR-B country/exchange chips + Commit A MUST-FIX sweep); old #303–#330 block demoted to new "Earlier" section; "In flight" entries (PR-B + financial-engineer) replaced with "(none)" - PHASE_STATUS.md: date 2026-05-31 → 2026-06-02; same recently-merged / earlier restructure with compact one-liners for all 43 PRs - AGENTS.md §Phase + version state: "In flight — PR-B" bullet replaced with "all PRs through #373 merged" pointer to CLAUDE.md - PHASE_STATUS_INFLIGHT.md: Commit B entry appended No compute / schema / scoring / valuation / frontend code change. https://claude.ai/code/session_01ELWfJoJp5kMje2j4zoUCQh
dackclup
added a commit
that referenced
this pull request
Jun 2, 2026
…ntries (#380) Drains 43 PRs (#331–#373) into CLAUDE.md + PHASE_STATUS.md Recently-merged blocks. Old #303–#330 block demoted to Earlier. In-flight entries for PR-B and financial-engineer replaced with (none). AGENTS.md In-flight bullet updated. PHASE_STATUS_INFLIGHT.md Commit B entry appended. No compute/schema/frontend change.
Merged
4 tasks
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Summary
compute/scoring/form4_signals.pymodule docstring + PR 4-eq Mode B verdict (2026-05-23, pre-approved "hardendetect_10b5_1_planwith a negation guard against FP matches on phrases like '10b5-1 plan terminated'"). PR 6 = pure engineering of the approved mitigation.edgar.ownership.core.detect_10b5_1_plan: when detector returnsTrue, re-scan the resolved footnote text for negation phrases (terminated/cancelled/no/previously/former/ etc.) within ±5 word tokens of the 10b5-1 mention. On match, downgradeTrue → Falseand bump a thread-safe module-level counter.0.10.10 → 0.10.11-phase4.6PATCH bump for the newMetadata.form4_negation_guard_downgrade_count: int | Nonefield (Rule 18 observability). Triple lockstep — Pydantic ↔ TypeScript ↔ snapshot all touched + regenerated;schema_checkverified clean.What changed
compute/scoring/form4_insider.py_NEGATION_PATTERNSfrozenset + compiled bidirectional_NEGATION_REGEX(±5 word-token window, case-insensitive, accepts both10b5-1and10b-5-1spellings) +_has_negation()helper + thread-safereset/get/_bump_negation_downgrade_count()lifecycle + modified_detect_10b5_1_on_transactionto apply guard; module docstring §"FP caveat" updatedcompute/scoring/form4_signals.pycompute/main.pyThreadPoolExecutorblock; read on success path; alias toform4_negation_guard_downgrade_countlocal; pass toMetadata(...)constructorcompute/output/schemas.pyMetadata.form4_negation_guard_downgrade_count: int | None = Nonewith full provenance docstringfrontend/lib/types.tsfrontend/lib/schema-snapshot.json--update-snapshotcompute/config.pySCHEMA_VERSION = "0.10.11-phase4.6"tests/test_config.pytests/test_scoring/test_form4_negation_guard.pytest-engineer(sonnet)CLAUDE.md+AGENTS.md+PHASE_STATUS_INFLIGHT.md+SKILL.md+CONTEXT.mdRule 18 observability (new field)
Metadata.form4_negation_guard_downgrade_count— universe-wide count ofTrue → Falsedowngrades applied by the post-detector negation guard during Form-4 cache build. Gates the Q3 2026-08-19 cohort-acceptance check (issue #130) for theINSIDER_SELL_CLUSTER_WEIGHT5.0 → 7.0 promotion alongsideform4_rule10b5_one_excluded_count.Nonesemantics mirrorsform4_wall_clock_seconds:NonewhenFORM4_FETCH_SKIP=1(loop didn't run) OR outertry/exceptfired before end markerint(zero is valid) on the happy path — warm-cache cron reports 0 (no detector ran this cycle); cold-cache cron populates the real cohort numberMethodology (skipped per pre-approval)
PR 4-eq Mode B verdict (2026-05-23) documented in
form4_signals.pyfootgun §1 already pre-approved this hardening. PR 6 = pure engineering implementation. The Q3 audit reads the new metric from the surfaced metadata field — no fresh methodology consultation needed.Expected delta firing-rate (per Cohen 2008 §III + Jagolinzer 2009 §3.2):
insider_sell_cluster+5% to +10% relative on a universe-baseline cron<< 1%(most 10b5-1 disclosures are affirmative, not negated)Test plan
ruff check .— cleanpython -m compute.output.schema_check— in sync (snapshot regenerated)python -m pytest tests/ -m "not network"— 1366 → 1399 (+33) · zero regressions · 103spython -m pytest tests/test_scoring/test_form4_negation_guard.py -v— 33/33 pass · 1.91squantrank-reviewer(opus) +schema-sentinel(sonnet) +phase-coordinatorMode B (sonnet) parallel spawnform4_negation_guard_downgrade_count(cold-cache run; warm-cache will report 0)Footgun caveats preserved
Hard constraints honored
manipulation_indexweights UNCHANGED🤖 Generated with Claude Code
Generated by Claude Code