feat(scoring): Phase 4.5e PR 4-eq — Form-4 10b5-1 contamination filter#224
Merged
Conversation
Production + docs commit. Tests follow in a separate commit (test-engineer sub-agent in progress on tests/test_scoring/test_form4_*.py). Closes footgun #1 documented in compute/scoring/form4_signals.py module docstring — Jagolinzer 2009 §3.2 expected FP rate 40-60% on insider_sell_cluster from 10b5-1 contamination. _is_opportunistic_sell now requires NOT `is_rule_10b5_one is True` in addition to the transaction_code ∈ {S, D} gate so 10b5-1 scheduled trades are excluded from BOTH cluster + C-suite cohort counts. None and False both pass (option (a) per methodology-scientist Mode B 2026-05-23 — matches CMP 2012 + Jagolinzer 2009 empirical regime used to calibrate the existing thresholds). Access-path caveat: edgartools 5.31.5 does NOT parse the SEC structured <rule10b5_1> XML element added by SEC Release 33-11138 (effective 2023-04-01). Verified by edgar-debugger 2026-05-23 via exhaustive grep of edgar.ownership. Resolution path: Ownership.footnotes.get(id) → text → edgar.ownership.core.detect_10b5_1_plan regex match. New manifest _FOOTNOTES_REQUIRED_ATTRS = ("get",); footnotes added to existing _NON_DERIVATIVE_TX_REQUIRED_ATTRS + _OWNERSHIP_REQUIRED_ATTRS manifests. FP risk: terminated-plan disclosures match True; bias is conservative (over-excludes from opportunistic cohort, never under-excludes); Q3 2026-08-19 audit gates negation guard. Methodology verdict highlights (Mode B 2026-05-23): - Q1 filter semantic: LITERATURE-ANCHORED (Cohen 2008 §III routine partition + Jagolinzer 2009 §3.1 — 10b5-1 ⊊ routine) - Q2 None-handling: option (a) — None → not-10b5-1 - Q3 expected Δ: cluster -30% to -45% / C-suite -45% to -65% - Q4 C-suite inherits filter: YES with stronger lit support (Jagolinzer 2009 §5.2 NEO subsample 80% predictability drop) - Q5 weights HOLD at 5.0 / 3.0; promotion 5.0 → 7.0 (Aboody et al. 2010 §3.2 vesting-residual mid-point) is a separate follow-up after ≥ 1 cron's firing-rate data Rule 18 observability shipped in same PR: Metadata.form4_rule10b5_one_excluded_count: int | None counts the universe-wide total of transactions excluded by the filter within the 30d cluster window. Gates the Q3 2026-08-19 cohort-acceptance check (issue #130). Schema bump 0.10.1-phase4.5e → 0.10.2-phase4.5e (PATCH, additive). Defense layer emitted-flag count UNCHANGED at 32 (filter is signal- quality, not new flag). schema_check clean. https://claude.ai/code/session_01SSg1tZypxdgthAYTnQyd1h
|
The latest updates on your projects. Learn more about Vercel for GitHub.
|
…te parser + drift detector Companion to the production commit (baffb73 / PR #224). Closes the CI red on `Python (lint + test)` by (a) bumping the test_config.py schema-version pin 0.10.1-phase4.5e → 0.10.2-phase4.5e and (b) adding behavioral coverage for the new filter / count helper / footnote-resolution surface. Test deltas: - tests/test_scoring/test_form4_signals.py: 29 → 40 (+11) - test_opportunistic_sell_excludes_explicit_10b5_1_true - test_opportunistic_sell_includes_explicit_10b5_1_false - test_opportunistic_sell_includes_10b5_1_none_pre_mandate_compat - test_opportunistic_sell_legacy_row_without_10b5_field_passes - test_cluster_with_majority_10b5_1_drops_below_threshold - test_cluster_with_minority_10b5_1_still_fires - test_c_suite_inherits_10b5_1_filter - test_strict_superset_invariant_holds_under_10b5_1_filter - test_count_10b5_1_filtered_counts_only_opportunistic_codes - test_count_10b5_1_filtered_respects_window - test_filter_monotonicity_property (Hypothesis @given) - tests/test_scoring/test_form4_insider.py: 17 → 24 (+7) - test_G1_form4_transaction_parses_is_rule_10b5_one_true_from_footnote_text - test_G2_form4_transaction_parses_is_rule_10b5_one_false_when_footnote_has_no_10b5_text - test_G3_form4_transaction_is_rule_10b5_one_none_when_no_footnote_ids - test_G4_form4_transaction_is_rule_10b5_one_none_when_footnotes_dict_missing - test_G5_form4_transaction_from_dict_handles_legacy_row_without_10b5_field - test_D3_footnotes_required_attrs_manifest_is_non_empty_and_tupled - test_D4_edgar_footnotes_api_surface_locked - tests/test_config.py: schema-version pin bump 0.10.1 → 0.10.2 Strict-superset invariant verification: when the 10b5-1 filter drops all insiders below the cluster threshold, c_suite_fires is also False (c_suite ⊆ cluster). Holds because detect_c_suite_unusual_sell calls _is_opportunistic_sell (which now gates on NOT is_rule_10b5_one is True) before checking _is_c_suite — so 10b5-1 filtered rows never reach the C-suite title regex. Local full suite: 1162 passed / 7 skipped / 22 deselected (network). https://claude.ai/code/session_01SSg1tZypxdgthAYTnQyd1h
Merged
6 tasks
Contributor
Pre-merge production simulation
Diff vs main
Main baseline: Top-10 movers (sorted by |Δcomposite_score|)
|
dackclup
pushed a commit
that referenced
this pull request
May 23, 2026
…ature-searcher (15 → 18)
Closes three session-observed gaps where main-agent inline work was
draining the "Weekly · all models" pool instead of the underutilized
"Weekly · Sonnet only" pool on Max plans.
(a) `.claude/agents/ci-triage-engineer.md` (Tier 4 Operations, sonnet)
— Reactive to GitHub Actions check failures via the
`<github-webhook-activity>` PR-activity event. Knows the CI matrix
(Python lint+test · Frontend build · simulate · Vercel preview) +
10-class failure taxonomy (schema-pin-drift / ruff-I001 / F401 /
F841 / dep-missing-ci-only / real-bug / simulate-45min-cap /
flaky-transient / vercel-build-skew / schema-drift-CI). Proposes
one-line fix the user authorizes. Refuses to auto-flip test
assertions or classify as flaky without re-run evidence. Read +
Bash + Grep + Glob; no MCP tool access (asks main agent to invoke
GitHub MCP).
(b) `.claude/agents/vercel-preview-auditor.md` (Tier 2 Lifecycle, sonnet)
— Wraps Vercel MCP server chain: `list_deployments` →
`get_deployment_build_logs` → `get_runtime_logs` →
`web_fetch_vercel_url` 3-route UA probe. Codifies the CLAUDE.md
§Commands "When Vercel MCP is loaded, list_deployments →
get_runtime_logs is the cheap pre-Playwright pass" — which today
depends on main-agent memory. Fires before Mark-Ready on any UI-
touching PR. Refuses to invoke `deploy_to_vercel` or promote
preview to production. Knows the QuantRank Vercel project name
(quantrank), team scope (dackclups-projects), and preview URL
pattern.
(c) `.claude/agents/literature-searcher.md` (Tier 3 Specialized, sonnet)
— WebSearch + WebFetch wrapper for academic papers + SEC rule
releases + EDGAR filings. Carries CLAUDE.md's 17-paper canonical
anchor list in-prompt (Altman / Sloan / Beneish / Dechow / Mayew
/ BD / HLM / DT / Damodaran / Roychowdhury / Cohen / CMP / JMZ /
Jagolinzer / Bushman-Smith / Aboody / Huber) and refuses to re-
fetch those. For new papers: WebSearch → preferred
author/SSRN/NBER free PDF → WebFetch → locate the section →
return citation-ready excerpt + suggested docstring format.
Offloads retrieval from `methodology-scientist` (opus) — judgment
stays on opus, fetch stays on sonnet. Refuses to make a
methodology verdict itself (that's methodology-scientist's slot
exclusively); refuses copyright-violating mirrors (sci-hub /
libgen) — preprint OR institutional-access workflow only.
Tier counts updated:
- Tier 1 Core: 5 (unchanged)
- Tier 2 Lifecycle: 4 → 5 (+vercel-preview-auditor)
- Tier 3 Specialized: 4 → 5 (+literature-searcher)
- Tier 4 Operations: 2 → 3 (+ci-triage-engineer)
- Total: 15 → 18
4-opus / 14-sonnet split preserved (was 4/11). All 3 new agents are
sonnet to drain the underutilized Sonnet-only pool per PR #219 +
PR #223 token-economy rebalance.
Doc lockstep:
- `.claude/agents/README.md` tier tables (T2 / T3 / T4 add a row each)
+ roster header 15 → 18
- `CLAUDE.md` §Layout `.claude/agents/` row 15 → 18
- `CLAUDE.md` §Auto-routing policy:
- Delegation patterns table +3 rows (CI fail / Vercel preview /
literature search)
- Cue table +3 rows (CI webhook / pre-Mark-Ready UI / methodology
cite outside anchor list)
- Spawn discipline split count 4-vs-11 → 4-vs-14
- "Pattern not in the table" walks 18 agents now (was 15)
- `AGENTS.md` §Project structure agents row 15 → 18; new §Phase +
version state entry documenting cross-tool routing posture (still
Claude-Code-only)
Doc-only PR. No compute / schema / scoring / valuation / frontend
code change. CI Python lint+test should pass on this branch with
zero regression (no Python code touched).
Stacked alongside PR #224 (Form-4 10b5-1 filter, on
`claude/magical-curie-saWfR`); both branched from same main SHA
`79bb5ae`. Land order does not matter — no scope overlap.
https://claude.ai/code/session_01SSg1tZypxdgthAYTnQyd1h
dackclup
added a commit
that referenced
this pull request
May 23, 2026
…ature-searcher (15 → 18) (#225) Closes three session-observed gaps where main-agent inline work was draining the "Weekly · all models" pool instead of the underutilized "Weekly · Sonnet only" pool on Max plans. (a) `.claude/agents/ci-triage-engineer.md` (Tier 4 Operations, sonnet) — Reactive to GitHub Actions check failures via the `<github-webhook-activity>` PR-activity event. Knows the CI matrix (Python lint+test · Frontend build · simulate · Vercel preview) + 10-class failure taxonomy (schema-pin-drift / ruff-I001 / F401 / F841 / dep-missing-ci-only / real-bug / simulate-45min-cap / flaky-transient / vercel-build-skew / schema-drift-CI). Proposes one-line fix the user authorizes. Refuses to auto-flip test assertions or classify as flaky without re-run evidence. Read + Bash + Grep + Glob; no MCP tool access (asks main agent to invoke GitHub MCP). (b) `.claude/agents/vercel-preview-auditor.md` (Tier 2 Lifecycle, sonnet) — Wraps Vercel MCP server chain: `list_deployments` → `get_deployment_build_logs` → `get_runtime_logs` → `web_fetch_vercel_url` 3-route UA probe. Codifies the CLAUDE.md §Commands "When Vercel MCP is loaded, list_deployments → get_runtime_logs is the cheap pre-Playwright pass" — which today depends on main-agent memory. Fires before Mark-Ready on any UI- touching PR. Refuses to invoke `deploy_to_vercel` or promote preview to production. Knows the QuantRank Vercel project name (quantrank), team scope (dackclups-projects), and preview URL pattern. (c) `.claude/agents/literature-searcher.md` (Tier 3 Specialized, sonnet) — WebSearch + WebFetch wrapper for academic papers + SEC rule releases + EDGAR filings. Carries CLAUDE.md's 17-paper canonical anchor list in-prompt (Altman / Sloan / Beneish / Dechow / Mayew / BD / HLM / DT / Damodaran / Roychowdhury / Cohen / CMP / JMZ / Jagolinzer / Bushman-Smith / Aboody / Huber) and refuses to re- fetch those. For new papers: WebSearch → preferred author/SSRN/NBER free PDF → WebFetch → locate the section → return citation-ready excerpt + suggested docstring format. Offloads retrieval from `methodology-scientist` (opus) — judgment stays on opus, fetch stays on sonnet. Refuses to make a methodology verdict itself (that's methodology-scientist's slot exclusively); refuses copyright-violating mirrors (sci-hub / libgen) — preprint OR institutional-access workflow only. Tier counts updated: - Tier 1 Core: 5 (unchanged) - Tier 2 Lifecycle: 4 → 5 (+vercel-preview-auditor) - Tier 3 Specialized: 4 → 5 (+literature-searcher) - Tier 4 Operations: 2 → 3 (+ci-triage-engineer) - Total: 15 → 18 4-opus / 14-sonnet split preserved (was 4/11). All 3 new agents are sonnet to drain the underutilized Sonnet-only pool per PR #219 + PR #223 token-economy rebalance. Doc lockstep: - `.claude/agents/README.md` tier tables (T2 / T3 / T4 add a row each) + roster header 15 → 18 - `CLAUDE.md` §Layout `.claude/agents/` row 15 → 18 - `CLAUDE.md` §Auto-routing policy: - Delegation patterns table +3 rows (CI fail / Vercel preview / literature search) - Cue table +3 rows (CI webhook / pre-Mark-Ready UI / methodology cite outside anchor list) - Spawn discipline split count 4-vs-11 → 4-vs-14 - "Pattern not in the table" walks 18 agents now (was 15) - `AGENTS.md` §Project structure agents row 15 → 18; new §Phase + version state entry documenting cross-tool routing posture (still Claude-Code-only) Doc-only PR. No compute / schema / scoring / valuation / frontend code change. CI Python lint+test should pass on this branch with zero regression (no Python code touched). Stacked alongside PR #224 (Form-4 10b5-1 filter, on `claude/magical-curie-saWfR`); both branched from same main SHA `79bb5ae`. Land order does not matter — no scope overlap. https://claude.ai/code/session_01SSg1tZypxdgthAYTnQyd1h Co-authored-by: Claude <noreply@anthropic.com>
6 tasks
dackclup
added a commit
that referenced
this pull request
May 23, 2026
…iewer WARNs land (#227) PR #224 quantrank-reviewer WARN-tier punch-list (3 items). Two land here as test-discipline polish; one deferred for @network verification. (a) tests/test_scoring/test_form4_signals.py — two PR-#222 Hypothesis property tests drop @settings(deadline=None) per CLAUDE.md §Gotchas "Don't use @settings(deadline=None) — a slow example is itself a signal": - test_cluster_monotonic_under_added_compensation_txns - test_cluster_fires_only_within_lookback Both verified sub-millisecond under default 200ms Hypothesis deadline (40-test suite passes 0.84s offline). HealthCheck.too_slow + HealthCheck.filter_too_much suppression retained — orthogonal to the deadline rule, separate concern. (b) test_strict_superset_invariant_holds_under_10b5_1_filter — docstring + inline contrapositive comment rewritten to remove the confusing mixed "c_suite ⊆ cluster strict-superset" notation (set symbol + boolean direction collided). Replaced with the unambiguous implication form "c_suite firing implies cluster firing (PR #222 strict-superset, when the $1M floor is met)" + the ¬cluster ⟹ ¬c_suite contrapositive framing. Inline comment line "c_suite requires a subset of the conditions cluster requires" (geometrically incorrect — c_suite has no $1M floor, so its fire-set is NOT a strict subset of cluster's fire-set in general) replaced with "Contrapositive check: c_suite firing implies cluster firing (PR #222 strict-superset)". (c) DEFERRED — _FOOTNOTES_REQUIRED_ATTRS manifest extension ("get",) → ("get", "__contains__"). Sandbox doesn't have edgartools installed; can't verify Footnotes.__contains__ exists on the live class. Adding the attr blindly risks a silent break under pytest --run-network on a future CI cron run. Schedule for a follow-up PR that can run @network tests first. Tests: 1168 → 1168 (3 in-place edits; no test added / removed). ruff clean. No compute / schema / scoring / valuation / frontend / Python production-code change. CLAUDE.md + AGENTS.md lockstep satisfied via §Phase status in-flight notes. https://claude.ai/code/session_01JwntEE4PNAXSMkZxRA9BB4 Co-authored-by: Claude <noreply@anthropic.com>
This was referenced May 24, 2026
dackclup
pushed a commit
that referenced
this pull request
May 24, 2026
…+ cache + path filter The docstring fix above triggered simulate (path filter matched compute/scoring/**) which cancelled at 45m02s on the timeout cap. ci-triage-engineer deep-dive (session 5, 2026-05-24) identified the recurring pattern across multiple PRs: the QR_SKIP_TIER2 kill-switch fully wired in compute/scoring/tier2.py:158 was NEVER set in .github/workflows/pre-merge-prod-sim.yml. Past mitigations: - PR #165 (1y non-reliance lookback): addressed a specific 5-year EDGAR backfill spike on one PR but left the universe-wide Tier-2 loop intact - PR-form4-2 (FORM4_FETCH_SKIP=1): saved form4 budget but left the Tier-2 (502 tickers × 10-K text fetch + 8-K fetch) running unconditionally (20-35m cold-cache cost) Recurrence tally on last 5 simulate runs: PR #165 19m01s ✅ warm PR #204 19m37s ✅ warm PR #222 16m56s ✅ warm PR #224 17m08s ✅ warm PR #230 45m15s ❌ CANCELLED (cold) Pattern is structural — when GitHub evicts the warm cache after a 7-day gap without a simulate-triggering PR, the next compute/scoring PR hits full cold. The 4-part permanent fix: (a) QR_SKIP_TIER2: "1" added to pre-merge-prod-sim.yml env block PRIMARY fix — eliminates the 20-35m cold-cache Tier-2 cost. Tradeoff: the non_reliance veto (enabled since PR 4g) is suppressed in simulate's diff output. Acceptable because simulate is informational-only (per workflow comment line 24); non_reliance veto correctness is covered by offline pytest. (b) compute/cache/edgar_form4 added to BOTH workflows' cache paths (compute-rankings.yml save+restore, pre-merge-prod-sim.yml restore only). Future-proofs for Phase 4.5e PR 5 when form4 weight promotion enables FORM4_FETCH_SKIP=0 on simulate. (c) Path filter widened in pre-merge-prod-sim.yml from compute/scoring/** + compute/features/** only to also include: - compute/ingest/** (fundamentals fetcher regressions) - compute/valuation/** (RIM / DCF / ensemble regressions) - compute/output/schemas.py (Pydantic schema bumps) - compute/main.py (orchestrator changes) - pyproject.toml (dep bumps affecting compute) (d) compute/scoring/tier2.py:154-155 docstring corrected The old comment said "_EIGHT_K_DEFENSES_ENABLED=False" but PR 4g (2026-05-17) flipped it to True. The non_reliance veto IS the active veto path now; updated comment explains the veto suppression tradeoff in simulate context. Expected outcomes: - Docstring-only PR in compute/scoring/ → simulate completes in ~12-15m warm or ~17-20m partial-cold (well under 45m cap) - Real scoring PR → same budget; composite-score diff unchanged - Cache eviction (7-day gap) → worst case fundamentals cold ~10-20m + no Tier-2 + no form4 = under cap - Weekly cron UNAFFECTED — QR_SKIP_TIER2 not set there; full run continues to populate the warm cache Companion benefit: this PR's re-pushed simulate is the LIVE VALIDATION of the fix — first sub-45m simulate on this branch proves the fix works. Files touched: - .github/workflows/pre-merge-prod-sim.yml (env + cache + paths) - .github/workflows/compute-rankings.yml (cache path only) - compute/scoring/tier2.py (stale comment) - CLAUDE.md + AGENTS.md (§Phase status note) YAML parse-verified; ruff clean; no compute / schema / scoring / valuation / Python behavior change. CLAUDE.md + AGENTS.md lockstep satisfied via the §Phase status notes. https://claude.ai/code/session_01JwntEE4PNAXSMkZxRA9BB4
dackclup
pushed a commit
that referenced
this pull request
May 24, 2026
…per edgar-debugger live-XML verify The literature-searcher proof-of-life on 2026-05-23 (session 4) flagged a precision gap: the form4 module docstrings referenced the colloquial <rule10b5_1> XML tag name (a label, not the actual SEC EDGAR Ownership XML element). edgar-debugger re-audit on 2026-05-24 (session 5) fetched 3 live AAPL Form 4 XMLs from SEC EDGAR and confirmed the actual element is <aff10b5One> at ownershipDocument/aff10b5One — a DOCUMENT-LEVEL boolean (one per filing, covering ALL transactions in that Form 4), NOT a per-transaction attribute. Updated 7 references to use the canonical name: 5 code spots: - compute/scoring/form4_insider.py:20 (module docstring header) - compute/scoring/form4_insider.py:82 (§Footnote resolution) - compute/scoring/form4_insider.py:587 (inline _form4_to_transactions comment) - compute/scoring/form4_signals.py:129 (module docstring) - compute/output/schemas.py:200 (extreme_estimate_majority_count comment context) 2 doc spots: - CLAUDE.md §Phase status PR #224 entry "Access-path caveat" block (line 1352-1359) - AGENTS.md §Phase + version state PR #224 entry "Access-path caveat for cross-tool agents" block (line 947-951) Added §Footnote resolution architectural-gap note in compute/scoring/form4_insider.py: a filer who checks <aff10b5One>true at the document level but does NOT include the per-transaction footnote text (valid — the checkbox IS the formal affirmative defense, footnotes are supplemental) will slip past the current footnote-text fallback path and enter the opportunistic cohort incorrectly. Deferred to a follow-up PR that direct-parses the raw Form 4 XML for ownershipDocument/aff10b5One (edgartools doesn't expose it, so the implementation walks the filing text once per Ownership object). Tracked as the architectural follow-up after PR 4-eq. edgartools 5.31.5 verified as PyPI latest by edgar-debugger 2026-05-24 — no newer release adds a parse path for <aff10b5One>. detect_10b5_1_plan regex set (6 patterns) confirmed complete vs real-world footnote text — pattern "10b5-1" alone covers every common variant including Rule 10b5-1(c) subsection cites. No additions needed. Docstring-only PR — no compute / scoring / valuation / behavior change. schema_check clean (comment-only edit on schemas.py), ruff clean, tests unchanged at 1168+. CLAUDE.md + AGENTS.md lockstep satisfied via §Phase status in-flight notes. Companion stale-header reword: marked PR #229 "Security WARN cleanup" → "merged via PR #229" in CLAUDE.md + AGENTS.md. https://claude.ai/code/session_01JwntEE4PNAXSMkZxRA9BB4
dackclup
pushed a commit
that referenced
this pull request
May 24, 2026
…+ cache + path filter The docstring fix above triggered simulate (path filter matched compute/scoring/**) which cancelled at 45m02s on the timeout cap. ci-triage-engineer deep-dive (session 5, 2026-05-24) identified the recurring pattern across multiple PRs: the QR_SKIP_TIER2 kill-switch fully wired in compute/scoring/tier2.py:158 was NEVER set in .github/workflows/pre-merge-prod-sim.yml. Past mitigations: - PR #165 (1y non-reliance lookback): addressed a specific 5-year EDGAR backfill spike on one PR but left the universe-wide Tier-2 loop intact - PR-form4-2 (FORM4_FETCH_SKIP=1): saved form4 budget but left the Tier-2 (502 tickers × 10-K text fetch + 8-K fetch) running unconditionally (20-35m cold-cache cost) Recurrence tally on last 5 simulate runs: PR #165 19m01s ✅ warm PR #204 19m37s ✅ warm PR #222 16m56s ✅ warm PR #224 17m08s ✅ warm PR #230 45m15s ❌ CANCELLED (cold) Pattern is structural — when GitHub evicts the warm cache after a 7-day gap without a simulate-triggering PR, the next compute/scoring PR hits full cold. The 4-part permanent fix: (a) QR_SKIP_TIER2: "1" added to pre-merge-prod-sim.yml env block PRIMARY fix — eliminates the 20-35m cold-cache Tier-2 cost. Tradeoff: the non_reliance veto (enabled since PR 4g) is suppressed in simulate's diff output. Acceptable because simulate is informational-only (per workflow comment line 24); non_reliance veto correctness is covered by offline pytest. (b) compute/cache/edgar_form4 added to BOTH workflows' cache paths (compute-rankings.yml save+restore, pre-merge-prod-sim.yml restore only). Future-proofs for Phase 4.5e PR 5 when form4 weight promotion enables FORM4_FETCH_SKIP=0 on simulate. (c) Path filter widened in pre-merge-prod-sim.yml from compute/scoring/** + compute/features/** only to also include: - compute/ingest/** (fundamentals fetcher regressions) - compute/valuation/** (RIM / DCF / ensemble regressions) - compute/output/schemas.py (Pydantic schema bumps) - compute/main.py (orchestrator changes) - pyproject.toml (dep bumps affecting compute) (d) compute/scoring/tier2.py:154-155 docstring corrected The old comment said "_EIGHT_K_DEFENSES_ENABLED=False" but PR 4g (2026-05-17) flipped it to True. The non_reliance veto IS the active veto path now; updated comment explains the veto suppression tradeoff in simulate context. Expected outcomes: - Docstring-only PR in compute/scoring/ → simulate completes in ~12-15m warm or ~17-20m partial-cold (well under 45m cap) - Real scoring PR → same budget; composite-score diff unchanged - Cache eviction (7-day gap) → worst case fundamentals cold ~10-20m + no Tier-2 + no form4 = under cap - Weekly cron UNAFFECTED — QR_SKIP_TIER2 not set there; full run continues to populate the warm cache Companion benefit: this PR's re-pushed simulate is the LIVE VALIDATION of the fix — first sub-45m simulate on this branch proves the fix works. Files touched: - .github/workflows/pre-merge-prod-sim.yml (env + cache + paths) - .github/workflows/compute-rankings.yml (cache path only) - compute/scoring/tier2.py (stale comment) - CLAUDE.md + AGENTS.md (§Phase status note) YAML parse-verified; ruff clean; no compute / schema / scoring / valuation / Python behavior change. CLAUDE.md + AGENTS.md lockstep satisfied via the §Phase status notes. https://claude.ai/code/session_01JwntEE4PNAXSMkZxRA9BB4
dackclup
pushed a commit
that referenced
this pull request
May 24, 2026
…per edgar-debugger live-XML verify The literature-searcher proof-of-life on 2026-05-23 (session 4) flagged a precision gap: the form4 module docstrings referenced the colloquial <rule10b5_1> XML tag name (a label, not the actual SEC EDGAR Ownership XML element). edgar-debugger re-audit on 2026-05-24 (session 5) fetched 3 live AAPL Form 4 XMLs from SEC EDGAR and confirmed the actual element is <aff10b5One> at ownershipDocument/aff10b5One — a DOCUMENT-LEVEL boolean (one per filing, covering ALL transactions in that Form 4), NOT a per-transaction attribute. Updated 7 references to use the canonical name: 5 code spots: - compute/scoring/form4_insider.py:20 (module docstring header) - compute/scoring/form4_insider.py:82 (§Footnote resolution) - compute/scoring/form4_insider.py:587 (inline _form4_to_transactions comment) - compute/scoring/form4_signals.py:129 (module docstring) - compute/output/schemas.py:200 (extreme_estimate_majority_count comment context) 2 doc spots: - CLAUDE.md §Phase status PR #224 entry "Access-path caveat" block (line 1352-1359) - AGENTS.md §Phase + version state PR #224 entry "Access-path caveat for cross-tool agents" block (line 947-951) Added §Footnote resolution architectural-gap note in compute/scoring/form4_insider.py: a filer who checks <aff10b5One>true at the document level but does NOT include the per-transaction footnote text (valid — the checkbox IS the formal affirmative defense, footnotes are supplemental) will slip past the current footnote-text fallback path and enter the opportunistic cohort incorrectly. Deferred to a follow-up PR that direct-parses the raw Form 4 XML for ownershipDocument/aff10b5One (edgartools doesn't expose it, so the implementation walks the filing text once per Ownership object). Tracked as the architectural follow-up after PR 4-eq. edgartools 5.31.5 verified as PyPI latest by edgar-debugger 2026-05-24 — no newer release adds a parse path for <aff10b5One>. detect_10b5_1_plan regex set (6 patterns) confirmed complete vs real-world footnote text — pattern "10b5-1" alone covers every common variant including Rule 10b5-1(c) subsection cites. No additions needed. Docstring-only PR — no compute / scoring / valuation / behavior change. schema_check clean (comment-only edit on schemas.py), ruff clean, tests unchanged at 1168+. CLAUDE.md + AGENTS.md lockstep satisfied via §Phase status in-flight notes. Companion stale-header reword: marked PR #229 "Security WARN cleanup" → "merged via PR #229" in CLAUDE.md + AGENTS.md. https://claude.ai/code/session_01JwntEE4PNAXSMkZxRA9BB4
dackclup
pushed a commit
that referenced
this pull request
May 24, 2026
…+ cache + path filter The docstring fix above triggered simulate (path filter matched compute/scoring/**) which cancelled at 45m02s on the timeout cap. ci-triage-engineer deep-dive (session 5, 2026-05-24) identified the recurring pattern across multiple PRs: the QR_SKIP_TIER2 kill-switch fully wired in compute/scoring/tier2.py:158 was NEVER set in .github/workflows/pre-merge-prod-sim.yml. Past mitigations: - PR #165 (1y non-reliance lookback): addressed a specific 5-year EDGAR backfill spike on one PR but left the universe-wide Tier-2 loop intact - PR-form4-2 (FORM4_FETCH_SKIP=1): saved form4 budget but left the Tier-2 (502 tickers × 10-K text fetch + 8-K fetch) running unconditionally (20-35m cold-cache cost) Recurrence tally on last 5 simulate runs: PR #165 19m01s ✅ warm PR #204 19m37s ✅ warm PR #222 16m56s ✅ warm PR #224 17m08s ✅ warm PR #230 45m15s ❌ CANCELLED (cold) Pattern is structural — when GitHub evicts the warm cache after a 7-day gap without a simulate-triggering PR, the next compute/scoring PR hits full cold. The 4-part permanent fix: (a) QR_SKIP_TIER2: "1" added to pre-merge-prod-sim.yml env block PRIMARY fix — eliminates the 20-35m cold-cache Tier-2 cost. Tradeoff: the non_reliance veto (enabled since PR 4g) is suppressed in simulate's diff output. Acceptable because simulate is informational-only (per workflow comment line 24); non_reliance veto correctness is covered by offline pytest. (b) compute/cache/edgar_form4 added to BOTH workflows' cache paths (compute-rankings.yml save+restore, pre-merge-prod-sim.yml restore only). Future-proofs for Phase 4.5e PR 5 when form4 weight promotion enables FORM4_FETCH_SKIP=0 on simulate. (c) Path filter widened in pre-merge-prod-sim.yml from compute/scoring/** + compute/features/** only to also include: - compute/ingest/** (fundamentals fetcher regressions) - compute/valuation/** (RIM / DCF / ensemble regressions) - compute/output/schemas.py (Pydantic schema bumps) - compute/main.py (orchestrator changes) - pyproject.toml (dep bumps affecting compute) (d) compute/scoring/tier2.py:154-155 docstring corrected The old comment said "_EIGHT_K_DEFENSES_ENABLED=False" but PR 4g (2026-05-17) flipped it to True. The non_reliance veto IS the active veto path now; updated comment explains the veto suppression tradeoff in simulate context. Expected outcomes: - Docstring-only PR in compute/scoring/ → simulate completes in ~12-15m warm or ~17-20m partial-cold (well under 45m cap) - Real scoring PR → same budget; composite-score diff unchanged - Cache eviction (7-day gap) → worst case fundamentals cold ~10-20m + no Tier-2 + no form4 = under cap - Weekly cron UNAFFECTED — QR_SKIP_TIER2 not set there; full run continues to populate the warm cache Companion benefit: this PR's re-pushed simulate is the LIVE VALIDATION of the fix — first sub-45m simulate on this branch proves the fix works. Files touched: - .github/workflows/pre-merge-prod-sim.yml (env + cache + paths) - .github/workflows/compute-rankings.yml (cache path only) - compute/scoring/tier2.py (stale comment) - CLAUDE.md + AGENTS.md (§Phase status note) YAML parse-verified; ruff clean; no compute / schema / scoring / valuation / Python behavior change. CLAUDE.md + AGENTS.md lockstep satisfied via the §Phase status notes. https://claude.ai/code/session_01JwntEE4PNAXSMkZxRA9BB4
dackclup
pushed a commit
that referenced
this pull request
May 24, 2026
…per edgar-debugger live-XML verify The literature-searcher proof-of-life on 2026-05-23 (session 4) flagged a precision gap: the form4 module docstrings referenced the colloquial <rule10b5_1> XML tag name (a label, not the actual SEC EDGAR Ownership XML element). edgar-debugger re-audit on 2026-05-24 (session 5) fetched 3 live AAPL Form 4 XMLs from SEC EDGAR and confirmed the actual element is <aff10b5One> at ownershipDocument/aff10b5One — a DOCUMENT-LEVEL boolean (one per filing, covering ALL transactions in that Form 4), NOT a per-transaction attribute. Updated 7 references to use the canonical name: 5 code spots: - compute/scoring/form4_insider.py:20 (module docstring header) - compute/scoring/form4_insider.py:82 (§Footnote resolution) - compute/scoring/form4_insider.py:587 (inline _form4_to_transactions comment) - compute/scoring/form4_signals.py:129 (module docstring) - compute/output/schemas.py:200 (extreme_estimate_majority_count comment context) 2 doc spots: - CLAUDE.md §Phase status PR #224 entry "Access-path caveat" block (line 1352-1359) - AGENTS.md §Phase + version state PR #224 entry "Access-path caveat for cross-tool agents" block (line 947-951) Added §Footnote resolution architectural-gap note in compute/scoring/form4_insider.py: a filer who checks <aff10b5One>true at the document level but does NOT include the per-transaction footnote text (valid — the checkbox IS the formal affirmative defense, footnotes are supplemental) will slip past the current footnote-text fallback path and enter the opportunistic cohort incorrectly. Deferred to a follow-up PR that direct-parses the raw Form 4 XML for ownershipDocument/aff10b5One (edgartools doesn't expose it, so the implementation walks the filing text once per Ownership object). Tracked as the architectural follow-up after PR 4-eq. edgartools 5.31.5 verified as PyPI latest by edgar-debugger 2026-05-24 — no newer release adds a parse path for <aff10b5One>. detect_10b5_1_plan regex set (6 patterns) confirmed complete vs real-world footnote text — pattern "10b5-1" alone covers every common variant including Rule 10b5-1(c) subsection cites. No additions needed. Docstring-only PR — no compute / scoring / valuation / behavior change. schema_check clean (comment-only edit on schemas.py), ruff clean, tests unchanged at 1168+. CLAUDE.md + AGENTS.md lockstep satisfied via §Phase status in-flight notes. Companion stale-header reword: marked PR #229 "Security WARN cleanup" → "merged via PR #229" in CLAUDE.md + AGENTS.md. https://claude.ai/code/session_01JwntEE4PNAXSMkZxRA9BB4
dackclup
pushed a commit
that referenced
this pull request
May 24, 2026
…+ cache + path filter The docstring fix above triggered simulate (path filter matched compute/scoring/**) which cancelled at 45m02s on the timeout cap. ci-triage-engineer deep-dive (session 5, 2026-05-24) identified the recurring pattern across multiple PRs: the QR_SKIP_TIER2 kill-switch fully wired in compute/scoring/tier2.py:158 was NEVER set in .github/workflows/pre-merge-prod-sim.yml. Past mitigations: - PR #165 (1y non-reliance lookback): addressed a specific 5-year EDGAR backfill spike on one PR but left the universe-wide Tier-2 loop intact - PR-form4-2 (FORM4_FETCH_SKIP=1): saved form4 budget but left the Tier-2 (502 tickers × 10-K text fetch + 8-K fetch) running unconditionally (20-35m cold-cache cost) Recurrence tally on last 5 simulate runs: PR #165 19m01s ✅ warm PR #204 19m37s ✅ warm PR #222 16m56s ✅ warm PR #224 17m08s ✅ warm PR #230 45m15s ❌ CANCELLED (cold) Pattern is structural — when GitHub evicts the warm cache after a 7-day gap without a simulate-triggering PR, the next compute/scoring PR hits full cold. The 4-part permanent fix: (a) QR_SKIP_TIER2: "1" added to pre-merge-prod-sim.yml env block PRIMARY fix — eliminates the 20-35m cold-cache Tier-2 cost. Tradeoff: the non_reliance veto (enabled since PR 4g) is suppressed in simulate's diff output. Acceptable because simulate is informational-only (per workflow comment line 24); non_reliance veto correctness is covered by offline pytest. (b) compute/cache/edgar_form4 added to BOTH workflows' cache paths (compute-rankings.yml save+restore, pre-merge-prod-sim.yml restore only). Future-proofs for Phase 4.5e PR 5 when form4 weight promotion enables FORM4_FETCH_SKIP=0 on simulate. (c) Path filter widened in pre-merge-prod-sim.yml from compute/scoring/** + compute/features/** only to also include: - compute/ingest/** (fundamentals fetcher regressions) - compute/valuation/** (RIM / DCF / ensemble regressions) - compute/output/schemas.py (Pydantic schema bumps) - compute/main.py (orchestrator changes) - pyproject.toml (dep bumps affecting compute) (d) compute/scoring/tier2.py:154-155 docstring corrected The old comment said "_EIGHT_K_DEFENSES_ENABLED=False" but PR 4g (2026-05-17) flipped it to True. The non_reliance veto IS the active veto path now; updated comment explains the veto suppression tradeoff in simulate context. Expected outcomes: - Docstring-only PR in compute/scoring/ → simulate completes in ~12-15m warm or ~17-20m partial-cold (well under 45m cap) - Real scoring PR → same budget; composite-score diff unchanged - Cache eviction (7-day gap) → worst case fundamentals cold ~10-20m + no Tier-2 + no form4 = under cap - Weekly cron UNAFFECTED — QR_SKIP_TIER2 not set there; full run continues to populate the warm cache Companion benefit: this PR's re-pushed simulate is the LIVE VALIDATION of the fix — first sub-45m simulate on this branch proves the fix works. Files touched: - .github/workflows/pre-merge-prod-sim.yml (env + cache + paths) - .github/workflows/compute-rankings.yml (cache path only) - compute/scoring/tier2.py (stale comment) - CLAUDE.md + AGENTS.md (§Phase status note) YAML parse-verified; ruff clean; no compute / schema / scoring / valuation / Python behavior change. CLAUDE.md + AGENTS.md lockstep satisfied via the §Phase status notes. https://claude.ai/code/session_01JwntEE4PNAXSMkZxRA9BB4
dackclup
added a commit
that referenced
this pull request
May 24, 2026
…nent 45-min simulate fix (#230) * docs(form4): correct <rule10b5_1> → <aff10b5One> docstring precision per edgar-debugger live-XML verify The literature-searcher proof-of-life on 2026-05-23 (session 4) flagged a precision gap: the form4 module docstrings referenced the colloquial <rule10b5_1> XML tag name (a label, not the actual SEC EDGAR Ownership XML element). edgar-debugger re-audit on 2026-05-24 (session 5) fetched 3 live AAPL Form 4 XMLs from SEC EDGAR and confirmed the actual element is <aff10b5One> at ownershipDocument/aff10b5One — a DOCUMENT-LEVEL boolean (one per filing, covering ALL transactions in that Form 4), NOT a per-transaction attribute. Updated 7 references to use the canonical name: 5 code spots: - compute/scoring/form4_insider.py:20 (module docstring header) - compute/scoring/form4_insider.py:82 (§Footnote resolution) - compute/scoring/form4_insider.py:587 (inline _form4_to_transactions comment) - compute/scoring/form4_signals.py:129 (module docstring) - compute/output/schemas.py:200 (extreme_estimate_majority_count comment context) 2 doc spots: - CLAUDE.md §Phase status PR #224 entry "Access-path caveat" block (line 1352-1359) - AGENTS.md §Phase + version state PR #224 entry "Access-path caveat for cross-tool agents" block (line 947-951) Added §Footnote resolution architectural-gap note in compute/scoring/form4_insider.py: a filer who checks <aff10b5One>true at the document level but does NOT include the per-transaction footnote text (valid — the checkbox IS the formal affirmative defense, footnotes are supplemental) will slip past the current footnote-text fallback path and enter the opportunistic cohort incorrectly. Deferred to a follow-up PR that direct-parses the raw Form 4 XML for ownershipDocument/aff10b5One (edgartools doesn't expose it, so the implementation walks the filing text once per Ownership object). Tracked as the architectural follow-up after PR 4-eq. edgartools 5.31.5 verified as PyPI latest by edgar-debugger 2026-05-24 — no newer release adds a parse path for <aff10b5One>. detect_10b5_1_plan regex set (6 patterns) confirmed complete vs real-world footnote text — pattern "10b5-1" alone covers every common variant including Rule 10b5-1(c) subsection cites. No additions needed. Docstring-only PR — no compute / scoring / valuation / behavior change. schema_check clean (comment-only edit on schemas.py), ruff clean, tests unchanged at 1168+. CLAUDE.md + AGENTS.md lockstep satisfied via §Phase status in-flight notes. Companion stale-header reword: marked PR #229 "Security WARN cleanup" → "merged via PR #229" in CLAUDE.md + AGENTS.md. https://claude.ai/code/session_01JwntEE4PNAXSMkZxRA9BB4 * ci(simulate): permanent 45-min cancellation fix — wire QR_SKIP_TIER2 + cache + path filter The docstring fix above triggered simulate (path filter matched compute/scoring/**) which cancelled at 45m02s on the timeout cap. ci-triage-engineer deep-dive (session 5, 2026-05-24) identified the recurring pattern across multiple PRs: the QR_SKIP_TIER2 kill-switch fully wired in compute/scoring/tier2.py:158 was NEVER set in .github/workflows/pre-merge-prod-sim.yml. Past mitigations: - PR #165 (1y non-reliance lookback): addressed a specific 5-year EDGAR backfill spike on one PR but left the universe-wide Tier-2 loop intact - PR-form4-2 (FORM4_FETCH_SKIP=1): saved form4 budget but left the Tier-2 (502 tickers × 10-K text fetch + 8-K fetch) running unconditionally (20-35m cold-cache cost) Recurrence tally on last 5 simulate runs: PR #165 19m01s ✅ warm PR #204 19m37s ✅ warm PR #222 16m56s ✅ warm PR #224 17m08s ✅ warm PR #230 45m15s ❌ CANCELLED (cold) Pattern is structural — when GitHub evicts the warm cache after a 7-day gap without a simulate-triggering PR, the next compute/scoring PR hits full cold. The 4-part permanent fix: (a) QR_SKIP_TIER2: "1" added to pre-merge-prod-sim.yml env block PRIMARY fix — eliminates the 20-35m cold-cache Tier-2 cost. Tradeoff: the non_reliance veto (enabled since PR 4g) is suppressed in simulate's diff output. Acceptable because simulate is informational-only (per workflow comment line 24); non_reliance veto correctness is covered by offline pytest. (b) compute/cache/edgar_form4 added to BOTH workflows' cache paths (compute-rankings.yml save+restore, pre-merge-prod-sim.yml restore only). Future-proofs for Phase 4.5e PR 5 when form4 weight promotion enables FORM4_FETCH_SKIP=0 on simulate. (c) Path filter widened in pre-merge-prod-sim.yml from compute/scoring/** + compute/features/** only to also include: - compute/ingest/** (fundamentals fetcher regressions) - compute/valuation/** (RIM / DCF / ensemble regressions) - compute/output/schemas.py (Pydantic schema bumps) - compute/main.py (orchestrator changes) - pyproject.toml (dep bumps affecting compute) (d) compute/scoring/tier2.py:154-155 docstring corrected The old comment said "_EIGHT_K_DEFENSES_ENABLED=False" but PR 4g (2026-05-17) flipped it to True. The non_reliance veto IS the active veto path now; updated comment explains the veto suppression tradeoff in simulate context. Expected outcomes: - Docstring-only PR in compute/scoring/ → simulate completes in ~12-15m warm or ~17-20m partial-cold (well under 45m cap) - Real scoring PR → same budget; composite-score diff unchanged - Cache eviction (7-day gap) → worst case fundamentals cold ~10-20m + no Tier-2 + no form4 = under cap - Weekly cron UNAFFECTED — QR_SKIP_TIER2 not set there; full run continues to populate the warm cache Companion benefit: this PR's re-pushed simulate is the LIVE VALIDATION of the fix — first sub-45m simulate on this branch proves the fix works. Files touched: - .github/workflows/pre-merge-prod-sim.yml (env + cache + paths) - .github/workflows/compute-rankings.yml (cache path only) - compute/scoring/tier2.py (stale comment) - CLAUDE.md + AGENTS.md (§Phase status note) YAML parse-verified; ruff clean; no compute / schema / scoring / valuation / Python behavior change. CLAUDE.md + AGENTS.md lockstep satisfied via the §Phase status notes. https://claude.ai/code/session_01JwntEE4PNAXSMkZxRA9BB4 * docs(workflow): rebase-discipline § + parallel-PR §Phase status collision §Gotcha Closes the recurring "merge ไม่ได้ หลังแก้แล้วกลับมาเป็นอีก" pattern surfaced 2026-05-24: PR #230 hit mergeable_state=dirty twice in a single session — first when PR #229 (security WARN cleanup) landed on main mid-iteration, then again when PR #232 + PR #233 (LedgerCraft A1 + A2) landed before Mark-Ready. ROOT CAUSE: every PR adds a "**X in flight (this PR)**" entry at the SAME insertion line in CLAUDE.md §Phase status + AGENTS.md §Phase + version state (just before "**Next deliverables**" / "## Claude-Code-specific tooling"). Two parallel PRs both touch that single line → `git merge` cannot auto-resolve two distinct adds at the same line → `mergeable_state: dirty`. The conflict is BENIGN (both adds are legitimate; resolution is always "keep both in chronological order") but git can't auto-detect that. THREE COMPANION EDITS bundled here: (a) CLAUDE.md §Conventions — new bullet "Rebase onto origin/main before flipping any PR Draft → Ready". Includes the operational `git fetch origin main && git rebase origin/main` recipe + the "keep both entries in chronological order (older PR first, your entry second)" resolution discipline. (b) CLAUDE.md §Gotchas — new "Parallel-PR §Phase status collision pattern" entry recording the recurring symptom (PR #230 ×2 on 2026-05-24 against PR #229 + PR #232 + PR #233) + the local-mitigation workflow + a forward-looking structural follow-up note: consider moving the "in flight" sub-block to a side file (PHASE_STATUS_INFLIGHT.md) that's append-only- per-PR; on merge a housekeeping commit moves the entry into CLAUDE.md proper. Not yet adopted — trade-off is extra discipline at merge time. (c) AGENTS.md mirror — cross-tool equivalent for Copilot / Cursor / Devin contributors, emphasising the rebase-before-Mark-Ready discipline applies to ALL agent runtimes (not Claude-Code- specific). ALSO bundled as a 3rd in-flight entry in the §Phase status block documenting THIS PR's scope expansion (Parts 1+2+3 now). No infrastructure / CI / behavior change — pure doc discipline. Future contributors who hit the same conflict find the §Gotchas entry + the §Conventions recipe + AGENTS.md note and resolve in seconds, instead of re-discovering the pattern. https://claude.ai/code/session_01JwntEE4PNAXSMkZxRA9BB4 * ci(simulate): Part 4 — wire QR_SKIP_FUNDAMENTALS to actually close the 45m cap Part 2's QR_SKIP_TIER2 fix was necessary but NOT sufficient. Re-pushing the rebased branch on 2026-05-24 07:06 UTC still hit simulate cancelled at 45m15s. ci-triage-engineer deep-dive #2 identified the gap: compute/main.py has THREE independent SEC EDGAR ThreadPoolExecutor loops, and Part 2 only killed ONE (Step 4b — Tier-2): Step 2 (compute/main.py:717) — fundamentals snapshot (502 tickers × SEC companyfacts XBRL); NOT skipped by QR_SKIP_TIER2 Step 3 (compute/main.py:785) — annual fundamentals history; same Step 4b (compute/main.py:972) — Tier-2 / 8-K; killed by Part 2 Cold-cache cost of Steps 2+3 alone is 25-50m per CLAUDE.md §Gotchas — enough to fill the entire 45m simulate budget. Worse, the cache freshness gate at compute/ingest/fundamentals.py:917 (_is_fresh()) checks the filed_date INSIDE each cached parquet against FUNDAMENTALS_REFETCH_DAYS=45. On a partial cache hit, any ticker with a > 45d-old most-recent filing still triggers a live EDGAR round-trip. Part 4 fix — QR_SKIP_FUNDAMENTALS=1 escape hatch: (a) compute/ingest/fundamentals.py:fetch_fundamentals — env-var check added at the top of the function (BEFORE _require_identity()), so the cached snapshot is returned unconditionally when set, without a freshness check OR an EDGAR identity requirement. Falls through to live fetch if no cache exists (cold runner has nothing to read). (b) compute/ingest/fundamentals.py:fetch_fundamentals_history — mirror pattern: returns the cached annual parquet without the 180d age check when QR_SKIP_FUNDAMENTALS=1 AND force_refresh=False. Same fallthrough. (c) .github/workflows/pre-merge-prod-sim.yml — adds QR_SKIP_FUNDAMENTALS: "1" to the env block alongside QR_SKIP_TIER2 and FORM4_FETCH_SKIP. Inline comment explains the root cause + the safety reasoning. SAFE for simulate because: - The workflow's purpose is composite-score-DIFF detection vs main's COMMITTED rankings.json - Both sides (PR branch + main) were produced from the same upstream fundamentals input (the cache the weekly cron wrote) - Using that cache without re-fetch is the CORRECT input for the diff - It's NOT a quality compromise — re-fetching live would give the PR branch newer data than main has, making the diff confusing rather than accurate Weekly cron (compute-rankings.yml) does NOT set QR_SKIP_FUNDAMENTALS — full live fetch still runs there and populates the warm cache for future simulate restores. Expected outcome: simulate completes in 8-12m on a cache-hit restore (no live SEC fetch in any of Steps 2, 3, or 4b). Live validation: re-push after this commit → simulate green under 25m on this PR. Tests verified: tests/test_features/test_fundamentals.py + tests/test_workflow_cache_coverage.py = 24 pass / 6 skipped. ruff clean. YAML parse-verified. schema_check in sync. CLAUDE.md §Phase status + AGENTS.md §Phase + version state both updated with the Part 4 explanation. Future contributors editing pre-merge-prod-sim.yml should now keep all THREE escape-hatch env vars set together: FORM4_FETCH_SKIP + QR_SKIP_TIER2 + QR_SKIP_FUNDAMENTALS. https://claude.ai/code/session_01JwntEE4PNAXSMkZxRA9BB4 --------- Co-authored-by: Claude <noreply@anthropic.com>
dackclup
pushed a commit
that referenced
this pull request
May 24, 2026
Addresses release-captain BLOCKED-ON-PRE-FLIGHT blocker #3 from the v1.3.0 tag attempt — PHASE_STATUS.md / SKILL.md / WORKFLOW.md were 3 days + ~32 PRs stale (last touched PR #171, 2026-05-21). Brings all three docs current to main HEAD 1ff6c11 so the release-captain ladder can re-attempt cleanly. PHASE_STATUS.md - Header date 2026-05-21 → 2026-05-24 - Current state table: schema 0.9.4-phase4h.4 → 0.10.2-phase4.5e; defense layer 27 → 32 emitted flags; subagent inventory 14 → 18 (named tier roster — 4 opus / 14 sonnet); skill inventory 42 → 43; production run a16c887 → 9015748 (cron #3 2026-05-23); release- tag line annotated with v1.3.0 target pending - Recently-merged block: refreshed to PR #170 → PR #237 (~36 entries with commit shas, chronological), drops the stale PR #147-#169 block - Next-deliverables list: 5 items updated — Phase 4.5e PR 5 cluster weight promotion / Issue #67 sector-CoE flip / v1.3.0 release tag gate / Phase 4i.1-4j.1-4k.1 factor integrations / Phase 5 ML meta-learner - Open issues line: drops resolved #155 (closed via PR #160), refreshes #41 (15 open advisories, zero exploitability on static-export), refreshes #67 (data-collection merged PR #204) SKILL.md - Schema-version table: 7 new rows added in reverse-chronological order (matches existing 0.9.x convention) for `0.9.5` → `0.9.6` → `0.9.7` → `0.9.8` → `0.10.0` → `0.10.1` → `0.10.2` covering PRs #180/#181/#183/#204/#205/#222/#224. Each row carries PR # + 1-line scope + backward-compat note + literature anchor. WORKFLOW.md - Phase Overview table 4.5 row marked ✅ DONE 2026-05-23 + 10b5-1 filter scope note - SEC Filing Roadmap Form 4 row flipped "planned" → "active" with 4-PR ladder reference (#167/#205/#222/#224 + 100% coverage on cron #3) - Phase 4.5e task list — 5 items flipped `[ ]` → `[x]` with per-PR commits + methodology-scientist Mode B verdicts inline + Aboody et al. 2010 §3.2 weight-promotion gate noted - Phase 4.5 Acceptance Criteria — all 9 items flipped to `[x]` with completion evidence (cron #3 / methodology verdicts / PR refs) - Phase 4.5f tag item — flipped `[ ]` → `[x]` (`v1.2.0-phase4.5` cut 2026-05-17 at 6d414a9) PHASE_STATUS_INFLIGHT.md - Append new "(this PR)" entry under In-flight section per the PR #237 side-file convention. Documents the doc-refresh scope + cross-refs to release-captain blockers 1/2/4/5 still pending. Lockstep - PR #237's PHASE_STATUS_INFLIGHT.md side-file pattern handles the §Conventions "ship with every PR" rule for this doc-only PR - No CLAUDE.md / AGENTS.md substantive change required — the in-flight entry lives in the side-file per the new convention - No compute / schema / scoring / valuation / frontend / Python / TypeScript code change - Unblocks v1.3.0 tag blocker #3; blockers 1 (wrong-branch), 2 (pyproject.toml 0.3.0 → 1.3.0), 4 (production output 1 cron cycle behind code), and 5 (release notes draft scope) still need resolution before tag cut
5 tasks
dackclup
added a commit
that referenced
this pull request
May 24, 2026
… from PR #230 (+ dogfoods PR #237 INFLIGHT convention) (#238) PR #230's edgar-debugger audit + Part 1 §"Footnote resolution" docstring surfaced an architectural gap: filers who check <aff10b5One>true at the document level but omit the per-transaction footnote text slip past the existing footnote-text regex path and INCORRECTLY enter the opportunistic-trades cohort that drives the insider_sell_cluster + c_suite_unusual_sell annotates. edgar-debugger session 5 design report (2026-05-24) confirmed: - Access path: filing.xml() — already @lru_cache(maxsize=4), so calling it AFTER filing.obj() is a free cache hit (zero extra HTTP per filing; universe-wide added cost ~1.5s for lxml find) - Element location: ownershipDocument/aff10b5One per SEC schema X0609 (Release 33-11138, effective 2023-04-01) - Edgartools 5.31.5's Ownership.parse_xml walks a fixed set of child tags and never reads aff10b5One — the element is PRESENT in the BS4 tree but discarded after parse Implementation (compute/scoring/form4_insider.py, ~30 LOC prod): - _AFF10B5_REQUIRED_ATTRS = ("aff10b5One",) manifest tuple (drift-detector documenting the canonical SEC element name) - _extract_aff10b5_one(xml_str) helper — lxml-based, handles 1/true/0/false variants, returns None on absent / parse fail (graceful-degradation per existing pattern + methodology- scientist Mode B option (a) from PR #224) - _combine_10b5_one_signals(doc_level, footnote_result) helper — OR-of-True truth table: True if either signal is True; None only when both are None; False otherwise - _form4_to_transactions modified to call filing.xml() + _extract_aff10b5_one() ONCE per filing, then propagate via _combine_10b5_one_signals() to every transaction in that filing's rows - Form4Transaction dataclass gains aff10b5_one_doc_level: bool | None = None field (backward-compat default for pre-PR cache rows); from_dict reads it via .get(...) with None fallback Tests (tests/test_scoring/test_form4_insider.py, ~80 LOC, 10 cases H1-H10) — test-engineer spawn delivered the spec: - H1-H4: _extract_aff10b5_one truth + variants + malformed + absent - H5: doc-level propagation to all transactions in a filing (mock filing with xml() method that returns synthetic XML) - H6-H8: _combine_10b5_one_signals truth-table coverage - H9: _AFF10B5_REQUIRED_ATTRS manifest drift-detector (mirrors the existing _FOOTNOTES_REQUIRED_ATTRS pattern at line 815) - H10 (@network): live AAPL Form 4 extraction verifies access path end-to-end Verification: $ pytest tests/test_scoring/test_form4_insider.py -v -m "not network" → 32 passed, 2 deselected (H10 + D4 @network) $ python3 -c "from compute.scoring.form4_insider import _extract_aff10b5_one, _combine_10b5_one_signals; ..." → 14 smoke assertions pass (all variants + truth-table) $ ruff check compute/scoring/form4_insider.py → All checks passed! $ python -m compute.output.schema_check → Schema snapshot in sync Scope held to edgar-debugger estimate: - ~30 LOC prod ✓ - ~80 LOC tests (actual: 214 lines including mock fixtures + docstrings) ✓ - 0 new deps (lxml is already a transitive dep of edgartools) ✓ - 0 schema changes (new field lives in Form-4 cache rows only; doesn't surface in StockDetail / Metadata in this PR) ✓ Defense layer flag count UNCHANGED at 32 (combined signal is quality-improvement, not new flag). Downstream consumer _is_opportunistic_sell in form4_signals.py reads the existing combined is_rule_10b5_one field — no consumer changes needed. DOGFOODING the PR #237 convention: this PR's in-flight entry lives in PHASE_STATUS_INFLIGHT.md (NOT CLAUDE.md / AGENTS.md §Phase status). First PR to test-drive the side-file pattern end-to-end. Lockstep rule satisfied per the new §Conventions wording (an in-flight entry in PHASE_STATUS_INFLIGHT.md OR a substance update to CLAUDE.md/AGENTS.md sections — this PR uses the former). Companion housekeeping move: PR #237's own in-flight entry moved from "## In flight" to "## Merged" section within PHASE_STATUS_INFLIGHT.md (still awaiting the housekeeping commit to CLAUDE.md §Phase status — that's a separate workflow not in scope here). https://claude.ai/code/session_01JwntEE4PNAXSMkZxRA9BB4 Co-authored-by: Claude <noreply@anthropic.com>
dackclup
pushed a commit
that referenced
this pull request
May 24, 2026
Addresses release-captain BLOCKED-ON-PRE-FLIGHT blocker #3 from the v1.3.0 tag attempt — PHASE_STATUS.md / SKILL.md / WORKFLOW.md were 3 days + ~32 PRs stale (last touched PR #171, 2026-05-21). Brings all three docs current to main HEAD 1ff6c11 so the release-captain ladder can re-attempt cleanly. PHASE_STATUS.md - Header date 2026-05-21 → 2026-05-24 - Current state table: schema 0.9.4-phase4h.4 → 0.10.2-phase4.5e; defense layer 27 → 32 emitted flags; subagent inventory 14 → 18 (named tier roster — 4 opus / 14 sonnet); skill inventory 42 → 43; production run a16c887 → 9015748 (cron #3 2026-05-23); release- tag line annotated with v1.3.0 target pending - Recently-merged block: refreshed to PR #170 → PR #237 (~36 entries with commit shas, chronological), drops the stale PR #147-#169 block - Next-deliverables list: 5 items updated — Phase 4.5e PR 5 cluster weight promotion / Issue #67 sector-CoE flip / v1.3.0 release tag gate / Phase 4i.1-4j.1-4k.1 factor integrations / Phase 5 ML meta-learner - Open issues line: drops resolved #155 (closed via PR #160), refreshes #41 (15 open advisories, zero exploitability on static-export), refreshes #67 (data-collection merged PR #204) SKILL.md - Schema-version table: 7 new rows added in reverse-chronological order (matches existing 0.9.x convention) for `0.9.5` → `0.9.6` → `0.9.7` → `0.9.8` → `0.10.0` → `0.10.1` → `0.10.2` covering PRs #180/#181/#183/#204/#205/#222/#224. Each row carries PR # + 1-line scope + backward-compat note + literature anchor. WORKFLOW.md - Phase Overview table 4.5 row marked ✅ DONE 2026-05-23 + 10b5-1 filter scope note - SEC Filing Roadmap Form 4 row flipped "planned" → "active" with 4-PR ladder reference (#167/#205/#222/#224 + 100% coverage on cron #3) - Phase 4.5e task list — 5 items flipped `[ ]` → `[x]` with per-PR commits + methodology-scientist Mode B verdicts inline + Aboody et al. 2010 §3.2 weight-promotion gate noted - Phase 4.5 Acceptance Criteria — all 9 items flipped to `[x]` with completion evidence (cron #3 / methodology verdicts / PR refs) - Phase 4.5f tag item — flipped `[ ]` → `[x]` (`v1.2.0-phase4.5` cut 2026-05-17 at 6d414a9) PHASE_STATUS_INFLIGHT.md - Append new "(this PR)" entry under In-flight section per the PR #237 side-file convention. Documents the doc-refresh scope + cross-refs to release-captain blockers 1/2/4/5 still pending. Lockstep - PR #237's PHASE_STATUS_INFLIGHT.md side-file pattern handles the §Conventions "ship with every PR" rule for this doc-only PR - No CLAUDE.md / AGENTS.md substantive change required — the in-flight entry lives in the side-file per the new convention - No compute / schema / scoring / valuation / frontend / Python / TypeScript code change - Unblocks v1.3.0 tag blocker #3; blockers 1 (wrong-branch), 2 (pyproject.toml 0.3.0 → 1.3.0), 4 (production output 1 cron cycle behind code), and 5 (release notes draft scope) still need resolution before tag cut
dackclup
added a commit
that referenced
this pull request
May 24, 2026
…239) Addresses release-captain BLOCKED-ON-PRE-FLIGHT blocker #3 from the v1.3.0 tag attempt — PHASE_STATUS.md / SKILL.md / WORKFLOW.md were 3 days + ~32 PRs stale (last touched PR #171, 2026-05-21). Brings all three docs current to main HEAD 1ff6c11 so the release-captain ladder can re-attempt cleanly. PHASE_STATUS.md - Header date 2026-05-21 → 2026-05-24 - Current state table: schema 0.9.4-phase4h.4 → 0.10.2-phase4.5e; defense layer 27 → 32 emitted flags; subagent inventory 14 → 18 (named tier roster — 4 opus / 14 sonnet); skill inventory 42 → 43; production run a16c887 → 9015748 (cron #3 2026-05-23); release- tag line annotated with v1.3.0 target pending - Recently-merged block: refreshed to PR #170 → PR #237 (~36 entries with commit shas, chronological), drops the stale PR #147-#169 block - Next-deliverables list: 5 items updated — Phase 4.5e PR 5 cluster weight promotion / Issue #67 sector-CoE flip / v1.3.0 release tag gate / Phase 4i.1-4j.1-4k.1 factor integrations / Phase 5 ML meta-learner - Open issues line: drops resolved #155 (closed via PR #160), refreshes #41 (15 open advisories, zero exploitability on static-export), refreshes #67 (data-collection merged PR #204) SKILL.md - Schema-version table: 7 new rows added in reverse-chronological order (matches existing 0.9.x convention) for `0.9.5` → `0.9.6` → `0.9.7` → `0.9.8` → `0.10.0` → `0.10.1` → `0.10.2` covering PRs #180/#181/#183/#204/#205/#222/#224. Each row carries PR # + 1-line scope + backward-compat note + literature anchor. WORKFLOW.md - Phase Overview table 4.5 row marked ✅ DONE 2026-05-23 + 10b5-1 filter scope note - SEC Filing Roadmap Form 4 row flipped "planned" → "active" with 4-PR ladder reference (#167/#205/#222/#224 + 100% coverage on cron #3) - Phase 4.5e task list — 5 items flipped `[ ]` → `[x]` with per-PR commits + methodology-scientist Mode B verdicts inline + Aboody et al. 2010 §3.2 weight-promotion gate noted - Phase 4.5 Acceptance Criteria — all 9 items flipped to `[x]` with completion evidence (cron #3 / methodology verdicts / PR refs) - Phase 4.5f tag item — flipped `[ ]` → `[x]` (`v1.2.0-phase4.5` cut 2026-05-17 at 6d414a9) PHASE_STATUS_INFLIGHT.md - Append new "(this PR)" entry under In-flight section per the PR #237 side-file convention. Documents the doc-refresh scope + cross-refs to release-captain blockers 1/2/4/5 still pending. Lockstep - PR #237's PHASE_STATUS_INFLIGHT.md side-file pattern handles the §Conventions "ship with every PR" rule for this doc-only PR - No CLAUDE.md / AGENTS.md substantive change required — the in-flight entry lives in the side-file per the new convention - No compute / schema / scoring / valuation / frontend / Python / TypeScript code change - Unblocks v1.3.0 tag blocker #3; blockers 1 (wrong-branch), 2 (pyproject.toml 0.3.0 → 1.3.0), 4 (production output 1 cron cycle behind code), and 5 (release notes draft scope) still need resolution before tag cut Co-authored-by: Claude <noreply@anthropic.com>
9 tasks
This was referenced May 25, 2026
Merged
dackclup
added a commit
that referenced
this pull request
May 26, 2026
…Craft frontend (#266) Cuts the v1.3.0-phase4.5e release tag, closing the Phase 4.5e Form-4 insider-clustering ladder (PRs #167+#205+#222+#224+#238) and shipping the LedgerCraft frontend reskin (A1-A3+B1-B4+animation PRs 1-3+#244 polish+dark-mode tooltip fixes through PR #263) since v1.2.0-phase4.5 (6d414a9, 2026-05-17). Scope (3 files): - pyproject.toml — version 0.3.0 → 1.3.0 - docs/release-notes/v1.3.0-phase4.5e.md (NEW) — release body grouped by Form-4 cluster / data-quality / defense layer / frontend / methodology + agent infra / CI hygiene; ~800 words - PHASE_STATUS.md — Current state schema 0.10.4 → 0.10.5-phase4.5e, defense layer headline 32 → 33 declared flags, production-run pointer refreshed to 26423296287 Pre-flight ladder verified by release-captain (opus): - ruff clean - pytest 1216 passed (offline) - schema_check in sync at 0.10.5-phase4.5e - verify-production-output Section A-G + I-L PASS; Section H 1 known FAIL (orphan BK.json legacy snapshot, pre-existing) - frontend build verified via vercel-preview-auditor (sonnet) on main HEAD e6013ba — 506/506 routes compiled, types validated, runtime clean, 3-route UA probe PASS Defense scorecard: 7 active vetoes unchanged (altman_distress / sloan_accruals_top_decile / net_issuance_top_decile / non_reliance_filing / beneish_manipulation_veto / dechow_manipulation_veto / data_quality_input_corruption). Headline 32 → 33 declared boolean flags (adds multi_class_aggregate_shares_suspected per PR #264; PR #265 DQIC rename is identifier-shape, not new flag). Production output: metadata.json reports 0.10.4-phase4.5e from cron #4 (2026-05-26T01:12); next weekday cron Wed 2026-05-27 22:00 UTC re-renders at full 0.10.5-phase4.5e semantics. Tag is anchored to code, not last committed snapshot per release-tag SKILL.md §Gotchas. CVE baseline 25 → 15 open (0C/6H/7M/2L); all 15 are next@14.x SSR advisories with zero exploitability on static-export. Post-merge: tag command + GitHub Release creation require explicit user authorization per CLAUDE.md §Executing actions with care. https://claude.ai/code/session_01JwntEE4PNAXSMkZxRA9BB4 Co-authored-by: Claude <noreply@anthropic.com>
6 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
Closes footgun #1 documented in
compute/scoring/form4_signals.pymodule docstring — Jagolinzer 2009 §3.2 expected FP rate 40-60% oninsider_sell_clusterfrom 10b5-1 contamination._is_opportunistic_sellnow requires NOTis_rule_10b5_one is Truein addition to thetransaction_code ∈ {S, D}gate so 10b5-1 scheduled trades are excluded from BOTH cluster + C-suite cohort counts._is_opportunistic_sellapplies to bothinsider_sell_clusterandc_suite_unusual_sell. C-suite inheritance carries STRONGER lit support (Jagolinzer 2009 §5.2 NEO 80% predictability drop; CMP 2012 §V.A CFO 9× ratio vs broad 4×).Metadata.form4_rule10b5_one_excluded_count.Access-path caveat — read before reviewing the parser
edgartools 5.31.5 does NOT parse the SEC structured
<rule10b5_1>XML element added by SEC Release 33-11138 (effective 2023-04-01). Verified byedgar-debugger2026-05-23 via exhaustive grep ofedgar.ownership. Theequity_swap: strfield onNonDerivativeTransactioncarries<equitySwapInvolved>— unrelated SEC concept, do NOT assume it carries 10b5-1.Resolution path:
NonDerivativeTransaction.footnotescarries newline-joined footnote IDs ("F1\nF2") — callingdetect_10b5_1_planon these directly returns False (silently broken).Ownership.footnotes: Footnotesis the dict that resolves IDs → text via public.get(id, default)accessor (avoids underscore-prefixed_resolve_footnotesprivate method).edgar.ownership.core.detect_10b5_1_plan(resolved_text)regex-matches["10b5-1", "10b-5-1", "rule 10b5", "rule 10b-5", "10b5 plan", "10b-5 plan"].New manifest pin
_FOOTNOTES_REQUIRED_ATTRS = ("get",);footnotesadded to existing_NON_DERIVATIVE_TX_REQUIRED_ATTRS+_OWNERSHIP_REQUIRED_ATTRSmanifests.FP risk: terminated-plan disclosures ("10b5-1 plan terminated 2022") match True. Bias is conservative (over-excludes from opportunistic cohort, never under-excludes); Q3 2026-08-19 audit gates negation guard.
Rule 18 observability
Metadata.form4_rule10b5_one_excluded_count: int | Nonecounts universe-wide transactions excluded by the filter within the 30d cluster window. Schema bump0.10.1-phase4.5e→0.10.2-phase4.5e(PATCH, additive). Defense layer emitted-flag count UNCHANGED at 32 (filter is signal-quality, not new flag). schema_check clean.Expected firing-rate Δ (Mode B 2026-05-23)
insider_sell_clusterfiring-rate Δ vs PR #222 baselinec_suite_unusual_sellfiring-rate Δ vs PR #222 baselineBelow/above-band → escalate at Q3 2026-08-19 cohort audit (issue #130).
Test plan
ruff check compute/— cleanpython -m compute.output.schema_check— clean (snapshot regenerated)test-engineersub-agent writing 16+ new cases ontests/test_scoring/test_form4_signals.py+tests/test_scoring/test_form4_insider.py(filter semantics + None-handling + cluster threshold interaction + C-suite inheritance + strict-superset invariant under filter + Hypothesis monotonicity property + parser footnote resolution + drift-detector manifest extension). Will land as a follow-up commit on this branch.pytest -m "not network"against full suite (1144 → 1160+)schema-sentinelfinal lockstep gatequantrank-reviewerRules 1-18 passReferences
compute/scoring/form4_signals.py:101-111(PR feat(scoring): Phase 4.5e PR 3 — insider_sell_cluster + c_suite_unusual_sell annotates #222 carried-forward gate)https://claude.ai/code/session_01SSg1tZypxdgthAYTnQyd1h
Generated by Claude Code