From 9672e341bca64c6a4b5caac9e42441203636b04b Mon Sep 17 00:00:00 2001 From: "github-actions[bot]" Date: Sat, 29 Nov 2025 21:12:43 +0000 Subject: [PATCH 01/40] chore(codex): bootstrap PR for issue #3879 --- agents/codex-3879.md | 1 + 1 file changed, 1 insertion(+) create mode 100644 agents/codex-3879.md diff --git a/agents/codex-3879.md b/agents/codex-3879.md new file mode 100644 index 0000000000..72cc7c30c3 --- /dev/null +++ b/agents/codex-3879.md @@ -0,0 +1 @@ + From 21bab4efd160d7e1d101459669557f2e26bbbbc1 Mon Sep 17 00:00:00 2001 From: stranske Date: Sat, 29 Nov 2025 15:46:23 -0600 Subject: [PATCH 02/40] Handle infinite cadence intervals without deprecated pandas option --- src/trend_analysis/io/market_data.py | 25 +++++++++++++--- .../test_market_data_validation_additional.py | 29 +++++++++++++++++++ 2 files changed, 50 insertions(+), 4 deletions(-) diff --git a/src/trend_analysis/io/market_data.py b/src/trend_analysis/io/market_data.py index 11848d07cf..4649bfa712 100644 --- a/src/trend_analysis/io/market_data.py +++ b/src/trend_analysis/io/market_data.py @@ -24,6 +24,8 @@ cast, ) +import numpy as np + import pandas as pd from pandas.api.types import is_numeric_dtype from pydantic import BaseModel, Field, model_validator @@ -350,6 +352,11 @@ def _summarise_missing_policy(info: Mapping[str, Any]) -> str: return "; ".join(parts) +def _normalize_delta_days(delta_days: pd.Series) -> pd.Series: + cleaned = delta_days.replace([np.inf, -np.inf], np.nan).dropna() + return cleaned.astype(float) + + def classify_frequency( index: pd.DatetimeIndex, *, @@ -379,7 +386,18 @@ def classify_frequency( "tolerance_periods": 0, } - delta_days = diffs / pd.Timedelta(days=1) + delta_days = _normalize_delta_days(diffs / pd.Timedelta(days=1)) + if delta_days.empty: + return { + "canonical": "UNKNOWN", + "code": "UNKNOWN", + "label": "unknown", + "median_days": 0.0, + "max_missing_periods": 0, + "total_missing_periods": 0, + "tolerance_periods": 0, + } + median_days = float(delta_days.median()) if median_days <= 0: @@ -426,9 +444,8 @@ def classify_frequency( if max_gap_limit is not None: tolerance_limit = max(tolerance_default, max_gap_limit) - with pd.option_context("mode.use_inf_as_na", True): - raw_ratio = delta_days / base_days - nearest = raw_ratio.round().clip(lower=1) + raw_ratio = delta_days / base_days + nearest = raw_ratio.round().clip(lower=1) deviation = (raw_ratio - nearest).abs() irregular_mask = (nearest == 1) & (deviation > 0.34) diff --git a/tests/test_market_data_validation_additional.py b/tests/test_market_data_validation_additional.py index dda6406637..733ae1d0c1 100644 --- a/tests/test_market_data_validation_additional.py +++ b/tests/test_market_data_validation_additional.py @@ -138,6 +138,35 @@ def test_classify_frequency_detects_weekly() -> None: assert info["tolerance_periods"] == 1 +def test_normalize_delta_days_drops_infinite_values() -> None: + delta_days = pd.Series([30.0, float("inf"), -float("inf"), 31.0]) + + cleaned = market_data._normalize_delta_days(delta_days) + + assert cleaned.tolist() == [30.0, 31.0] + + +def test_classify_frequency_ignores_infinite_offsets( + monkeypatch: pytest.MonkeyPatch, +) -> None: + index = pd.date_range("2024-01-31", periods=5, freq="ME") + + original = market_data._normalize_delta_days + + def inject_and_clean(delta_days: pd.Series) -> pd.Series: + polluted = delta_days.astype(float) + polluted.iloc[0] = float("inf") + polluted.iloc[-1] = -float("inf") + return original(polluted) + + monkeypatch.setattr(market_data, "_normalize_delta_days", inject_and_clean) + + info = market_data.classify_frequency(index) + + assert info["code"] == "M" + assert info["label"] == "monthly" + + def test_classify_frequency_irregular_preview_includes_ellipsis() -> None: base = pd.date_range("2024-01-01", periods=8, freq="30D") irregular = base.insert(4, base[3] + pd.Timedelta(days=2)) From 9aef2a72ce11c9c56ff6b9d51502b86b2775ad30 Mon Sep 17 00:00:00 2001 From: stranske Date: Sat, 29 Nov 2025 15:48:09 -0600 Subject: [PATCH 03/40] Handle infinite cadence intervals without deprecated pandas option (#3889) --- agents/codex-3879.md | 1 + src/trend_analysis/io/market_data.py | 14 ++++-- .../test_market_data_validation_additional.py | 44 +++++++++++++++++++ 3 files changed, 56 insertions(+), 3 deletions(-) diff --git a/agents/codex-3879.md b/agents/codex-3879.md index 72cc7c30c3..f5feecc01e 100644 --- a/agents/codex-3879.md +++ b/agents/codex-3879.md @@ -1 +1,2 @@ + diff --git a/src/trend_analysis/io/market_data.py b/src/trend_analysis/io/market_data.py index 4649bfa712..41dc0dabda 100644 --- a/src/trend_analysis/io/market_data.py +++ b/src/trend_analysis/io/market_data.py @@ -25,7 +25,6 @@ ) import numpy as np - import pandas as pd from pandas.api.types import is_numeric_dtype from pydantic import BaseModel, Field, model_validator @@ -46,6 +45,15 @@ "YE": "annual", } + +def _normalise_delta_days(delta_days: pd.Series) -> pd.Series: + if delta_days.empty: + return delta_days + + cleaned = delta_days.replace([np.inf, -np.inf], np.nan) + return cleaned.dropna() + + _DEFAULT_MISSING_POLICY = "drop" _VALID_MISSING_POLICIES = {"drop", "ffill", "zero"} @@ -386,7 +394,8 @@ def classify_frequency( "tolerance_periods": 0, } - delta_days = _normalize_delta_days(diffs / pd.Timedelta(days=1)) + delta_days = diffs / pd.Timedelta(days=1) + delta_days = _normalise_delta_days(delta_days) if delta_days.empty: return { "canonical": "UNKNOWN", @@ -397,7 +406,6 @@ def classify_frequency( "total_missing_periods": 0, "tolerance_periods": 0, } - median_days = float(delta_days.median()) if median_days <= 0: diff --git a/tests/test_market_data_validation_additional.py b/tests/test_market_data_validation_additional.py index 733ae1d0c1..79064f3c12 100644 --- a/tests/test_market_data_validation_additional.py +++ b/tests/test_market_data_validation_additional.py @@ -5,6 +5,7 @@ from datetime import datetime from types import SimpleNamespace +import numpy as np import pandas as pd import pytest @@ -138,6 +139,25 @@ def test_classify_frequency_detects_weekly() -> None: assert info["tolerance_periods"] == 1 +def test_classify_frequency_normalises_infinite_intervals(monkeypatch: pytest.MonkeyPatch) -> None: + index = pd.date_range("2024-01-05", periods=5, freq="7D") + + original_normalise = market_data._normalise_delta_days + + def inject_infinite_delta(delta_days: pd.Series) -> pd.Series: + augmented = pd.concat( + [delta_days, pd.Series([np.inf, -np.inf], dtype=delta_days.dtype)], + ignore_index=True, + ) + return original_normalise(augmented) + + monkeypatch.setattr(market_data, "_normalise_delta_days", inject_infinite_delta) + + info = market_data.classify_frequency(index) + + assert info["code"] == "W" + assert info["max_missing_periods"] == 0 + def test_normalize_delta_days_drops_infinite_values() -> None: delta_days = pd.Series([30.0, float("inf"), -float("inf"), 31.0]) @@ -182,6 +202,30 @@ def test_classify_frequency_irregular_preview_includes_ellipsis() -> None: assert "…" in message +def test_classify_frequency_irregular_diagnostics_survive_infinite_gaps( + monkeypatch: pytest.MonkeyPatch, +) -> None: + base = pd.date_range("2024-01-01", periods=8, freq="30D") + irregular = base.insert(4, base[3] + pd.Timedelta(days=2)) + + original_normalise = market_data._normalise_delta_days + + def inject_infinite_delta(delta_days: pd.Series) -> pd.Series: + augmented = pd.concat( + [delta_days, pd.Series([np.inf], dtype=delta_days.dtype)], + ignore_index=True, + ) + return original_normalise(augmented) + + monkeypatch.setattr(market_data, "_normalise_delta_days", inject_infinite_delta) + + with pytest.raises(market_data.MarketDataValidationError) as exc: + market_data.classify_frequency(irregular) + + message = str(exc.value) + assert "irregular sampling intervals" in message + + def test_classify_frequency_rejects_super_sparse_data() -> None: index = pd.DatetimeIndex( [ From d51bdc1bb0551709ba622001de7996058205665e Mon Sep 17 00:00:00 2001 From: "github-actions[bot]" Date: Sat, 29 Nov 2025 21:48:45 +0000 Subject: [PATCH 04/40] chore(autofix): formatting/lint --- tests/test_market_data_validation_additional.py | 7 +++++-- 1 file changed, 5 insertions(+), 2 deletions(-) diff --git a/tests/test_market_data_validation_additional.py b/tests/test_market_data_validation_additional.py index 79064f3c12..41363692fe 100644 --- a/tests/test_market_data_validation_additional.py +++ b/tests/test_market_data_validation_additional.py @@ -139,7 +139,9 @@ def test_classify_frequency_detects_weekly() -> None: assert info["tolerance_periods"] == 1 -def test_classify_frequency_normalises_infinite_intervals(monkeypatch: pytest.MonkeyPatch) -> None: +def test_classify_frequency_normalises_infinite_intervals( + monkeypatch: pytest.MonkeyPatch, +) -> None: index = pd.date_range("2024-01-05", periods=5, freq="7D") original_normalise = market_data._normalise_delta_days @@ -157,7 +159,8 @@ def inject_infinite_delta(delta_days: pd.Series) -> pd.Series: assert info["code"] == "W" assert info["max_missing_periods"] == 0 - + + def test_normalize_delta_days_drops_infinite_values() -> None: delta_days = pd.Series([30.0, float("inf"), -float("inf"), 31.0]) From 015011e2a1b5427a3ae5c21172cf098439188878 Mon Sep 17 00:00:00 2001 From: stranske Date: Sat, 29 Nov 2025 21:51:30 +0000 Subject: [PATCH 05/40] fix: replace missing reusable workflow with inline rate limit check The maint-coverage-guard.yml was referencing a non-existent reusable-rate-limit-check.yml workflow. Replace with inline rate limit gate job consistent with health-41-repo-health.yml and selftest-reusable-ci.yml patterns. --- .github/workflows/maint-coverage-guard.yml | 45 ++++++++++++++++++++-- 1 file changed, 41 insertions(+), 4 deletions(-) diff --git a/.github/workflows/maint-coverage-guard.yml b/.github/workflows/maint-coverage-guard.yml index 80841e3d58..81b3c00467 100644 --- a/.github/workflows/maint-coverage-guard.yml +++ b/.github/workflows/maint-coverage-guard.yml @@ -11,11 +11,48 @@ permissions: issues: write jobs: - # Call reusable rate limit check workflow + # Rate limit gate: skip non-critical coverage checks when API quota is low + # This ensures keepalive and core workflows get priority (threshold: 2000) rate-limit-check: - uses: ./.github/workflows/reusable-rate-limit-check.yml - with: - rate_limit_threshold: 2000 + name: Rate limit gate + runs-on: ubuntu-latest + outputs: + proceed: ${{ steps.check.outputs.proceed || 'true' }} + steps: + - name: Check API quota + id: check + uses: actions/github-script@v7 + env: + # Higher threshold than orchestrator (1000) so keepalive runs first + RATE_LIMIT_THRESHOLD: '2000' + with: + script: | + const threshold = parseInt(process.env.RATE_LIMIT_THRESHOLD || '2000', 10); + try { + const { data } = await github.rest.rateLimit.get(); + const remaining = data?.resources?.core?.remaining || 0; + const limit = data?.resources?.core?.limit || 5000; + const proceed = remaining >= threshold; + + core.setOutput('proceed', proceed ? 'true' : 'false'); + core.setOutput('remaining', String(remaining)); + + if (!proceed) { + const reset = data?.resources?.core?.reset || 0; + const resetTime = new Date(reset * 1000).toISOString(); + core.notice(`Deferring coverage guard: API quota low (${remaining}/${limit}). Resets at ${resetTime}`); + await core.summary + .addHeading('Coverage Guard Deferred', 3) + .addRaw(`API quota too low for non-critical health checks (${remaining}/${limit} remaining).`) + .addEOL() + .addRaw(`Threshold: ${threshold}. Resets at: ${resetTime}`) + .write(); + } + } catch (error) { + core.warning(`Rate limit check failed: ${error.message}. Proceeding anyway.`); + core.setOutput('proceed', 'true'); + } + guard: name: coverage baseline monitor needs: rate-limit-check From 193be1bc0892c86c6b33e421830742e5890bcc3a Mon Sep 17 00:00:00 2001 From: stranske Date: Sat, 29 Nov 2025 22:58:05 +0000 Subject: [PATCH 06/40] fix: keepalive dispatch payload overflow and add rate limit retry - Nest auxiliary dispatch properties (trace, round, comment_id, comment_url, idempotency_key) under a 'meta' object to stay within GitHub's 10-property limit for repository_dispatch client_payload - Add withRateLimitRetry() helper in keepalive_gate.js with exponential backoff (3 retries, 2s base delay) to recover from rate limit errors - Update dispatch handler to read from both nested meta and legacy flat properties for backward compatibility - Document findings in GapAssessment.md Fixes: property overflow and pr-fetch-failed rate limit errors --- .github/scripts/keepalive_gate.js | 74 ++++++++++++++++++- .github/scripts/keepalive_post_work.js | 37 +++++----- .github/workflows/agents-70-orchestrator.yml | 14 ++-- .../agents-keepalive-dispatch-handler.yml | 21 ++++-- .github/workflows/agents-pr-meta.yml | 24 ++++-- docs/keepalive/GapAssessment.md | 13 ++++ 6 files changed, 145 insertions(+), 38 deletions(-) diff --git a/.github/scripts/keepalive_gate.js b/.github/scripts/keepalive_gate.js index b2ce666521..6a8a08cc8b 100644 --- a/.github/scripts/keepalive_gate.js +++ b/.github/scripts/keepalive_gate.js @@ -15,6 +15,70 @@ const ORCHESTRATOR_WORKFLOW_FILE = 'agents-70-orchestrator.yml'; const WORKER_WORKFLOW_FILE = 'agents-72-codex-belt-worker.yml'; const RECENT_COMPLETED_LOOKBACK_SECONDS = 300; // 5 minutes +// Rate limit retry configuration +const RATE_LIMIT_MAX_RETRIES = 3; +const RATE_LIMIT_BASE_DELAY_MS = 2000; + +/** + * Sleep for a given number of milliseconds. + * @param {number} ms - Milliseconds to sleep + * @returns {Promise} + */ +function sleep(ms) { + return new Promise((resolve) => setTimeout(resolve, ms)); +} + +/** + * Check if an error is a GitHub rate limit error. + * @param {Error|unknown} error + * @returns {boolean} + */ +function isRateLimitError(error) { + if (!error) return false; + const message = error instanceof Error ? error.message : String(error); + const status = error?.status || error?.response?.status; + return ( + status === 403 || + status === 429 || + /rate\s*limit/i.test(message) || + /secondary\s*rate\s*limit/i.test(message) + ); +} + +/** + * Execute a GitHub API call with exponential backoff retry on rate limit errors. + * @template T + * @param {() => Promise} fn - The API call to execute + * @param {Object} [options] + * @param {number} [options.maxRetries=3] - Maximum retry attempts + * @param {number} [options.baseDelayMs=2000] - Base delay in milliseconds + * @param {Object} [options.core] - GitHub Actions core for logging + * @returns {Promise} + */ +async function withRateLimitRetry(fn, options = {}) { + const maxRetries = options.maxRetries ?? RATE_LIMIT_MAX_RETRIES; + const baseDelayMs = options.baseDelayMs ?? RATE_LIMIT_BASE_DELAY_MS; + const core = options.core; + + let lastError; + for (let attempt = 0; attempt <= maxRetries; attempt++) { + try { + return await fn(); + } catch (error) { + lastError = error; + if (!isRateLimitError(error) || attempt >= maxRetries) { + throw error; + } + const delay = baseDelayMs * Math.pow(2, attempt); + if (core?.info) { + core.info(`Rate limited, retrying in ${delay}ms (attempt ${attempt + 1}/${maxRetries})`); + } + await sleep(delay); + } + } + throw lastError; +} + function toInteger(value) { const parsed = Number.parseInt(value, 10); if (!Number.isFinite(parsed)) { @@ -723,7 +787,10 @@ async function evaluateRunCapForPr({ let pull; try { - const response = await github.rest.pulls.get({ owner, repo, pull_number: number }); + const response = await withRateLimitRetry( + () => github.rest.pulls.get({ owner, repo, pull_number: number }), + { core } + ); pull = response.data; } catch (error) { const message = error instanceof Error ? error.message : String(error); @@ -832,7 +899,10 @@ async function evaluateKeepaliveGate({ core, github, context, options = {} }) { let pr = pullRequest || null; if (!pr) { try { - const response = await github.rest.pulls.get({ owner, repo, pull_number: prNumber }); + const response = await withRateLimitRetry( + () => github.rest.pulls.get({ owner, repo, pull_number: prNumber }), + { core } + ); pr = response.data; } catch (error) { const message = error instanceof Error ? error.message : String(error); diff --git a/.github/scripts/keepalive_post_work.js b/.github/scripts/keepalive_post_work.js index 7d7b1a79df..dcba1941e7 100644 --- a/.github/scripts/keepalive_post_work.js +++ b/.github/scripts/keepalive_post_work.js @@ -340,31 +340,34 @@ async function dispatchCommand({ return false; } - const payload = { - issue: Number.isFinite(prNumber) ? Number(prNumber) : parseNumber(prNumber, 0, { min: 0 }), - action, - agent: agentAlias || 'codex', - base: baseRef || '', - head: headRef || '', - head_sha: headSha || '', + // GitHub repository_dispatch limits client_payload to 10 top-level properties. + // Nest auxiliary data under `meta` to stay within the limit while preserving + // backward compatibility by keeping core routing properties at the top level. + const meta = { trace: trace || '', + round: parseRoundNumber(round) || 0, }; - - const parsedRound = parseRoundNumber(round); - if (parsedRound > 0) { - payload.round = parsedRound; - } if (commentInfo?.id) { - payload.comment_id = Number(commentInfo.id); + meta.comment_id = Number(commentInfo.id); } if (commentInfo?.url) { - payload.comment_url = commentInfo.url; + meta.comment_url = commentInfo.url; } if (idempotencyKey) { - payload.idempotency_key = idempotencyKey; + meta.idempotency_key = idempotencyKey; } - payload.quiet = true; - payload.reply = 'none'; + + const payload = { + issue: Number.isFinite(prNumber) ? Number(prNumber) : parseNumber(prNumber, 0, { min: 0 }), + action, + agent: agentAlias || 'codex', + base: baseRef || '', + head: headRef || '', + head_sha: headSha || '', + meta, + quiet: true, + reply: 'none', + }; try { await github.rest.repos.createDispatchEvent({ diff --git a/.github/workflows/agents-70-orchestrator.yml b/.github/workflows/agents-70-orchestrator.yml index 2a617f40b5..6db5776a80 100644 --- a/.github/workflows/agents-70-orchestrator.yml +++ b/.github/workflows/agents-70-orchestrator.yml @@ -2830,17 +2830,21 @@ jobs: return; } + // GitHub repository_dispatch limits client_payload to 10 top-level properties. + // Nest auxiliary data under `meta` to stay within the limit. const payload = { issue: issueNumber || prNumber, base, head, agent: (process.env.AGENT_ALIAS || '').trim() || 'codex', - comment_id: commentId, - comment_url: process.env.COMMENT_URL || '', - round: process.env.ROUND || '', - trace: process.env.TRACE || '', - dispatch_mode: process.env.DISPATCH_MODE || '', instruction_body: instructionBody, + dispatch_mode: process.env.DISPATCH_MODE || '', + meta: { + comment_id: commentId, + comment_url: process.env.COMMENT_URL || '', + round: process.env.ROUND || '', + trace: process.env.TRACE || '', + }, quiet: true, reply: 'none', }; diff --git a/.github/workflows/agents-keepalive-dispatch-handler.yml b/.github/workflows/agents-keepalive-dispatch-handler.yml index d92eb3eb9c..99af495187 100644 --- a/.github/workflows/agents-keepalive-dispatch-handler.yml +++ b/.github/workflows/agents-keepalive-dispatch-handler.yml @@ -48,13 +48,21 @@ jobs: pull_number: prNumber, }); - const trace = payload.trace || payload.comment_trace || ''; - const round = payload.round || payload.comment_round || ''; + // Support both legacy flat payload and new nested `meta` structure. + // New dispatches nest comment info under `meta` to stay within GitHub's + // 10-property limit for repository_dispatch client_payload. + const meta = payload.meta || {}; + const trace = meta.trace || payload.trace || payload.comment_trace || ''; + const round = meta.round || payload.round || payload.comment_round || ''; + const commentId = meta.comment_id || payload.comment_id || ''; + const commentUrl = meta.comment_url || payload.comment_url || ''; + const idempotencyKey = meta.idempotency_key || payload.idempotency_key || ''; + const headSha = pr?.head?.sha || ''; const env = { ...process.env, TRACE: trace, - ROUND: round, + ROUND: String(round), PR_NUMBER: String(prNumber), ISSUE_NUMBER: String(prNumber), BASE_BRANCH: pr?.base?.ref || '', @@ -64,10 +72,11 @@ jobs: PREVIOUS_HEAD: headSha, PR_HEAD_SHA_PREV: headSha, HEAD_SHA_PREV: headSha, - COMMENT_ID: payload.comment_id || '', - COMMENT_URL: payload.comment_url || '', + COMMENT_ID: String(commentId), + COMMENT_URL: commentUrl, COMMENT_TRACE: trace, - COMMENT_ROUND: round, + COMMENT_ROUND: String(round), + IDEMPOTENCY_KEY: idempotencyKey, AGENT_ALIAS: payload.agent || 'codex', DISPATCH_EVENT_TYPE: process.env.DISPATCH_EVENT_TYPE, SYNC_LABEL: process.env.SYNC_LABEL, diff --git a/.github/workflows/agents-pr-meta.yml b/.github/workflows/agents-pr-meta.yml index 2605b33948..0e9e134823 100644 --- a/.github/workflows/agents-pr-meta.yml +++ b/.github/workflows/agents-pr-meta.yml @@ -634,16 +634,20 @@ jobs: return; } + // GitHub repository_dispatch limits client_payload to 10 top-level properties. + // Nest auxiliary data under `meta` to stay within the limit. const clientPayload = { issue: prNumber, base: resolvedBase, head: resolvedHead, agent: agentAlias, - comment_id: commentId, - comment_url: commentUrl, - round, - trace, instruction_body: instructionBody, + meta: { + comment_id: commentId, + comment_url: commentUrl, + round, + trace, + }, quiet: true, reply: 'none', }; @@ -1687,16 +1691,20 @@ jobs: return; } + // GitHub repository_dispatch limits client_payload to 10 top-level properties. + // Nest auxiliary data under `meta` to stay within the limit. const clientPayload = { issue: prNumber, base: resolvedBase, head: resolvedHead, agent: agentAlias, - comment_id: commentId, - comment_url: commentUrl, - round, - trace, instruction_body: instructionBody, + meta: { + comment_id: commentId, + comment_url: commentUrl, + round, + trace, + }, quiet: true, reply: 'none', }; diff --git a/docs/keepalive/GapAssessment.md b/docs/keepalive/GapAssessment.md index 387370eaf1..6dcb7766c4 100644 --- a/docs/keepalive/GapAssessment.md +++ b/docs/keepalive/GapAssessment.md @@ -22,3 +22,16 @@ - **Enforce the orchestrator-only run cap** - Change the run-cap evaluation calls for keepalive dispatch to set `includeWorker: false`, or flip the default so workers are ignored unless explicitly requested. - Update the summary line to report orchestrator-only counts, matching the contract’s `cap=/` definition, and extend tests to prove worker runs no longer consume cap budget. + +3. **Repository dispatch payload property limit (RESOLVED 2025-11)** + - GitHub limits `repository_dispatch` `client_payload` to **10 top-level properties**. + - Prior implementation sent up to 14 properties, causing `Invalid request. No more than 10 properties are allowed; N were supplied` errors. + - **Fix:** Nested auxiliary data (`comment_id`, `comment_url`, `round`, `trace`, `idempotency_key`) under a single `meta` object. + - Affected files: `keepalive_post_work.js`, `agents-pr-meta.yml`, `agents-70-orchestrator.yml`, `agents-keepalive-dispatch-handler.yml`. + - Handler updated to support both legacy flat payloads and new nested structure for backward compatibility. + +4. **Rate limit resilience (RESOLVED 2025-11)** + - The contract did not specify retry behavior when GitHub API rate limits are hit. + - Prior implementation failed immediately on rate limit, causing `pr-fetch-failed` without recovery. + - **Fix:** Added `withRateLimitRetry()` helper with exponential backoff (3 retries, 2s base delay). + - Applied to PR fetch calls in `keepalive_gate.js` (`evaluateRunCapForPr`, `evaluateKeepaliveGate`). From 885251d61190e6b329c3cec58f3f487827fe502e Mon Sep 17 00:00:00 2001 From: stranske Date: Sat, 29 Nov 2025 23:13:35 +0000 Subject: [PATCH 07/40] fix: make script logging optional for CI environments Scripts used by autofix workflow now catch ImportError when trend_analysis package is not installed, allowing them to run in CI environments without requiring full package installation. --- scripts/build_autofix_pr_comment.py | 7 +++++-- scripts/generate_residual_trend.py | 7 +++++-- 2 files changed, 10 insertions(+), 4 deletions(-) diff --git a/scripts/build_autofix_pr_comment.py b/scripts/build_autofix_pr_comment.py index cccb4f993b..6cb3394eca 100644 --- a/scripts/build_autofix_pr_comment.py +++ b/scripts/build_autofix_pr_comment.py @@ -345,7 +345,10 @@ def main(argv: Sequence[str] | None = None) -> int: if __name__ == "__main__": # pragma: no cover - CLI entry point - from trend_analysis.script_logging import setup_script_logging + try: + from trend_analysis.script_logging import setup_script_logging - setup_script_logging(module_file=__file__) + setup_script_logging(module_file=__file__) + except ImportError: + pass # Package not installed in CI environment sys.exit(main()) diff --git a/scripts/generate_residual_trend.py b/scripts/generate_residual_trend.py index c88301197f..f851c91722 100644 --- a/scripts/generate_residual_trend.py +++ b/scripts/generate_residual_trend.py @@ -98,7 +98,10 @@ def main() -> int: if __name__ == "__main__": - from trend_analysis.script_logging import setup_script_logging + try: + from trend_analysis.script_logging import setup_script_logging - setup_script_logging(module_file=__file__) + setup_script_logging(module_file=__file__) + except ImportError: + pass # Package not installed in CI environment raise SystemExit(main()) From 3ba4d9670202b744ba65d4a5f3c17ab6eb253a56 Mon Sep 17 00:00:00 2001 From: stranske Date: Sat, 29 Nov 2025 17:15:11 -0600 Subject: [PATCH 08/40] Fix infinite cadence test and format bootstrap file (#3890) --- agents/codex-3879.md | 1 + tests/test_market_data_validation_additional.py | 4 ++-- 2 files changed, 3 insertions(+), 2 deletions(-) diff --git a/agents/codex-3879.md b/agents/codex-3879.md index f5feecc01e..6daeab9a60 100644 --- a/agents/codex-3879.md +++ b/agents/codex-3879.md @@ -1,2 +1,3 @@ + diff --git a/tests/test_market_data_validation_additional.py b/tests/test_market_data_validation_additional.py index 41363692fe..96348944ac 100644 --- a/tests/test_market_data_validation_additional.py +++ b/tests/test_market_data_validation_additional.py @@ -174,7 +174,7 @@ def test_classify_frequency_ignores_infinite_offsets( ) -> None: index = pd.date_range("2024-01-31", periods=5, freq="ME") - original = market_data._normalize_delta_days + original = market_data._normalise_delta_days def inject_and_clean(delta_days: pd.Series) -> pd.Series: polluted = delta_days.astype(float) @@ -182,7 +182,7 @@ def inject_and_clean(delta_days: pd.Series) -> pd.Series: polluted.iloc[-1] = -float("inf") return original(polluted) - monkeypatch.setattr(market_data, "_normalize_delta_days", inject_and_clean) + monkeypatch.setattr(market_data, "_normalise_delta_days", inject_and_clean) info = market_data.classify_frequency(index) From 22e5427d97329d8ea4973882b3eadddde8ee0fd6 Mon Sep 17 00:00:00 2001 From: stranske Date: Sat, 29 Nov 2025 17:15:47 -0600 Subject: [PATCH 09/40] Handle infinite cadence intervals without deprecated pandas options (#3891) --- src/trend_analysis/io/market_data.py | 6 +----- 1 file changed, 1 insertion(+), 5 deletions(-) diff --git a/src/trend_analysis/io/market_data.py b/src/trend_analysis/io/market_data.py index 41dc0dabda..f185eb54eb 100644 --- a/src/trend_analysis/io/market_data.py +++ b/src/trend_analysis/io/market_data.py @@ -47,11 +47,7 @@ def _normalise_delta_days(delta_days: pd.Series) -> pd.Series: - if delta_days.empty: - return delta_days - - cleaned = delta_days.replace([np.inf, -np.inf], np.nan) - return cleaned.dropna() + return _normalize_delta_days(delta_days) _DEFAULT_MISSING_POLICY = "drop" From f0755a0a5c036b8d58f4449023075b696b9fdd16 Mon Sep 17 00:00:00 2001 From: stranske Date: Sat, 29 Nov 2025 23:28:31 +0000 Subject: [PATCH 10/40] fix(health): remove redundant 'const core' declarations The github-script action already provides 'core' in scope, so manually requiring @actions/core causes 'Identifier already declared' error. This pre-existing bug has been causing health workflow failures since Nov 10. --- .github/workflows/health-41-repo-health.yml | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/.github/workflows/health-41-repo-health.yml b/.github/workflows/health-41-repo-health.yml index 9cb26d94b7..9a0d147799 100644 --- a/.github/workflows/health-41-repo-health.yml +++ b/.github/workflows/health-41-repo-health.yml @@ -67,7 +67,7 @@ jobs: uses: actions/github-script@v7 with: script: | - const core = require('@actions/core'); + // Note: 'core' is already provided by github-script, no require needed const staleBranchDays = parseInt(process.env.STALE_BRANCH_DAYS || '30', 10); const stalePrDays = parseInt(process.env.STALE_PR_DAYS || '30', 10); @@ -279,7 +279,7 @@ jobs: DEFAULT_BRANCH: ${{ steps.summarise.outputs.default-branch }} with: script: | - const core = require('@actions/core'); + // Note: 'core' is already provided by github-script, no require needed const defaultBranch = process.env.DEFAULT_BRANCH || null; if (!defaultBranch) { From c24cb646f13d9fa5403bb5b986d95b3e6c9a6c45 Mon Sep 17 00:00:00 2001 From: stranske Date: Sat, 29 Nov 2025 23:33:17 +0000 Subject: [PATCH 11/40] fix: preserve checklist progress when updating PR status summary The agents-pr-meta workflow was regenerating the Automated Status Summary entirely from the source issue, causing checked checkboxes to revert to unchecked state and losing records of completed work. Added helpers to: - extractBlock(): Extract existing status block from PR body - parseCheckboxStates(): Parse which items are checked - mergeCheckboxStates(): Merge checked states into new content Now the buildStatusBlock() function preserves any checked items from the existing PR body before regenerating the status summary. Documented in GapAssessment.md as finding #5 (RESOLVED). --- .github/workflows/agents-pr-meta.yml | 69 ++++++++++++++++++++++++++-- docs/keepalive/GapAssessment.md | 8 ++++ 2 files changed, 73 insertions(+), 4 deletions(-) diff --git a/.github/workflows/agents-pr-meta.yml b/.github/workflows/agents-pr-meta.yml index 0e9e134823..3cf48ce3c5 100644 --- a/.github/workflows/agents-pr-meta.yml +++ b/.github/workflows/agents-pr-meta.yml @@ -1981,6 +1981,56 @@ jobs: .join('\n'); } + // Extract an existing block from PR body by marker + function extractBlock(body, marker) { + const start = ``; + const end = ``; + const startIndex = (body || '').indexOf(start); + const endIndex = (body || '').indexOf(end); + if (startIndex === -1 || endIndex === -1 || endIndex <= startIndex) { + return ''; + } + return body.slice(startIndex + start.length, endIndex).trim(); + } + + // Parse checkbox states from a block, returning a Map of normalized text -> checked state + function parseCheckboxStates(block) { + const states = new Map(); + const lines = String(block || '').split(/\r?\n/); + for (const line of lines) { + const match = line.match(/^- \[(x| )\]\s*(.+)$/i); + if (match) { + const checked = match[1].toLowerCase() === 'x'; + const text = match[2].trim(); + // Normalize: remove leading "- " if present and trim + const normalized = text.replace(/^-\s*/, '').trim().toLowerCase(); + if (normalized && checked) { + states.set(normalized, true); + } + } + } + return states; + } + + // Merge checked states into new checklist content + function mergeCheckboxStates(newContent, existingStates) { + if (!existingStates || existingStates.size === 0) { + return newContent; + } + const lines = String(newContent || '').split(/\r?\n/); + return lines.map((line) => { + const match = line.match(/^- \[( )\]\s*(.+)$/); + if (match) { + const text = match[2].trim(); + const normalized = text.replace(/^-\s*/, '').trim().toLowerCase(); + if (existingStates.has(normalized)) { + return `- [x] ${text}`; + } + } + return line; + }).join('\n'); + } + async function withRetries(fn, options = {}) { const attempts = Number(options.attempts) || 3; const baseDelay = Number(options.delayMs) || 1000; @@ -2233,6 +2283,7 @@ jobs: headSha: prInfo.headSha, workflowRuns, requiredChecks, + existingBody: pr.body, }); const bodyWithPreamble = upsertBlock(pr.body || '', 'pr-preamble', preamble); @@ -2337,21 +2388,31 @@ jobs: return latest; } - function buildStatusBlock({scope, tasks, acceptance, headSha, workflowRuns, requiredChecks}) { + function buildStatusBlock({scope, tasks, acceptance, headSha, workflowRuns, requiredChecks, existingBody}) { const statusLines = ['', '## Automated Status Summary']; + // Extract existing checkbox states from current PR body to preserve progress + const existingBlock = extractBlock(existingBody || '', 'auto-status-summary'); + const existingStates = parseCheckboxStates(existingBlock); + if (existingStates.size > 0) { + core.info(`Preserving ${existingStates.size} checked item(s) from existing status summary`); + } + statusLines.push('#### Scope'); - const scopeFormatted = scope ? ensureChecklist(scope) : fallbackChecklist('Scope section missing from source issue.'); + let scopeFormatted = scope ? ensureChecklist(scope) : fallbackChecklist('Scope section missing from source issue.'); + scopeFormatted = mergeCheckboxStates(scopeFormatted, existingStates); statusLines.push(scopeFormatted); statusLines.push(''); statusLines.push('#### Tasks'); - const tasksFormatted = tasks ? ensureChecklist(tasks) : fallbackChecklist('Tasks section missing from source issue.'); + let tasksFormatted = tasks ? ensureChecklist(tasks) : fallbackChecklist('Tasks section missing from source issue.'); + tasksFormatted = mergeCheckboxStates(tasksFormatted, existingStates); statusLines.push(tasksFormatted); statusLines.push(''); statusLines.push('#### Acceptance criteria'); - const acceptanceFormatted = acceptance ? ensureChecklist(acceptance) : fallbackChecklist('Acceptance criteria section missing from source issue.'); + let acceptanceFormatted = acceptance ? ensureChecklist(acceptance) : fallbackChecklist('Acceptance criteria section missing from source issue.'); + acceptanceFormatted = mergeCheckboxStates(acceptanceFormatted, existingStates); statusLines.push(acceptanceFormatted); statusLines.push(''); diff --git a/docs/keepalive/GapAssessment.md b/docs/keepalive/GapAssessment.md index 6dcb7766c4..2f93d6f9aa 100644 --- a/docs/keepalive/GapAssessment.md +++ b/docs/keepalive/GapAssessment.md @@ -35,3 +35,11 @@ - Prior implementation failed immediately on rate limit, causing `pr-fetch-failed` without recovery. - **Fix:** Added `withRateLimitRetry()` helper with exponential backoff (3 retries, 2s base delay). - Applied to PR fetch calls in `keepalive_gate.js` (`evaluateRunCapForPr`, `evaluateKeepaliveGate`). + +5. **Checklist progress not preserved across status updates (RESOLVED 2025-11)** + - The `agents-pr-meta` workflow was regenerating the Automated Status Summary entirely from the source issue on every update. + - This caused checked checkboxes (recording completed work) to revert to unchecked state. + - **Root cause:** `buildStatusBlock()` pulled scope/tasks/acceptance directly from source issue without reading existing PR body state. + - **Fix:** Added `extractBlock()`, `parseCheckboxStates()`, and `mergeCheckboxStates()` helpers. + - Before generating the status block, the workflow now extracts existing checkbox states from the PR body and merges them into the new content. + - Affected file: `agents-pr-meta.yml` (Upsert PR body sections job). From 6874326214cf5510604468e39c874a7beabe7b6e Mon Sep 17 00:00:00 2001 From: stranske Date: Sat, 29 Nov 2025 23:38:19 +0000 Subject: [PATCH 12/40] feat(workflows): add rate limit resilience improvements - Add rate limit retry with backoff to Resolve Context job in autofix.yml Uses paginateWithBackoff from api-helpers.js for PR file listing - Enhance orchestrator rate limit summary with installation token note Helps debug rate limit failures from GITHUB_TOKEN vs PAT Addresses WorkflowSystemBugReport.md recommendations for rate limit handling. --- .github/workflows/agents-70-orchestrator.yml | 9 +++++++ .github/workflows/autofix.yml | 25 ++++++++++++++------ 2 files changed, 27 insertions(+), 7 deletions(-) diff --git a/.github/workflows/agents-70-orchestrator.yml b/.github/workflows/agents-70-orchestrator.yml index 6db5776a80..d1e4fd3326 100644 --- a/.github/workflows/agents-70-orchestrator.yml +++ b/.github/workflows/agents-70-orchestrator.yml @@ -78,6 +78,7 @@ jobs: ); const threshold = parseInt(process.env.RATE_LIMIT_THRESHOLD || '500', 10); + // Check PAT rate limit (used for authenticated operations) const status = await checkRateLimitStatus(github, { threshold, core }); core.setOutput('safe', status.safe ? 'true' : 'false'); @@ -88,6 +89,8 @@ jobs: const summary = core.summary; summary.addHeading('Rate Limit Status', 3); + // Display PAT rate limit + summary.addHeading('Personal Access Token (PAT)', 4); if (status.error) { summary.addRaw(`⚠️ Could not check rate limit: ${status.error}`).addEOL(); summary.addRaw('Proceeding with orchestrator run.').addEOL(); @@ -102,6 +105,12 @@ jobs: } } + // Note: Installation token (GITHUB_TOKEN) has separate rate limits + // shown in workflow logs but not directly queryable via this token + summary.addHeading('Note', 4); + summary.addRaw('Installation token (GITHUB_TOKEN) has separate rate limits. ').addEOL(); + summary.addRaw('Check workflow run headers for `x-ratelimit-*` if other jobs fail with rate limit errors.').addEOL(); + await summary.write(); if (!status.safe) { diff --git a/.github/workflows/autofix.yml b/.github/workflows/autofix.yml index 8929202d36..eb63f890c5 100644 --- a/.github/workflows/autofix.yml +++ b/.github/workflows/autofix.yml @@ -35,11 +35,22 @@ jobs: same_repo: ${{ steps.context.outputs.same_repo }} caller_actor: ${{ steps.context.outputs.caller_actor }} steps: + - name: Checkout for API helpers + uses: actions/checkout@v4 + with: + sparse-checkout: .github/scripts + sparse-checkout-cone-mode: false + - name: Resolve PR context id: context uses: actions/github-script@v7 with: script: | + const path = require('path'); + const { paginateWithBackoff } = require( + path.join(process.env.GITHUB_WORKSPACE, '.github/scripts/api-helpers.js') + ); + const pr = context.payload.pull_request; if (!pr) { core.setOutput('should_run', 'false'); @@ -87,14 +98,14 @@ jobs: return; } - // File check + // File check with rate limit retry const { owner, repo } = context.repo; - const files = await github.paginate(github.rest.pulls.listFiles, { - owner, - repo, - pull_number: pr.number, - per_page: 100, - }); + const files = await paginateWithBackoff( + github, + github.rest.pulls.listFiles, + { owner, repo, pull_number: pr.number, per_page: 100 }, + { maxRetries: 3, core } + ); const hasPython = files.some(f => f.filename.endsWith('.py') || f.filename.endsWith('.pyi')); if (!hasPython) { From 62e0644e91498c0452bb3fb6ffa2cabe9236f0e3 Mon Sep 17 00:00:00 2001 From: stranske Date: Sun, 30 Nov 2025 02:41:54 +0000 Subject: [PATCH 13/40] refactor: consolidate root folder and add directory index Root folder cleanup: - Move test_multi_period_selection.py, test_upload_app.py to tests/ - Move CSV data files to data/ folder (Trend Universe Data.csv, Trend Universe Membership.csv, hedge_fund_returns_with_indexes.csv) - Remove ROBUSTNESS_GUIDE.md stub (pointed to archives) - Consolidate AGENTS_APP.md into Agents.md Path updates: - Update config files to reference data/ paths - Update analysis/results.py default paths - Update README.md and README_DATA.md documentation New directory index (docs/directory-index/): - ROOT.md: Complete root-level file reference - src.md, config.md, data.md, scripts.md, tests.md, docs.md - Attractive formatting with purpose tables and quick links Retains Issues.txt at root for keepalive workflow usage. --- AGENTS_APP.md | 6 -- Agents.md | 7 ++ README.md | 17 ++-- README_DATA.md | 4 +- ROBUSTNESS_GUIDE.md | 3 - analysis/results.py | 4 +- config/long_backtest.yml | 2 +- config/universe/core.yml | 4 +- config/universe/core_plus_benchmarks.yml | 4 +- config/universe/managed_futures_min.yml | 4 +- data/README.md | 8 +- .../Trend Universe Data.csv | 0 .../Trend Universe Membership.csv | 0 .../hedge_fund_returns_with_indexes.csv | 0 docs/directory-index/README.md | 0 docs/directory-index/ROOT.md | 99 +++++++++++++++++++ docs/directory-index/config.md | 48 +++++++++ docs/directory-index/data.md | 55 +++++++++++ docs/directory-index/docs.md | 43 ++++++++ docs/directory-index/scripts.md | 86 ++++++++++++++++ docs/directory-index/src.md | 48 +++++++++ docs/directory-index/tests.md | 88 +++++++++++++++++ .../test_multi_period_selection.py | 0 .../test_upload_app.py | 0 24 files changed, 496 insertions(+), 34 deletions(-) delete mode 100644 AGENTS_APP.md delete mode 100644 ROBUSTNESS_GUIDE.md rename Trend Universe Data.csv => data/Trend Universe Data.csv (100%) rename Trend Universe Membership.csv => data/Trend Universe Membership.csv (100%) rename hedge_fund_returns_with_indexes.csv => data/hedge_fund_returns_with_indexes.csv (100%) create mode 100644 docs/directory-index/README.md create mode 100644 docs/directory-index/ROOT.md create mode 100644 docs/directory-index/config.md create mode 100644 docs/directory-index/data.md create mode 100644 docs/directory-index/docs.md create mode 100644 docs/directory-index/scripts.md create mode 100644 docs/directory-index/src.md create mode 100644 docs/directory-index/tests.md rename test_multi_period_selection.py => tests/test_multi_period_selection.py (100%) rename test_upload_app.py => tests/test_upload_app.py (100%) diff --git a/AGENTS_APP.md b/AGENTS_APP.md deleted file mode 100644 index 5fd7f37569..0000000000 --- a/AGENTS_APP.md +++ /dev/null @@ -1,6 +0,0 @@ -# Codex Work Instructions (App + Sim Layer) -- Prefer calling `trend_analysis.pipeline.single_period_run` when available. -- Expand tests first; each PR solves one issue. -- How to run: `./scripts/run_streamlit.sh`, `pytest -q`. -- Acceptance criteria: schema validator, policy engine behavior, simulator smoke test, pipeline integration parity within tolerance. -- Backlog: preview score frame, weight heatmap, integrate native rank_selection after upstream merge, add expected shortfall & diversification value, export commit hash. diff --git a/Agents.md b/Agents.md index da5123db1b..d501b196e9 100644 --- a/Agents.md +++ b/Agents.md @@ -3,6 +3,13 @@ YOU ARE CODEX. EXTEND THE VOL_ADJ_TREND_ANALYSIS PROJECT AS FOLLOWS -------------------------------------------------------------------- +## App + Sim Layer Instructions +- Prefer calling `trend_analysis.pipeline.single_period_run` when available. +- Expand tests first; each PR solves one issue. +- How to run: `./scripts/run_streamlit.sh`, `pytest -q`. +- Acceptance criteria: schema validator, policy engine behavior, simulator smoke test, pipeline integration parity within tolerance. +- Backlog: preview score frame, weight heatmap, integrate native rank_selection after upstream merge, add expected shortfall & diversification value, export commit hash. + ## Agents consumer workflows (historical) Manual consumer wrappers were fully retired once the orchestrator became the diff --git a/README.md b/README.md index 6fe61ba887..2615a7b577 100644 --- a/README.md +++ b/README.md @@ -61,7 +61,7 @@ runtime by adding the `--universe` flag to `trend-model run`: ```bash trend-model run \ --config config/trend_universe_2004.yml \ - --input "Trend Universe Data.csv" \ + --input "data/Trend Universe Data.csv" \ --universe core ``` @@ -130,16 +130,13 @@ if __name__ == "__main__": | `CONTRIBUTING.md` | Reference doc | Contribution workflow and review expectations. | | `DEPENDENCY_QUICKSTART.md` | Reference doc | Dependency setup cheat sheet kept beside the main README. | | `DOCKER_QUICKSTART.md` | Reference doc | Docker usage guide co-located with `docker-compose.yml` and the root Dockerfile. | -| `ROBUSTNESS_GUIDE.md` | Reference doc | Legacy robustness pointer retained until a refreshed guide lands. | | `SECURITY.md` | Reference doc | Security policy and disclosure expectations. | -| `Trend Universe Data.csv` | Data sample | Primary demo return matrix; universe configs reference the root path directly. | -| `Trend Universe Membership.csv` | Data sample | Membership ledger paired with the return matrix; loaders expect the root location. | -| `hedge_fund_returns_with_indexes.csv` | Data sample | Benchmark demo input consumed by example configs and docs. | -| `test_multi_period_selection.py` | Active script | Standalone regression harness kept at root for quick manual selection checks. | -| `test_upload_app.py` | Active script | Upload-app smoke harness invoked directly outside the pytest tree. | -| `coverage-summary.md` | Historical | Symlink to `archives/generated/2025/2025-11-22_coverage-summary.md` (CI snapshot). | -| `gate-summary.md` | Historical | Symlink to `archives/generated/2025/2025-11-22_gate-summary.md` (CI gate snapshot). | -| `keepalive_status.md` | Historical | Symlink to `archives/generated/2025/2025-11-22_keepalive_status.md` (keepalive snapshot). | +| `data/Trend Universe Data.csv` | Data sample | Primary demo return matrix; universe configs reference `data/` path. | +| `data/Trend Universe Membership.csv` | Data sample | Membership ledger paired with the return matrix in `data/`. | +| `data/hedge_fund_returns_with_indexes.csv` | Data sample | Benchmark demo input consumed by example configs and docs. | +| `coverage-summary.md` | CI-generated | Coverage trend snapshot updated by CI workflows. | +| `gate-summary.md` | CI-generated | Gate status snapshot for PR checks. | +| `keepalive_status.md` | Index | Keepalive status index pointing to `docs/keepalive/status/`. | See `archives/ROOT_FILE_INDEX.md` for the dated archive index covering additional root-level artefacts moved out of the entrypoint. diff --git a/README_DATA.md b/README_DATA.md index 09e7859a58..f3d3e3df34 100644 --- a/README_DATA.md +++ b/README_DATA.md @@ -1,6 +1,6 @@ # Demo dataset provenance -This repository bundles a few small CSV files (for example `hedge_fund_returns_with_indexes.csv`, `Trend Universe Data.csv`, and other samples under `demo/`). They exist solely to support tests, docs, and interactive demos. +This repository bundles a few small CSV files in the `data/` folder (for example `data/hedge_fund_returns_with_indexes.csv`, `data/Trend Universe Data.csv`, and other samples under `demo/`). They exist solely to support tests, docs, and interactive demos. - **Provenance:** All bundled data is synthetic or derived from public benchmark series. No confidential client information or proprietary hedge fund records are present. - **Intended use:** The files allow contributors to exercise the Trend Model demos, verify export pipelines, and run automated tests without reaching out to live data providers. @@ -42,7 +42,7 @@ not meant to inform live investment decisions. ## Risk-free columns in sample data -- The long backtest sample (`hedge_fund_returns_with_indexes.csv`) includes a +- The long backtest sample (`data/hedge_fund_returns_with_indexes.csv`) includes a **"Risk-Free Rate"** column. Configs such as `config/long_backtest.yml` specify `data.risk_free_column: "Risk-Free Rate"` and set `allow_risk_free_fallback: false` to ensure the cash proxy is used and diff --git a/ROBUSTNESS_GUIDE.md b/ROBUSTNESS_GUIDE.md deleted file mode 100644 index 1d9ca21412..0000000000 --- a/ROBUSTNESS_GUIDE.md +++ /dev/null @@ -1,3 +0,0 @@ -# Robustness guide (archived) - -This robustness how-to has moved to `archives/docs/ROBUSTNESS_GUIDE.md`. See `docs/INDEX.md` for the current testing and workflow guides and for links to the archived copy when you need historical context. diff --git a/analysis/results.py b/analysis/results.py index 8b3117da54..cf9767f4de 100644 --- a/analysis/results.py +++ b/analysis/results.py @@ -14,8 +14,8 @@ __all__ = ["Results", "build_metadata", "compute_universe_fingerprint"] _ROOT = Path(__file__).resolve().parents[1] -_DEFAULT_DATA_PATH = _ROOT / "Trend Universe Data.csv" -_DEFAULT_MEMBERSHIP_PATH = _ROOT / "Trend Universe Membership.csv" +_DEFAULT_DATA_PATH = _ROOT / "data" / "Trend Universe Data.csv" +_DEFAULT_MEMBERSHIP_PATH = _ROOT / "data" / "Trend Universe Membership.csv" def _coerce_series(obj: Any) -> pd.Series: diff --git a/config/long_backtest.yml b/config/long_backtest.yml index 2104eaffaf..bdf8e5ddb2 100644 --- a/config/long_backtest.yml +++ b/config/long_backtest.yml @@ -2,7 +2,7 @@ version: "1" data: - csv_path: hedge_fund_returns_with_indexes.csv + csv_path: data/hedge_fund_returns_with_indexes.csv date_column: Date frequency: ME # monthly data (month-end) risk_free_column: "Risk-Free Rate" diff --git a/config/universe/core.yml b/config/universe/core.yml index 74533096a0..5470f8e661 100644 --- a/config/universe/core.yml +++ b/config/universe/core.yml @@ -2,8 +2,8 @@ version: 1 key: core name: Core trend cohort description: Concentrated set of diversified trend managers with long live track records. -data_csv: Trend Universe Data.csv -membership_csv: Trend Universe Membership.csv +data_csv: data/Trend Universe Data.csv +membership_csv: data/Trend Universe Membership.csv date_column: Date members: - AHL Dimension diff --git a/config/universe/core_plus_benchmarks.yml b/config/universe/core_plus_benchmarks.yml index 50cf39f168..f776af291d 100644 --- a/config/universe/core_plus_benchmarks.yml +++ b/config/universe/core_plus_benchmarks.yml @@ -2,8 +2,8 @@ version: 1 key: core_plus_benchmarks name: Core + benchmark overlays description: Core trend managers plus representative benchmark series for comparison. -data_csv: Trend Universe Data.csv -membership_csv: Trend Universe Membership.csv +data_csv: data/Trend Universe Data.csv +membership_csv: data/Trend Universe Membership.csv date_column: Date members: - AHL Dimension diff --git a/config/universe/managed_futures_min.yml b/config/universe/managed_futures_min.yml index 664842bf47..947dbe47e1 100644 --- a/config/universe/managed_futures_min.yml +++ b/config/universe/managed_futures_min.yml @@ -2,8 +2,8 @@ version: 1 key: managed_futures_min name: Managed futures mini description: Small comparison set for quick smoke tests and doc examples. -data_csv: Trend Universe Data.csv -membership_csv: Trend Universe Membership.csv +data_csv: data/Trend Universe Data.csv +membership_csv: data/Trend Universe Membership.csv date_column: Date members: - Crabel Advanced Trend Program diff --git a/data/README.md b/data/README.md index c0cd90d484..3089a3bcfe 100644 --- a/data/README.md +++ b/data/README.md @@ -1,12 +1,12 @@ # Reference datasets -Only active reference inputs remain in the root or `data/` directories. Demo outputs and ad-hoc analyses are archived under `archives/data_snapshots/`. +All active reference datasets are now consolidated in this `data/` directory. Demo outputs and ad-hoc analyses are archived under `archives/data_snapshots/`. | Dataset | Location | Size | Schema | Owner | Purpose | | --- | --- | --- | --- | --- | --- | -| Trend Universe total returns | `Trend Universe Data.csv` | 136 KB | [Schema](#trend-universe-data) | Demo data maintainers (Research Ops) | Primary monthly total return matrix for Trend universe configs and tests. | -| Trend Universe membership ledger | `Trend Universe Membership.csv` | 4 KB | [Schema](#trend-universe-membership) | Demo data maintainers (Research Ops) | Effective-date windows for each Trend universe column used by loaders and configs. See `docs/data/Trend_Universe_Data.md` for stewardship notes. | -| Hedge fund returns with benchmarks | `hedge_fund_returns_with_indexes.csv` | 140 KB | [Schema](#hedge-fund-returns-with-indexes) | Demo data maintainers (Research Ops) | Input for long backtest and rolling-hold configs plus legacy demo notebooks. | +| Trend Universe total returns | `data/Trend Universe Data.csv` | 136 KB | [Schema](#trend-universe-data) | Demo data maintainers (Research Ops) | Primary monthly total return matrix for Trend universe configs and tests. | +| Trend Universe membership ledger | `data/Trend Universe Membership.csv` | 4 KB | [Schema](#trend-universe-membership) | Demo data maintainers (Research Ops) | Effective-date windows for each Trend universe column used by loaders and configs. See `docs/data/Trend_Universe_Data.md` for stewardship notes. | +| Hedge fund returns with benchmarks | `data/hedge_fund_returns_with_indexes.csv` | 140 KB | [Schema](#hedge-fund-returns-with-indexes) | Demo data maintainers (Research Ops) | Input for long backtest and rolling-hold configs plus legacy demo notebooks. | | Sample manager returns | `data/raw/managers/sample_manager.csv` | 4 KB | [Schema](#sample-manager-returns) | Demo data maintainers (Research Ops) | Minimal fixture used by CLI preset tests. | | Sample benchmark index | `data/raw/indices/sample_index.csv` | 4 KB | [Schema](#sample-benchmark-index) | Demo data maintainers (Research Ops) | Lightweight index series kept for parity with sample manager inputs. | diff --git a/Trend Universe Data.csv b/data/Trend Universe Data.csv similarity index 100% rename from Trend Universe Data.csv rename to data/Trend Universe Data.csv diff --git a/Trend Universe Membership.csv b/data/Trend Universe Membership.csv similarity index 100% rename from Trend Universe Membership.csv rename to data/Trend Universe Membership.csv diff --git a/hedge_fund_returns_with_indexes.csv b/data/hedge_fund_returns_with_indexes.csv similarity index 100% rename from hedge_fund_returns_with_indexes.csv rename to data/hedge_fund_returns_with_indexes.csv diff --git a/docs/directory-index/README.md b/docs/directory-index/README.md new file mode 100644 index 0000000000..e69de29bb2 diff --git a/docs/directory-index/ROOT.md b/docs/directory-index/ROOT.md new file mode 100644 index 0000000000..296cef1b11 --- /dev/null +++ b/docs/directory-index/ROOT.md @@ -0,0 +1,99 @@ +# 📂 Repository Root Directory Index + +> **Last updated:** November 2025 +> **Purpose:** Quick reference for all root-level files and their roles + +--- + +## 🏗️ Build & Configuration + +| File | Purpose | +|------|---------| +| `pyproject.toml` | Python package configuration, dependencies, and build settings | +| `pytest.ini` | Pytest configuration and markers | +| `requirements.lock` | Pinned dependency versions for reproducible installs | +| `Makefile` | Build automation targets | +| `MANIFEST.in` | Package manifest for distribution | +| `cliff.toml` | Git-cliff changelog generator configuration | + +## 🐳 Container & DevOps + +| File | Purpose | +|------|---------| +| `Dockerfile` | Container image definition | +| `docker-compose.yml` | Multi-container orchestration | +| `.dockerignore` | Files excluded from Docker builds | +| `.hadolint.yaml` | Dockerfile linting rules | + +## 🔧 Development Tools + +| File | Purpose | +|------|---------| +| `.coveragerc` | Default coverage configuration | +| `.coveragerc.core` | Core module coverage settings | +| `.coveragerc.full` | Full coverage configuration | +| `.coveragerc.workflows` | Workflow-specific coverage settings | +| `.flake8` | Flake8 linting configuration | +| `.pre-commit-config.yaml` | Pre-commit hook definitions | +| `.gitignore` | Git ignore patterns | +| `.gitattributes` | Git file attributes | + +## 📖 Documentation + +| File | Purpose | +|------|---------| +| `README.md` | Primary project documentation | +| `README_APP.md` | Streamlit application guide | +| `README_DATA.md` | Data provenance and usage guide | +| `CHANGELOG.md` | Version history and release notes | +| `CONTRIBUTING.md` | Contribution guidelines | +| `CODE_OF_CONDUCT.md` | Community standards | +| `SECURITY.md` | Security policy and disclosure | +| `DEPENDENCY_QUICKSTART.md` | Quick dependency setup guide | +| `DOCKER_QUICKSTART.md` | Docker usage guide | +| `LICENSE` | MIT License | + +## 🤖 AI Agent Instructions + +| File | Purpose | +|------|---------| +| `Agents.md` | Codex agent instructions and workflow guidance | +| `Issues.txt` | Issue templates for keepalive automation | + +## 📊 CI-Generated Status Files + +| File | Purpose | +|------|---------| +| `coverage-summary.md` | Coverage trend snapshot (CI-generated) | +| `gate-summary.md` | PR gate status (CI-generated) | +| `keepalive_status.md` | Keepalive status index | + +--- + +## 📁 Directory Structure + +| Folder | Purpose | Index | +|--------|---------|-------| +| `agents/` | Codex agent session logs | [View](agents.md) | +| `analysis/` | Analysis modules and results helpers | [View](analysis.md) | +| `archives/` | Historical artifacts and retired code | [View](archives.md) | +| `assets/` | Static assets (images, templates) | [View](assets.md) | +| `config/` | YAML configuration files | [View](config.md) | +| `data/` | Reference datasets and raw data | [View](data.md) | +| `demo/` | Demo outputs and generated samples | [View](demo.md) | +| `docs/` | Project documentation | [View](docs.md) | +| `examples/` | Example scripts and notebooks | [View](examples.md) | +| `man/` | Manual pages | [View](man.md) | +| `notebooks/` | Jupyter notebooks | [View](notebooks.md) | +| `perf/` | Performance benchmarks and reports | [View](perf.md) | +| `reports/` | Generated reports | [View](reports.md) | +| `retired/` | Deprecated modules awaiting removal | [View](retired.md) | +| `scripts/` | Utility and automation scripts | [View](scripts.md) | +| `src/` | Main source code | [View](src.md) | +| `streamlit_app/` | Streamlit web application | [View](streamlit_app.md) | +| `tests/` | Test suite | [View](tests.md) | +| `tools/` | Development and build tools | [View](tools.md) | + +--- + +*See individual folder indexes for detailed contents.* diff --git a/docs/directory-index/config.md b/docs/directory-index/config.md new file mode 100644 index 0000000000..cd16390466 --- /dev/null +++ b/docs/directory-index/config.md @@ -0,0 +1,48 @@ +# 📂 `config/` — Configuration Directory + +> **Purpose:** YAML configuration files for analysis runs +> **Last updated:** November 2025 + +--- + +## 📄 Configuration Files + +| File | Description | +|------|-------------| +| `defaults.yml` | Default configuration values | +| `demo.yml` | Demo run configuration | +| `portfolio_test.yml` | Portfolio testing configuration | +| `trend_universe_2004.yml` | Trend universe 2004 configuration | +| `trend_concentrated_2004.yml` | Concentrated trend strategy | +| `long_backtest.yml` | Long backtest configuration | +| `robust_demo.yml` | Robustness testing configuration | +| `walk_forward.yml` | Walk-forward analysis settings | +| `trend.toml` | TOML-format trend settings | +| `coverage-baseline.json` | Coverage baseline for CI | + +## 📁 Subdirectories + +### `universe/` +Universe definition files: +- `core.yml` — Core universe definition +- `core_plus_benchmarks.yml` — Core with benchmark indices +- `managed_futures_min.yml` — Minimal managed futures universe + +### `presets/` +Pre-configured analysis presets for common use cases. + +--- + +## 🔧 Usage + +```bash +# Run with specific config +python -m trend_analysis.run_analysis -c config/demo.yml + +# Use environment variable +TREND_CFG=config/defaults.yml python -m trend_analysis.run_analysis +``` + +--- + +*See `docs/configuration.md` for full configuration reference.* diff --git a/docs/directory-index/data.md b/docs/directory-index/data.md new file mode 100644 index 0000000000..91d458700b --- /dev/null +++ b/docs/directory-index/data.md @@ -0,0 +1,55 @@ +# 📂 `data/` — Reference Datasets + +> **Purpose:** Demo datasets and reference data for tests and examples +> **Last updated:** November 2025 + +--- + +## 📊 Primary Datasets + +| File | Size | Description | +|------|------|-------------| +| `Trend Universe Data.csv` | 136 KB | Monthly total returns for Trend universe funds | +| `Trend Universe Membership.csv` | 4 KB | Fund membership effective dates | +| `hedge_fund_returns_with_indexes.csv` | 140 KB | Hedge fund returns with benchmark indices | + +## 📁 Subdirectories + +### `raw/` +Raw input data organized by type: + +#### `raw/managers/` +- `sample_manager.csv` — Minimal manager fixture for tests + +#### `raw/indices/` +- `sample_index.csv` — Sample benchmark index data + +--- + +## 📋 Schema Reference + +### Trend Universe Data +- **Columns:** `Date` + fund/index return series (decimal percentages) +- **Frequency:** Monthly +- **Pair with:** Membership ledger for effective windows + +### Trend Universe Membership +- **Columns:** `fund`, `effective_date`, `end_date` +- **Purpose:** Maps each fund to its active date range + +### Hedge Fund Returns +- **Columns:** `Date`, `Risk-Free Rate`, fund returns +- **Frequency:** Monthly +- **Use:** Long backtests and rolling-hold configs + +--- + +## ⚠️ Important Notes + +1. **Synthetic Data:** All datasets are synthetic or derived from public benchmarks +2. **Demo Only:** Not suitable for production trading decisions +3. **Provenance:** See `README_DATA.md` for full details + +--- + +*See `docs/data/Trend_Universe_Data.md` for stewardship notes.* diff --git a/docs/directory-index/docs.md b/docs/directory-index/docs.md new file mode 100644 index 0000000000..70c4a75637 --- /dev/null +++ b/docs/directory-index/docs.md @@ -0,0 +1,43 @@ +# 📂 `docs/` — Documentation + +> **Purpose:** Project documentation and guides +> **Last updated:** November 2025 + +--- + +## 📁 Key Subdirectories + +| Directory | Description | +|-----------|-------------| +| `archive/` | Archived documentation | +| `data/` | Data documentation and schemas | +| `directory-index/` | This directory index system | +| `keepalive/` | Keepalive workflow documentation | +| `phase-1/` | Phase 1 implementation docs | +| `phase-2/` | Phase 2 implementation docs | +| `workflows/` | GitHub workflow documentation | + +--- + +## 📄 Key Documents + +| Document | Description | +|----------|-------------| +| `INDEX.md` | Main documentation index | +| `architecture.md` | System architecture overview | +| `configuration.md` | Configuration reference | +| `walk_forward.md` | Walk-forward analysis guide | + +--- + +## 🔗 Quick Links + +- **Getting Started:** See `README.md` in root +- **Configuration:** `docs/configuration.md` +- **Architecture:** `docs/architecture.md` +- **Workflows:** `docs/workflows/` +- **Data Schemas:** `docs/data/` + +--- + +*For historical documentation, see `archives/docs/`.* diff --git a/docs/directory-index/scripts.md b/docs/directory-index/scripts.md new file mode 100644 index 0000000000..608f4a6c6a --- /dev/null +++ b/docs/directory-index/scripts.md @@ -0,0 +1,86 @@ +# 📂 `scripts/` — Utility Scripts + +> **Purpose:** Automation, development, and CI/CD scripts +> **Last updated:** November 2025 + +--- + +## 🚀 Quick Start Scripts + +| Script | Description | +|--------|-------------| +| `setup_env.sh` | Bootstrap virtual environment (60-180s) | +| `run_tests.sh` | Run full test suite with coverage | +| `run_streamlit.sh` | Launch Streamlit web application | +| `generate_demo.py` | Generate demo dataset | + +## 🔍 Validation Scripts + +| Script | Description | +|--------|-------------| +| `dev_check.sh` | Fast development validation (2-5s) | +| `validate_fast.sh` | Adaptive validation (5-30s) | +| `check_branch.sh` | Comprehensive pre-merge validation (30-120s) | +| `quality_gate.sh` | Quality gate enforcement | +| `quick_check.sh` | Rapid syntax/import check | + +## 🔧 CI/CD Scripts + +| Script | Description | +|--------|-------------| +| `ci_cosmetic_repair.py` | Auto-fix cosmetic issues | +| `ci_coverage_delta.py` | Calculate coverage changes | +| `ci_history.py` | CI run history tracking | +| `ci_metrics.py` | CI metrics collection | +| `workflow_lint.sh` | Lint GitHub workflow files | +| `workflow_smoke_tests.py` | Workflow smoke tests | + +## 📊 Analysis & Reporting + +| Script | Description | +|--------|-------------| +| `run_multi_demo.py` | Multi-period demo runner | +| `walk_forward.py` | Walk-forward analysis | +| `benchmark_performance.py` | Performance benchmarking | +| `compare_perf.py` | Performance comparison | +| `generate_residual_report.py` | Residual analysis reports | + +## 🤖 Automation + +| Script | Description | +|--------|-------------| +| `codex_git_bootstrap.sh` | Codex agent git setup | +| `keepalive-runner.js` | Keepalive workflow runner | +| `open_pr_from_issue.sh` | Create PR from issue | +| `git_hooks.sh` | Install git hooks | + +## 🛠️ Development Tools + +| Script | Description | +|--------|-------------| +| `fix_common_issues.sh` | Auto-fix common problems | +| `mypy_autofix.py` | Auto-fix type errors | +| `prune_allowlist.py` | Prune lint allowlists | +| `sync_tool_versions.py` | Sync tool versions | + +--- + +## 📋 Common Workflows + +### Development Cycle +```bash +./scripts/dev_check.sh --changed --fix # Quick validation +./scripts/validate_fast.sh --fix # Before commit +./scripts/check_branch.sh --fast --fix # Before merge +``` + +### Demo Pipeline +```bash +./scripts/setup_env.sh +python scripts/generate_demo.py +python scripts/run_multi_demo.py +``` + +--- + +*See `.github/copilot-instructions.md` for timing expectations.* diff --git a/docs/directory-index/src.md b/docs/directory-index/src.md new file mode 100644 index 0000000000..1108c331c9 --- /dev/null +++ b/docs/directory-index/src.md @@ -0,0 +1,48 @@ +# 📂 `src/` — Source Code Directory + +> **Purpose:** Main application source code +> **Last updated:** November 2025 + +--- + +## 📦 Packages + +| Package | Description | +|---------|-------------| +| `trend_analysis/` | Core trend analysis engine and pipeline | +| `trend_model/` | Trend model implementation | +| `trend_portfolio_app/` | Portfolio application components | +| `backtest/` | Backtesting framework | +| `data/` | Data loading and validation | +| `health_summarize/` | Health check summarization | +| `trend/` | Trend signal generation | +| `utils/` | Shared utilities | + +## 📄 Root Files + +| File | Purpose | +|------|---------| +| `__init__.py` | Package initialization | +| `cli.py` | Command-line interface entry point | + +--- + +## 🔗 Key Subpackages + +### `trend_analysis/` +The primary analysis package containing: +- Pipeline orchestration +- Metrics computation +- Configuration management +- Multi-period analysis engine +- Export functionality + +### `trend_portfolio_app/` +Streamlit web application components for interactive portfolio analysis. + +### `backtest/` +Walk-forward and backtesting utilities for strategy validation. + +--- + +*See `docs/architecture.md` for detailed module relationships.* diff --git a/docs/directory-index/tests.md b/docs/directory-index/tests.md new file mode 100644 index 0000000000..1dc451e5ad --- /dev/null +++ b/docs/directory-index/tests.md @@ -0,0 +1,88 @@ +# 📂 `tests/` — Test Suite + +> **Purpose:** Comprehensive unit and integration tests +> **Last updated:** November 2025 +> **Test count:** 400+ tests | **Coverage target:** 70%+ + +--- + +## 📁 Structure + +| Directory | Description | +|-----------|-------------| +| `app/` | Application-level tests | +| `backtesting/` | Backtest engine tests | +| `data/` | Data loading/validation tests | +| `fixtures/` | Test fixtures and sample data | +| `github_scripts/` | GitHub workflow script tests | +| `golden/` | Golden master comparison files | +| `proxy/` | Proxy server tests | +| `scripts/` | Script tests | +| `smoke/` | Smoke tests for quick validation | +| `soft_coverage/` | Soft coverage tracking | +| `tools/` | Tool tests | +| `trend_analysis/` | Core analysis tests | +| `unit/` | Pure unit tests | + +--- + +## 🧪 Test Categories + +### Core Analysis +- `test_pipeline*.py` — Pipeline orchestration +- `test_metrics*.py` — Financial metrics +- `test_config*.py` — Configuration loading +- `test_export*.py` — Export functionality + +### Multi-Period Engine +- `test_multi_period_engine*.py` — Rolling analysis engine +- `test_multi_period_export.py` — Period export tests +- `test_multi_period_selection.py` — Manager selection + +### Data & Validation +- `test_data*.py` — Data loading +- `test_validators*.py` — Input validation +- `test_market_data*.py` — Market data handling + +### UI & Application +- `test_streamlit*.py` — Streamlit app tests +- `test_gui*.py` — GUI component tests +- `test_cli*.py` — CLI tests + +### Workflows & CI +- `test_workflow*.py` — Workflow tests +- `test_autofix*.py` — Autofix pipeline tests +- `test_keepalive*.py` — Keepalive tests + +--- + +## 🚀 Running Tests + +```bash +# Full suite with coverage +./scripts/run_tests.sh + +# Quick run +pytest -q + +# Specific category +pytest tests/test_pipeline*.py + +# With coverage report +pytest --cov=trend_analysis --cov-branch +``` + +--- + +## 📋 Key Files + +| File | Purpose | +|------|---------| +| `conftest.py` | Pytest fixtures and configuration | +| `quarantine.yml` | Quarantined flaky tests | +| `sitecustomize.py` | Test environment customization | +| `score_frame_golden.csv` | Golden master for score frame | + +--- + +*See `pytest.ini` for test configuration.* diff --git a/test_multi_period_selection.py b/tests/test_multi_period_selection.py similarity index 100% rename from test_multi_period_selection.py rename to tests/test_multi_period_selection.py diff --git a/test_upload_app.py b/tests/test_upload_app.py similarity index 100% rename from test_upload_app.py rename to tests/test_upload_app.py From 3a2f5d07765463aaf39ff644aca4bbb030c67efd Mon Sep 17 00:00:00 2001 From: stranske Date: Sun, 30 Nov 2025 03:03:07 +0000 Subject: [PATCH 14/40] chore: archive agent files for closed issues - Archive all 18 .agents/ ledger files to archives/agents/ledgers/ (issues #3011-#3498, all CLOSED) - Archive 415 codex-*.md files referencing closed issues - Keep only codex-3572.md (issue #3572 OPEN) - Update agents/README.md with active file table - Update archives/agents/README.md with archive manifest - Add scripts/archive_agents.sh for future archival Before: 418 codex files + 18 ledgers After: 1 active codex file, rest archived with date prefix --- agents/README.md | 28 ++++-- .../agents/2025-11-30-codex-1018.md | 0 .../agents/2025-11-30-codex-1064.md | 0 .../agents/2025-11-30-codex-1137.md | 0 .../agents/2025-11-30-codex-1140.md | 0 .../agents/2025-11-30-codex-1142.md | 0 .../agents/2025-11-30-codex-1156.md | 0 .../agents/2025-11-30-codex-1157.md | 0 .../agents/2025-11-30-codex-1159.md | 0 .../agents/2025-11-30-codex-1161.md | 0 .../agents/2025-11-30-codex-1205.md | 0 .../agents/2025-11-30-codex-1207.md | 0 .../agents/2025-11-30-codex-1259.md | 0 .../agents/2025-11-30-codex-1342.md | 0 .../agents/2025-11-30-codex-1344.md | 0 .../agents/2025-11-30-codex-1345.md | 0 .../agents/2025-11-30-codex-1346.md | 0 .../agents/2025-11-30-codex-1347.md | 0 .../agents/2025-11-30-codex-1348.md | 0 .../agents/2025-11-30-codex-1350.md | 0 .../agents/2025-11-30-codex-1351.md | 0 .../agents/2025-11-30-codex-1386.md | 0 .../agents/2025-11-30-codex-1414.md | 0 .../agents/2025-11-30-codex-1415.md | 0 .../agents/2025-11-30-codex-1417.md | 0 .../agents/2025-11-30-codex-1418.md | 0 .../agents/2025-11-30-codex-1419.md | 0 .../agents/2025-11-30-codex-1420.md | 0 .../agents/2025-11-30-codex-1421.md | 0 .../agents/2025-11-30-codex-1422.md | 0 .../agents/2025-11-30-codex-1426.md | 0 .../agents/2025-11-30-codex-1436.md | 0 .../agents/2025-11-30-codex-1437.md | 0 .../agents/2025-11-30-codex-1438.md | 0 .../agents/2025-11-30-codex-1439.md | 0 .../agents/2025-11-30-codex-1440.md | 0 .../agents/2025-11-30-codex-1441.md | 0 .../agents/2025-11-30-codex-1491.md | 0 .../agents/2025-11-30-codex-1610.md | 0 .../agents/2025-11-30-codex-1630.md | 0 .../agents/2025-11-30-codex-1655.md | 0 .../agents/2025-11-30-codex-1656.md | 0 .../agents/2025-11-30-codex-1657.md | 0 .../agents/2025-11-30-codex-1658.md | 0 .../agents/2025-11-30-codex-1659.md | 0 .../agents/2025-11-30-codex-1660.md | 0 .../agents/2025-11-30-codex-1661.md | 0 .../agents/2025-11-30-codex-1662.md | 0 .../agents/2025-11-30-codex-1663.md | 0 .../agents/2025-11-30-codex-1664.md | 0 .../agents/2025-11-30-codex-1665.md | 0 .../agents/2025-11-30-codex-1666.md | 0 .../agents/2025-11-30-codex-1667.md | 0 .../agents/2025-11-30-codex-1668.md | 0 .../agents/2025-11-30-codex-1669.md | 0 .../agents/2025-11-30-codex-1674.md | 0 .../agents/2025-11-30-codex-1675.md | 0 .../agents/2025-11-30-codex-1676.md | 0 .../agents/2025-11-30-codex-1677.md | 0 .../agents/2025-11-30-codex-1678.md | 0 .../agents/2025-11-30-codex-1679.md | 0 .../agents/2025-11-30-codex-1680.md | 0 .../agents/2025-11-30-codex-1681.md | 0 .../agents/2025-11-30-codex-1682.md | 0 .../agents/2025-11-30-codex-1683.md | 0 .../agents/2025-11-30-codex-1684.md | 0 .../agents/2025-11-30-codex-1685.md | 0 .../agents/2025-11-30-codex-1686.md | 0 .../agents/2025-11-30-codex-1687.md | 0 .../agents/2025-11-30-codex-1688.md | 0 .../agents/2025-11-30-codex-2190.md | 0 .../agents/2025-11-30-codex-2191.md | 0 .../agents/2025-11-30-codex-2192.md | 0 .../agents/2025-11-30-codex-2193.md | 0 .../agents/2025-11-30-codex-2194.md | 0 .../agents/2025-11-30-codex-2195.md | 0 .../agents/2025-11-30-codex-2196.md | 0 .../agents/2025-11-30-codex-2197.md | 0 .../agents/2025-11-30-codex-2198.md | 0 .../agents/2025-11-30-codex-2199.md | 0 .../agents/2025-11-30-codex-2200.md | 0 .../agents/2025-11-30-codex-2201.md | 0 .../agents/2025-11-30-codex-2202.md | 0 .../agents/2025-11-30-codex-2376.md | 0 .../agents/2025-11-30-codex-2377.md | 0 .../agents/2025-11-30-codex-2378.md | 0 .../agents/2025-11-30-codex-2379.md | 0 .../agents/2025-11-30-codex-2380.md | 0 .../agents/2025-11-30-codex-2381.md | 0 .../agents/2025-11-30-codex-2382.md | 0 .../agents/2025-11-30-codex-2383.md | 0 .../agents/2025-11-30-codex-2384.md | 0 .../agents/2025-11-30-codex-2385.md | 0 .../agents/2025-11-30-codex-2386.md | 0 .../agents/2025-11-30-codex-2433.md | 0 .../agents/2025-11-30-codex-2434.md | 0 .../agents/2025-11-30-codex-2435.md | 0 .../agents/2025-11-30-codex-2436.md | 0 .../agents/2025-11-30-codex-2437.md | 0 .../agents/2025-11-30-codex-2438.md | 0 .../agents/2025-11-30-codex-2439.md | 0 .../agents/2025-11-30-codex-2461.md | 0 .../agents/2025-11-30-codex-2462.md | 0 .../agents/2025-11-30-codex-2463.md | 0 .../agents/2025-11-30-codex-2464.md | 0 .../agents/2025-11-30-codex-2465.md | 0 .../agents/2025-11-30-codex-2466.md | 0 .../agents/2025-11-30-codex-2492.md | 0 .../agents/2025-11-30-codex-2493.md | 0 .../agents/2025-11-30-codex-2494.md | 0 .../agents/2025-11-30-codex-2495.md | 0 .../agents/2025-11-30-codex-2496.md | 0 .../agents/2025-11-30-codex-2497.md | 0 .../agents/2025-11-30-codex-2498.md | 0 .../agents/2025-11-30-codex-2523.md | 0 .../agents/2025-11-30-codex-2524.md | 0 .../agents/2025-11-30-codex-2525.md | 0 .../agents/2025-11-30-codex-2526.md | 0 .../agents/2025-11-30-codex-2527.md | 0 .../agents/2025-11-30-codex-2528.md | 0 .../agents/2025-11-30-codex-2529.md | 0 .../agents/2025-11-30-codex-2560.md | 0 .../agents/2025-11-30-codex-2561.md | 0 .../agents/2025-11-30-codex-2562.md | 0 .../agents/2025-11-30-codex-2563.md | 0 .../agents/2025-11-30-codex-2564.md | 0 .../agents/2025-11-30-codex-2565.md | 0 .../agents/2025-11-30-codex-2566.md | 0 .../agents/2025-11-30-codex-2567.md | 0 .../agents/2025-11-30-codex-2609.md | 0 .../agents/2025-11-30-codex-2610.md | 0 .../agents/2025-11-30-codex-2611.md | 0 .../agents/2025-11-30-codex-2612.md | 0 .../agents/2025-11-30-codex-2614.md | 0 .../agents/2025-11-30-codex-2615.md | 0 .../agents/2025-11-30-codex-2616.md | 0 .../agents/2025-11-30-codex-2617.md | 0 .../agents/2025-11-30-codex-2618.md | 0 .../agents/2025-11-30-codex-2649.md | 0 .../agents/2025-11-30-codex-2650.md | 0 .../agents/2025-11-30-codex-2651.md | 0 .../agents/2025-11-30-codex-2652.md | 0 .../agents/2025-11-30-codex-2653.md | 0 .../agents/2025-11-30-codex-2654.md | 0 .../agents/2025-11-30-codex-2655.md | 0 .../agents/2025-11-30-codex-2656.md | 0 .../agents/2025-11-30-codex-2680.md | 0 .../agents/2025-11-30-codex-2681.md | 0 .../agents/2025-11-30-codex-2683.md | 0 .../agents/2025-11-30-codex-2685.md | 0 .../agents/2025-11-30-codex-2686.md | 0 .../agents/2025-11-30-codex-2687.md | 0 .../agents/2025-11-30-codex-2688.md | 0 .../agents/2025-11-30-codex-2718.md | 0 .../agents/2025-11-30-codex-2719.md | 0 .../agents/2025-11-30-codex-2720.md | 0 .../agents/2025-11-30-codex-2721.md | 0 .../agents/2025-11-30-codex-2722.md | 0 .../agents/2025-11-30-codex-2723.md | 0 .../agents/2025-11-30-codex-2724.md | 0 .../agents/2025-11-30-codex-2727.md | 0 .../agents/2025-11-30-codex-2728.md | 0 .../agents/2025-11-30-codex-2730.md | 0 .../agents/2025-11-30-codex-2731.md | 0 .../agents/2025-11-30-codex-2732.md | 0 .../agents/2025-11-30-codex-2733.md | 0 .../agents/2025-11-30-codex-2736.md | 0 .../agents/2025-11-30-codex-2739.md | 0 .../agents/2025-11-30-codex-2740.md | 0 .../agents/2025-11-30-codex-2801.md | 0 .../agents/2025-11-30-codex-2802.md | 0 .../agents/2025-11-30-codex-2811.md | 0 .../agents/2025-11-30-codex-2812.md | 0 .../agents/2025-11-30-codex-2813.md | 0 .../agents/2025-11-30-codex-2814.md | 0 .../agents/2025-11-30-codex-2815.md | 0 .../agents/2025-11-30-codex-2816.md | 0 .../agents/2025-11-30-codex-2820.md | 0 .../agents/2025-11-30-codex-2821.md | 0 .../agents/2025-11-30-codex-2822.md | 0 .../agents/2025-11-30-codex-2823.md | 0 .../agents/2025-11-30-codex-2846.md | 0 .../agents/2025-11-30-codex-2847.md | 0 .../agents/2025-11-30-codex-2848.md | 0 .../agents/2025-11-30-codex-2849.md | 0 .../agents/2025-11-30-codex-2850.md | 0 .../agents/2025-11-30-codex-2851.md | 0 .../agents/2025-11-30-codex-2853.md | 0 .../agents/2025-11-30-codex-2854.md | 0 .../agents/2025-11-30-codex-2878.md | 0 .../agents/2025-11-30-codex-2882.md | 0 .../agents/2025-11-30-codex-2883.md | 0 .../agents/2025-11-30-codex-2884.md | 0 .../agents/2025-11-30-codex-2885.md | 0 .../agents/2025-11-30-codex-2886.md | 0 .../agents/2025-11-30-codex-2913.md | 0 .../agents/2025-11-30-codex-2914.md | 0 .../agents/2025-11-30-codex-2915.md | 0 .../agents/2025-11-30-codex-2916.md | 0 .../agents/2025-11-30-codex-2917.md | 0 .../agents/2025-11-30-codex-2918.md | 0 .../agents/2025-11-30-codex-2919.md | 0 .../agents/2025-11-30-codex-2940.md | 0 .../agents/2025-11-30-codex-2942.md | 0 .../agents/2025-11-30-codex-2945.md | 0 .../agents/2025-11-30-codex-2955.md | 0 .../agents/2025-11-30-codex-2957.md | 0 .../agents/2025-11-30-codex-2958.md | 0 .../agents/2025-11-30-codex-2959.md | 0 .../agents/2025-11-30-codex-2960.md | 0 .../agents/2025-11-30-codex-2961.md | 0 .../agents/2025-11-30-codex-2962.md | 0 .../agents/2025-11-30-codex-2963.md | 0 .../agents/2025-11-30-codex-2964.md | 0 .../agents/2025-11-30-codex-2994.md | 0 .../agents/2025-11-30-codex-2995.md | 0 .../agents/2025-11-30-codex-2996.md | 0 .../agents/2025-11-30-codex-2997.md | 0 .../agents/2025-11-30-codex-2998.md | 0 .../agents/2025-11-30-codex-3006.md | 0 .../agents/2025-11-30-codex-3007.md | 0 .../agents/2025-11-30-codex-3008.md | 0 .../agents/2025-11-30-codex-3009.md | 0 .../agents/2025-11-30-codex-3010.md | 0 .../agents/2025-11-30-codex-3011.md | 0 .../agents/2025-11-30-codex-3013.md | 0 .../agents/2025-11-30-codex-3017.md | 0 .../agents/2025-11-30-codex-3019.md | 0 .../agents/2025-11-30-codex-3038.md | 0 .../agents/2025-11-30-codex-3039.md | 0 .../agents/2025-11-30-codex-3040.md | 0 .../agents/2025-11-30-codex-3041.md | 0 .../agents/2025-11-30-codex-3042.md | 0 .../agents/2025-11-30-codex-3053.md | 0 .../agents/2025-11-30-codex-3054.md | 0 .../agents/2025-11-30-codex-3055.md | 0 .../agents/2025-11-30-codex-3056.md | 0 .../agents/2025-11-30-codex-3057.md | 0 .../agents/2025-11-30-codex-3058.md | 0 .../agents/2025-11-30-codex-3073.md | 0 .../agents/2025-11-30-codex-3074.md | 0 .../agents/2025-11-30-codex-3075.md | 0 .../agents/2025-11-30-codex-3076.md | 0 .../agents/2025-11-30-codex-3077.md | 0 .../agents/2025-11-30-codex-3078.md | 0 .../agents/2025-11-30-codex-3085.md | 0 .../agents/2025-11-30-codex-3092.md | 0 .../agents/2025-11-30-codex-3093.md | 0 .../agents/2025-11-30-codex-3094.md | 0 .../agents/2025-11-30-codex-3095.md | 0 .../agents/2025-11-30-codex-3096.md | 0 .../agents/2025-11-30-codex-3098.md | 0 .../agents/2025-11-30-codex-3099.md | 0 .../agents/2025-11-30-codex-3100.md | 0 .../agents/2025-11-30-codex-3101.md | 0 .../agents/2025-11-30-codex-3118.md | 0 .../agents/2025-11-30-codex-3119.md | 0 .../agents/2025-11-30-codex-3122.md | 0 .../agents/2025-11-30-codex-3126.md | 0 .../agents/2025-11-30-codex-3129.md | 0 .../agents/2025-11-30-codex-3131.md | 0 .../agents/2025-11-30-codex-3135.md | 0 .../agents/2025-11-30-codex-3138.md | 0 .../agents/2025-11-30-codex-3139.md | 0 .../agents/2025-11-30-codex-3144.md | 0 .../agents/2025-11-30-codex-3149.md | 0 .../agents/2025-11-30-codex-3150.md | 0 .../agents/2025-11-30-codex-3154.md | 0 .../agents/2025-11-30-codex-3158.md | 0 .../agents/2025-11-30-codex-3160.md | 0 .../agents/2025-11-30-codex-3166.md | 0 .../agents/2025-11-30-codex-3171.md | 0 .../agents/2025-11-30-codex-3176.md | 0 .../agents/2025-11-30-codex-3179.md | 0 .../agents/2025-11-30-codex-3183.md | 0 .../agents/2025-11-30-codex-3190.md | 0 .../agents/2025-11-30-codex-3193.md | 0 .../agents/2025-11-30-codex-3196.md | 0 .../agents/2025-11-30-codex-3203.md | 0 .../agents/2025-11-30-codex-3209.md | 0 .../agents/2025-11-30-codex-3213.md | 0 .../agents/2025-11-30-codex-3216.md | 0 .../agents/2025-11-30-codex-3218.md | 0 .../agents/2025-11-30-codex-3219.md | 0 .../agents/2025-11-30-codex-3225.md | 0 .../agents/2025-11-30-codex-3227.md | 0 .../agents/2025-11-30-codex-3228.md | 0 .../agents/2025-11-30-codex-3233.md | 0 .../agents/2025-11-30-codex-3235.md | 0 .../agents/2025-11-30-codex-3237.md | 0 .../agents/2025-11-30-codex-3238.md | 0 .../agents/2025-11-30-codex-3249.md | 0 .../agents/2025-11-30-codex-3253.md | 0 .../agents/2025-11-30-codex-3254.md | 0 .../agents/2025-11-30-codex-3255.md | 0 .../agents/2025-11-30-codex-3260.md | 0 .../agents/2025-11-30-codex-3261.md | 0 .../agents/2025-11-30-codex-3266.md | 0 .../agents/2025-11-30-codex-3279.md | 0 .../agents/2025-11-30-codex-3284.md | 0 .../agents/2025-11-30-codex-3309.md | 0 .../agents/2025-11-30-codex-3318.md | 0 .../agents/2025-11-30-codex-3319.md | 0 .../agents/2025-11-30-codex-3321.md | 0 .../agents/2025-11-30-codex-3331.md | 0 .../agents/2025-11-30-codex-3333.md | 0 .../agents/2025-11-30-codex-3335.md | 0 .../agents/2025-11-30-codex-3352.md | 0 .../agents/2025-11-30-codex-3363.md | 0 .../agents/2025-11-30-codex-3364.md | 0 .../agents/2025-11-30-codex-3377.md | 0 .../agents/2025-11-30-codex-3380.md | 0 .../agents/2025-11-30-codex-3384.md | 0 .../agents/2025-11-30-codex-3391.md | 0 .../agents/2025-11-30-codex-3393.md | 0 .../agents/2025-11-30-codex-3397.md | 0 .../agents/2025-11-30-codex-3401.md | 0 .../agents/2025-11-30-codex-3404.md | 0 .../agents/2025-11-30-codex-3408.md | 0 .../agents/2025-11-30-codex-3412.md | 0 .../agents/2025-11-30-codex-3415.md | 0 .../agents/2025-11-30-codex-3418.md | 0 .../agents/2025-11-30-codex-3420.md | 0 .../agents/2025-11-30-codex-3424.md | 0 .../agents/2025-11-30-codex-3428.md | 0 .../agents/2025-11-30-codex-3431.md | 0 .../agents/2025-11-30-codex-3442.md | 0 .../agents/2025-11-30-codex-3488.md | 0 .../agents/2025-11-30-codex-3490.md | 0 .../agents/2025-11-30-codex-3498.md | 0 .../agents/2025-11-30-codex-3499.md | 0 .../agents/2025-11-30-codex-3500.md | 0 .../agents/2025-11-30-codex-3504.md | 0 .../agents/2025-11-30-codex-3505.md | 0 .../agents/2025-11-30-codex-3511.md | 0 .../agents/2025-11-30-codex-3523.md | 0 .../agents/2025-11-30-codex-3525.md | 0 .../agents/2025-11-30-codex-3527.md | 0 .../agents/2025-11-30-codex-3532.md | 0 .../agents/2025-11-30-codex-3533.md | 0 .../agents/2025-11-30-codex-3538.md | 0 .../agents/2025-11-30-codex-3544.md | 0 .../agents/2025-11-30-codex-3545.md | 0 .../agents/2025-11-30-codex-3546.md | 0 .../agents/2025-11-30-codex-3547.md | 0 .../agents/2025-11-30-codex-3552.md | 0 .../agents/2025-11-30-codex-3557.md | 0 .../agents/2025-11-30-codex-3558.md | 0 .../agents/2025-11-30-codex-3559.md | 0 .../agents/2025-11-30-codex-3581.md | 0 .../agents/2025-11-30-codex-3582.md | 0 .../agents/2025-11-30-codex-3583.md | 0 .../agents/2025-11-30-codex-3584.md | 0 .../agents/2025-11-30-codex-3585.md | 0 .../agents/2025-11-30-codex-3586.md | 0 .../agents/2025-11-30-codex-3587.md | 0 .../agents/2025-11-30-codex-3589.md | 0 .../agents/2025-11-30-codex-3590.md | 0 .../agents/2025-11-30-codex-3592.md | 0 .../agents/2025-11-30-codex-3593.md | 0 .../agents/2025-11-30-codex-3594.md | 0 .../agents/2025-11-30-codex-3595.md | 0 .../agents/2025-11-30-codex-3637.md | 0 .../agents/2025-11-30-codex-3638.md | 0 .../agents/2025-11-30-codex-3639.md | 0 .../agents/2025-11-30-codex-3640.md | 0 .../agents/2025-11-30-codex-3641.md | 0 .../agents/2025-11-30-codex-3642.md | 0 .../agents/2025-11-30-codex-3643.md | 0 .../agents/2025-11-30-codex-3645.md | 0 .../agents/2025-11-30-codex-3646.md | 0 .../agents/2025-11-30-codex-3647.md | 0 .../agents/2025-11-30-codex-3648.md | 0 .../agents/2025-11-30-codex-3649.md | 0 .../agents/2025-11-30-codex-3650.md | 0 .../agents/2025-11-30-codex-3651.md | 0 .../agents/2025-11-30-codex-3679.md | 0 .../agents/2025-11-30-codex-3680.md | 0 .../agents/2025-11-30-codex-3681.md | 0 .../agents/2025-11-30-codex-3682.md | 0 .../agents/2025-11-30-codex-3683.md | 0 .../agents/2025-11-30-codex-3684.md | 0 .../agents/2025-11-30-codex-3685.md | 0 .../agents/2025-11-30-codex-3687.md | 0 .../agents/2025-11-30-codex-3688.md | 0 .../agents/2025-11-30-codex-3689.md | 0 .../agents/2025-11-30-codex-3690.md | 0 .../agents/2025-11-30-codex-3691.md | 0 .../agents/2025-11-30-codex-3692.md | 0 .../agents/2025-11-30-codex-3693.md | 0 .../agents/2025-11-30-codex-3701.md | 0 .../agents/2025-11-30-codex-3737.md | 0 .../agents/2025-11-30-codex-3738.md | 0 .../agents/2025-11-30-codex-3739.md | 0 .../agents/2025-11-30-codex-3754.md | 0 .../agents/2025-11-30-codex-3756.md | 0 .../agents/2025-11-30-codex-3770.md | 0 .../agents/2025-11-30-codex-3771.md | 0 .../agents/2025-11-30-codex-3773.md | 0 .../agents/2025-11-30-codex-3784.md | 0 .../agents/2025-11-30-codex-3797.md | 0 .../agents/2025-11-30-codex-3798.md | 0 .../agents/2025-11-30-codex-3799.md | 0 .../agents/2025-11-30-codex-3800.md | 0 .../agents/2025-11-30-codex-3801.md | 0 .../agents/2025-11-30-codex-3817.md | 0 .../agents/2025-11-30-codex-3818.md | 0 .../agents/2025-11-30-codex-3819.md | 0 .../agents/2025-11-30-codex-3820.md | 0 .../agents/2025-11-30-codex-3861.md | 0 .../agents/2025-11-30-codex-3878.md | 0 .../agents/2025-11-30-codex-3879.md | 0 .../agents/2025-11-30-codex-721.md | 0 .../agents/2025-11-30-codex-730.md | 0 .../agents/2025-11-30-codex-732.md | 0 .../agents/2025-11-30-codex-734.md | 0 archives/agents/README.md | 21 ++++- .../agents/ledgers}/issue-3011-ledger.yml | 0 .../agents/ledgers}/issue-3203-ledger.yml | 0 .../agents/ledgers}/issue-3209-ledger.yml | 0 .../agents/ledgers}/issue-3213-ledger.yml | 0 .../agents/ledgers}/issue-3218-ledger.yml | 0 .../agents/ledgers}/issue-3219-ledger.yml | 0 .../agents/ledgers}/issue-3279-ledger.yml | 0 .../agents/ledgers}/issue-3284-ledger.yml | 0 .../agents/ledgers}/issue-3309-ledger.yml | 0 .../agents/ledgers}/issue-3318-ledger.yml | 0 .../agents/ledgers}/issue-3321-ledger.yml | 0 .../agents/ledgers}/issue-3333-ledger.yml | 0 .../agents/ledgers}/issue-3352-ledger.yml | 0 .../agents/ledgers}/issue-3363-ledger.yml | 0 .../agents/ledgers}/issue-3428-ledger.yml | 0 .../agents/ledgers}/issue-3442-ledger.yml | 0 .../agents/ledgers}/issue-3490-ledger.yml | 0 .../agents/ledgers}/issue-3498-ledger.yml | 0 scripts/archive_agents.sh | 85 +++++++++++++++++++ 436 files changed, 128 insertions(+), 6 deletions(-) rename agents/codex-1018.md => archives/agents/2025-11-30-codex-1018.md (100%) rename agents/codex-1064.md => archives/agents/2025-11-30-codex-1064.md (100%) rename agents/codex-1137.md => archives/agents/2025-11-30-codex-1137.md (100%) rename agents/codex-1140.md => archives/agents/2025-11-30-codex-1140.md (100%) rename agents/codex-1142.md => archives/agents/2025-11-30-codex-1142.md (100%) rename agents/codex-1156.md => archives/agents/2025-11-30-codex-1156.md (100%) rename agents/codex-1157.md => archives/agents/2025-11-30-codex-1157.md (100%) rename agents/codex-1159.md => archives/agents/2025-11-30-codex-1159.md (100%) rename agents/codex-1161.md => archives/agents/2025-11-30-codex-1161.md (100%) rename agents/codex-1205.md => archives/agents/2025-11-30-codex-1205.md (100%) rename agents/codex-1207.md => archives/agents/2025-11-30-codex-1207.md (100%) rename agents/codex-1259.md => archives/agents/2025-11-30-codex-1259.md (100%) rename agents/codex-1342.md => archives/agents/2025-11-30-codex-1342.md (100%) rename agents/codex-1344.md => archives/agents/2025-11-30-codex-1344.md (100%) rename agents/codex-1345.md => archives/agents/2025-11-30-codex-1345.md (100%) rename agents/codex-1346.md => archives/agents/2025-11-30-codex-1346.md (100%) rename agents/codex-1347.md => archives/agents/2025-11-30-codex-1347.md (100%) rename agents/codex-1348.md => archives/agents/2025-11-30-codex-1348.md (100%) rename agents/codex-1350.md => archives/agents/2025-11-30-codex-1350.md (100%) rename agents/codex-1351.md => archives/agents/2025-11-30-codex-1351.md (100%) rename agents/codex-1386.md => archives/agents/2025-11-30-codex-1386.md (100%) rename agents/codex-1414.md => archives/agents/2025-11-30-codex-1414.md (100%) rename agents/codex-1415.md => archives/agents/2025-11-30-codex-1415.md (100%) rename agents/codex-1417.md => archives/agents/2025-11-30-codex-1417.md (100%) rename agents/codex-1418.md => archives/agents/2025-11-30-codex-1418.md (100%) rename agents/codex-1419.md => archives/agents/2025-11-30-codex-1419.md (100%) rename agents/codex-1420.md => archives/agents/2025-11-30-codex-1420.md (100%) rename agents/codex-1421.md => archives/agents/2025-11-30-codex-1421.md (100%) rename agents/codex-1422.md => archives/agents/2025-11-30-codex-1422.md (100%) rename agents/codex-1426.md => archives/agents/2025-11-30-codex-1426.md (100%) rename agents/codex-1436.md => archives/agents/2025-11-30-codex-1436.md (100%) rename agents/codex-1437.md => archives/agents/2025-11-30-codex-1437.md (100%) rename agents/codex-1438.md => archives/agents/2025-11-30-codex-1438.md (100%) rename agents/codex-1439.md => archives/agents/2025-11-30-codex-1439.md (100%) rename agents/codex-1440.md => archives/agents/2025-11-30-codex-1440.md (100%) rename agents/codex-1441.md => archives/agents/2025-11-30-codex-1441.md (100%) rename agents/codex-1491.md => archives/agents/2025-11-30-codex-1491.md (100%) rename agents/codex-1610.md => archives/agents/2025-11-30-codex-1610.md (100%) rename agents/codex-1630.md => archives/agents/2025-11-30-codex-1630.md (100%) rename agents/codex-1655.md => archives/agents/2025-11-30-codex-1655.md (100%) rename agents/codex-1656.md => archives/agents/2025-11-30-codex-1656.md (100%) rename agents/codex-1657.md => archives/agents/2025-11-30-codex-1657.md (100%) rename agents/codex-1658.md => archives/agents/2025-11-30-codex-1658.md (100%) rename agents/codex-1659.md => archives/agents/2025-11-30-codex-1659.md (100%) rename agents/codex-1660.md => archives/agents/2025-11-30-codex-1660.md (100%) rename agents/codex-1661.md => archives/agents/2025-11-30-codex-1661.md (100%) rename agents/codex-1662.md => archives/agents/2025-11-30-codex-1662.md (100%) rename agents/codex-1663.md => archives/agents/2025-11-30-codex-1663.md (100%) rename agents/codex-1664.md => archives/agents/2025-11-30-codex-1664.md (100%) rename agents/codex-1665.md => archives/agents/2025-11-30-codex-1665.md (100%) rename agents/codex-1666.md => archives/agents/2025-11-30-codex-1666.md (100%) rename agents/codex-1667.md => archives/agents/2025-11-30-codex-1667.md (100%) rename agents/codex-1668.md => archives/agents/2025-11-30-codex-1668.md (100%) rename agents/codex-1669.md => archives/agents/2025-11-30-codex-1669.md (100%) rename agents/codex-1674.md => archives/agents/2025-11-30-codex-1674.md (100%) rename agents/codex-1675.md => archives/agents/2025-11-30-codex-1675.md (100%) rename agents/codex-1676.md => archives/agents/2025-11-30-codex-1676.md (100%) rename agents/codex-1677.md => archives/agents/2025-11-30-codex-1677.md (100%) rename agents/codex-1678.md => archives/agents/2025-11-30-codex-1678.md (100%) rename agents/codex-1679.md => archives/agents/2025-11-30-codex-1679.md (100%) rename agents/codex-1680.md => archives/agents/2025-11-30-codex-1680.md (100%) rename agents/codex-1681.md => archives/agents/2025-11-30-codex-1681.md (100%) rename agents/codex-1682.md => archives/agents/2025-11-30-codex-1682.md (100%) rename agents/codex-1683.md => archives/agents/2025-11-30-codex-1683.md (100%) rename agents/codex-1684.md => archives/agents/2025-11-30-codex-1684.md (100%) rename agents/codex-1685.md => archives/agents/2025-11-30-codex-1685.md (100%) rename agents/codex-1686.md => archives/agents/2025-11-30-codex-1686.md (100%) rename agents/codex-1687.md => archives/agents/2025-11-30-codex-1687.md (100%) rename agents/codex-1688.md => archives/agents/2025-11-30-codex-1688.md (100%) rename agents/codex-2190.md => archives/agents/2025-11-30-codex-2190.md (100%) rename agents/codex-2191.md => archives/agents/2025-11-30-codex-2191.md (100%) rename agents/codex-2192.md => archives/agents/2025-11-30-codex-2192.md (100%) rename agents/codex-2193.md => archives/agents/2025-11-30-codex-2193.md (100%) rename agents/codex-2194.md => archives/agents/2025-11-30-codex-2194.md (100%) rename agents/codex-2195.md => archives/agents/2025-11-30-codex-2195.md (100%) rename agents/codex-2196.md => archives/agents/2025-11-30-codex-2196.md (100%) rename agents/codex-2197.md => archives/agents/2025-11-30-codex-2197.md (100%) rename agents/codex-2198.md => archives/agents/2025-11-30-codex-2198.md (100%) rename agents/codex-2199.md => archives/agents/2025-11-30-codex-2199.md (100%) rename agents/codex-2200.md => archives/agents/2025-11-30-codex-2200.md (100%) rename agents/codex-2201.md => archives/agents/2025-11-30-codex-2201.md (100%) rename agents/codex-2202.md => archives/agents/2025-11-30-codex-2202.md (100%) rename agents/codex-2376.md => archives/agents/2025-11-30-codex-2376.md (100%) rename agents/codex-2377.md => archives/agents/2025-11-30-codex-2377.md (100%) rename agents/codex-2378.md => archives/agents/2025-11-30-codex-2378.md (100%) rename agents/codex-2379.md => archives/agents/2025-11-30-codex-2379.md (100%) rename agents/codex-2380.md => archives/agents/2025-11-30-codex-2380.md (100%) rename agents/codex-2381.md => archives/agents/2025-11-30-codex-2381.md (100%) rename agents/codex-2382.md => archives/agents/2025-11-30-codex-2382.md (100%) rename agents/codex-2383.md => archives/agents/2025-11-30-codex-2383.md (100%) rename agents/codex-2384.md => archives/agents/2025-11-30-codex-2384.md (100%) rename agents/codex-2385.md => archives/agents/2025-11-30-codex-2385.md (100%) rename agents/codex-2386.md => archives/agents/2025-11-30-codex-2386.md (100%) rename agents/codex-2433.md => archives/agents/2025-11-30-codex-2433.md (100%) rename agents/codex-2434.md => archives/agents/2025-11-30-codex-2434.md (100%) rename agents/codex-2435.md => archives/agents/2025-11-30-codex-2435.md (100%) rename agents/codex-2436.md => archives/agents/2025-11-30-codex-2436.md (100%) rename agents/codex-2437.md => archives/agents/2025-11-30-codex-2437.md (100%) rename agents/codex-2438.md => archives/agents/2025-11-30-codex-2438.md (100%) rename agents/codex-2439.md => archives/agents/2025-11-30-codex-2439.md (100%) rename agents/codex-2461.md => archives/agents/2025-11-30-codex-2461.md (100%) rename agents/codex-2462.md => archives/agents/2025-11-30-codex-2462.md (100%) rename agents/codex-2463.md => archives/agents/2025-11-30-codex-2463.md (100%) rename agents/codex-2464.md => archives/agents/2025-11-30-codex-2464.md (100%) rename agents/codex-2465.md => archives/agents/2025-11-30-codex-2465.md (100%) rename agents/codex-2466.md => archives/agents/2025-11-30-codex-2466.md (100%) rename agents/codex-2492.md => archives/agents/2025-11-30-codex-2492.md (100%) rename agents/codex-2493.md => archives/agents/2025-11-30-codex-2493.md (100%) rename agents/codex-2494.md => archives/agents/2025-11-30-codex-2494.md (100%) rename agents/codex-2495.md => archives/agents/2025-11-30-codex-2495.md (100%) rename agents/codex-2496.md => archives/agents/2025-11-30-codex-2496.md (100%) rename agents/codex-2497.md => archives/agents/2025-11-30-codex-2497.md (100%) rename agents/codex-2498.md => archives/agents/2025-11-30-codex-2498.md (100%) rename agents/codex-2523.md => archives/agents/2025-11-30-codex-2523.md (100%) rename agents/codex-2524.md => archives/agents/2025-11-30-codex-2524.md (100%) rename agents/codex-2525.md => archives/agents/2025-11-30-codex-2525.md (100%) rename agents/codex-2526.md => archives/agents/2025-11-30-codex-2526.md (100%) rename agents/codex-2527.md => archives/agents/2025-11-30-codex-2527.md (100%) rename agents/codex-2528.md => archives/agents/2025-11-30-codex-2528.md (100%) rename agents/codex-2529.md => archives/agents/2025-11-30-codex-2529.md (100%) rename agents/codex-2560.md => archives/agents/2025-11-30-codex-2560.md (100%) rename agents/codex-2561.md => archives/agents/2025-11-30-codex-2561.md (100%) rename agents/codex-2562.md => archives/agents/2025-11-30-codex-2562.md (100%) rename agents/codex-2563.md => archives/agents/2025-11-30-codex-2563.md (100%) rename agents/codex-2564.md => archives/agents/2025-11-30-codex-2564.md (100%) rename agents/codex-2565.md => archives/agents/2025-11-30-codex-2565.md (100%) rename agents/codex-2566.md => archives/agents/2025-11-30-codex-2566.md (100%) rename agents/codex-2567.md => archives/agents/2025-11-30-codex-2567.md (100%) rename agents/codex-2609.md => archives/agents/2025-11-30-codex-2609.md (100%) rename agents/codex-2610.md => archives/agents/2025-11-30-codex-2610.md (100%) rename agents/codex-2611.md => archives/agents/2025-11-30-codex-2611.md (100%) rename agents/codex-2612.md => archives/agents/2025-11-30-codex-2612.md (100%) rename agents/codex-2614.md => archives/agents/2025-11-30-codex-2614.md (100%) rename agents/codex-2615.md => archives/agents/2025-11-30-codex-2615.md (100%) rename agents/codex-2616.md => archives/agents/2025-11-30-codex-2616.md (100%) rename agents/codex-2617.md => archives/agents/2025-11-30-codex-2617.md (100%) rename agents/codex-2618.md => archives/agents/2025-11-30-codex-2618.md (100%) rename agents/codex-2649.md => archives/agents/2025-11-30-codex-2649.md (100%) rename agents/codex-2650.md => archives/agents/2025-11-30-codex-2650.md (100%) rename agents/codex-2651.md => archives/agents/2025-11-30-codex-2651.md (100%) rename agents/codex-2652.md => archives/agents/2025-11-30-codex-2652.md (100%) rename agents/codex-2653.md => archives/agents/2025-11-30-codex-2653.md (100%) rename agents/codex-2654.md => archives/agents/2025-11-30-codex-2654.md (100%) rename agents/codex-2655.md => archives/agents/2025-11-30-codex-2655.md (100%) rename agents/codex-2656.md => archives/agents/2025-11-30-codex-2656.md (100%) rename agents/codex-2680.md => archives/agents/2025-11-30-codex-2680.md (100%) rename agents/codex-2681.md => archives/agents/2025-11-30-codex-2681.md (100%) rename agents/codex-2683.md => archives/agents/2025-11-30-codex-2683.md (100%) rename agents/codex-2685.md => archives/agents/2025-11-30-codex-2685.md (100%) rename agents/codex-2686.md => archives/agents/2025-11-30-codex-2686.md (100%) rename agents/codex-2687.md => archives/agents/2025-11-30-codex-2687.md (100%) rename agents/codex-2688.md => archives/agents/2025-11-30-codex-2688.md (100%) rename agents/codex-2718.md => archives/agents/2025-11-30-codex-2718.md (100%) rename agents/codex-2719.md => archives/agents/2025-11-30-codex-2719.md (100%) rename agents/codex-2720.md => archives/agents/2025-11-30-codex-2720.md (100%) rename agents/codex-2721.md => archives/agents/2025-11-30-codex-2721.md (100%) rename agents/codex-2722.md => archives/agents/2025-11-30-codex-2722.md (100%) rename agents/codex-2723.md => archives/agents/2025-11-30-codex-2723.md (100%) rename agents/codex-2724.md => archives/agents/2025-11-30-codex-2724.md (100%) rename agents/codex-2727.md => archives/agents/2025-11-30-codex-2727.md (100%) rename agents/codex-2728.md => archives/agents/2025-11-30-codex-2728.md (100%) rename agents/codex-2730.md => archives/agents/2025-11-30-codex-2730.md (100%) rename agents/codex-2731.md => archives/agents/2025-11-30-codex-2731.md (100%) rename agents/codex-2732.md => archives/agents/2025-11-30-codex-2732.md (100%) rename agents/codex-2733.md => archives/agents/2025-11-30-codex-2733.md (100%) rename agents/codex-2736.md => archives/agents/2025-11-30-codex-2736.md (100%) rename agents/codex-2739.md => archives/agents/2025-11-30-codex-2739.md (100%) rename agents/codex-2740.md => archives/agents/2025-11-30-codex-2740.md (100%) rename agents/codex-2801.md => archives/agents/2025-11-30-codex-2801.md (100%) rename agents/codex-2802.md => archives/agents/2025-11-30-codex-2802.md (100%) rename agents/codex-2811.md => archives/agents/2025-11-30-codex-2811.md (100%) rename agents/codex-2812.md => archives/agents/2025-11-30-codex-2812.md (100%) rename agents/codex-2813.md => archives/agents/2025-11-30-codex-2813.md (100%) rename agents/codex-2814.md => archives/agents/2025-11-30-codex-2814.md (100%) rename agents/codex-2815.md => archives/agents/2025-11-30-codex-2815.md (100%) rename agents/codex-2816.md => archives/agents/2025-11-30-codex-2816.md (100%) rename agents/codex-2820.md => archives/agents/2025-11-30-codex-2820.md (100%) rename agents/codex-2821.md => archives/agents/2025-11-30-codex-2821.md (100%) rename agents/codex-2822.md => archives/agents/2025-11-30-codex-2822.md (100%) rename agents/codex-2823.md => archives/agents/2025-11-30-codex-2823.md (100%) rename agents/codex-2846.md => archives/agents/2025-11-30-codex-2846.md (100%) rename agents/codex-2847.md => archives/agents/2025-11-30-codex-2847.md (100%) rename agents/codex-2848.md => archives/agents/2025-11-30-codex-2848.md (100%) rename agents/codex-2849.md => archives/agents/2025-11-30-codex-2849.md (100%) rename agents/codex-2850.md => archives/agents/2025-11-30-codex-2850.md (100%) rename agents/codex-2851.md => archives/agents/2025-11-30-codex-2851.md (100%) rename agents/codex-2853.md => archives/agents/2025-11-30-codex-2853.md (100%) rename agents/codex-2854.md => archives/agents/2025-11-30-codex-2854.md (100%) rename agents/codex-2878.md => archives/agents/2025-11-30-codex-2878.md (100%) rename agents/codex-2882.md => archives/agents/2025-11-30-codex-2882.md (100%) rename agents/codex-2883.md => archives/agents/2025-11-30-codex-2883.md (100%) rename agents/codex-2884.md => archives/agents/2025-11-30-codex-2884.md (100%) rename agents/codex-2885.md => archives/agents/2025-11-30-codex-2885.md (100%) rename agents/codex-2886.md => archives/agents/2025-11-30-codex-2886.md (100%) rename agents/codex-2913.md => archives/agents/2025-11-30-codex-2913.md (100%) rename agents/codex-2914.md => archives/agents/2025-11-30-codex-2914.md (100%) rename agents/codex-2915.md => archives/agents/2025-11-30-codex-2915.md (100%) rename agents/codex-2916.md => archives/agents/2025-11-30-codex-2916.md (100%) rename agents/codex-2917.md => archives/agents/2025-11-30-codex-2917.md (100%) rename agents/codex-2918.md => archives/agents/2025-11-30-codex-2918.md (100%) rename agents/codex-2919.md => archives/agents/2025-11-30-codex-2919.md (100%) rename agents/codex-2940.md => archives/agents/2025-11-30-codex-2940.md (100%) rename agents/codex-2942.md => archives/agents/2025-11-30-codex-2942.md (100%) rename agents/codex-2945.md => archives/agents/2025-11-30-codex-2945.md (100%) rename agents/codex-2955.md => archives/agents/2025-11-30-codex-2955.md (100%) rename agents/codex-2957.md => archives/agents/2025-11-30-codex-2957.md (100%) rename agents/codex-2958.md => archives/agents/2025-11-30-codex-2958.md (100%) rename agents/codex-2959.md => archives/agents/2025-11-30-codex-2959.md (100%) rename agents/codex-2960.md => archives/agents/2025-11-30-codex-2960.md (100%) rename agents/codex-2961.md => archives/agents/2025-11-30-codex-2961.md (100%) rename agents/codex-2962.md => archives/agents/2025-11-30-codex-2962.md (100%) rename agents/codex-2963.md => archives/agents/2025-11-30-codex-2963.md (100%) rename agents/codex-2964.md => archives/agents/2025-11-30-codex-2964.md (100%) rename agents/codex-2994.md => archives/agents/2025-11-30-codex-2994.md (100%) rename agents/codex-2995.md => archives/agents/2025-11-30-codex-2995.md (100%) rename agents/codex-2996.md => archives/agents/2025-11-30-codex-2996.md (100%) rename agents/codex-2997.md => archives/agents/2025-11-30-codex-2997.md (100%) rename agents/codex-2998.md => archives/agents/2025-11-30-codex-2998.md (100%) rename agents/codex-3006.md => archives/agents/2025-11-30-codex-3006.md (100%) rename agents/codex-3007.md => archives/agents/2025-11-30-codex-3007.md (100%) rename agents/codex-3008.md => archives/agents/2025-11-30-codex-3008.md (100%) rename agents/codex-3009.md => archives/agents/2025-11-30-codex-3009.md (100%) rename agents/codex-3010.md => archives/agents/2025-11-30-codex-3010.md (100%) rename agents/codex-3011.md => archives/agents/2025-11-30-codex-3011.md (100%) rename agents/codex-3013.md => archives/agents/2025-11-30-codex-3013.md (100%) rename agents/codex-3017.md => archives/agents/2025-11-30-codex-3017.md (100%) rename agents/codex-3019.md => archives/agents/2025-11-30-codex-3019.md (100%) rename agents/codex-3038.md => archives/agents/2025-11-30-codex-3038.md (100%) rename agents/codex-3039.md => archives/agents/2025-11-30-codex-3039.md (100%) rename agents/codex-3040.md => archives/agents/2025-11-30-codex-3040.md (100%) rename agents/codex-3041.md => archives/agents/2025-11-30-codex-3041.md (100%) rename agents/codex-3042.md => archives/agents/2025-11-30-codex-3042.md (100%) rename agents/codex-3053.md => archives/agents/2025-11-30-codex-3053.md (100%) rename agents/codex-3054.md => archives/agents/2025-11-30-codex-3054.md (100%) rename agents/codex-3055.md => archives/agents/2025-11-30-codex-3055.md (100%) rename agents/codex-3056.md => archives/agents/2025-11-30-codex-3056.md (100%) rename agents/codex-3057.md => archives/agents/2025-11-30-codex-3057.md (100%) rename agents/codex-3058.md => archives/agents/2025-11-30-codex-3058.md (100%) rename agents/codex-3073.md => archives/agents/2025-11-30-codex-3073.md (100%) rename agents/codex-3074.md => archives/agents/2025-11-30-codex-3074.md (100%) rename agents/codex-3075.md => archives/agents/2025-11-30-codex-3075.md (100%) rename agents/codex-3076.md => archives/agents/2025-11-30-codex-3076.md (100%) rename agents/codex-3077.md => archives/agents/2025-11-30-codex-3077.md (100%) rename agents/codex-3078.md => archives/agents/2025-11-30-codex-3078.md (100%) rename agents/codex-3085.md => archives/agents/2025-11-30-codex-3085.md (100%) rename agents/codex-3092.md => archives/agents/2025-11-30-codex-3092.md (100%) rename agents/codex-3093.md => archives/agents/2025-11-30-codex-3093.md (100%) rename agents/codex-3094.md => archives/agents/2025-11-30-codex-3094.md (100%) rename agents/codex-3095.md => archives/agents/2025-11-30-codex-3095.md (100%) rename agents/codex-3096.md => archives/agents/2025-11-30-codex-3096.md (100%) rename agents/codex-3098.md => archives/agents/2025-11-30-codex-3098.md (100%) rename agents/codex-3099.md => archives/agents/2025-11-30-codex-3099.md (100%) rename agents/codex-3100.md => archives/agents/2025-11-30-codex-3100.md (100%) rename agents/codex-3101.md => archives/agents/2025-11-30-codex-3101.md (100%) rename agents/codex-3118.md => archives/agents/2025-11-30-codex-3118.md (100%) rename agents/codex-3119.md => archives/agents/2025-11-30-codex-3119.md (100%) rename agents/codex-3122.md => archives/agents/2025-11-30-codex-3122.md (100%) rename agents/codex-3126.md => archives/agents/2025-11-30-codex-3126.md (100%) rename agents/codex-3129.md => archives/agents/2025-11-30-codex-3129.md (100%) rename agents/codex-3131.md => archives/agents/2025-11-30-codex-3131.md (100%) rename agents/codex-3135.md => archives/agents/2025-11-30-codex-3135.md (100%) rename agents/codex-3138.md => archives/agents/2025-11-30-codex-3138.md (100%) rename agents/codex-3139.md => archives/agents/2025-11-30-codex-3139.md (100%) rename agents/codex-3144.md => archives/agents/2025-11-30-codex-3144.md (100%) rename agents/codex-3149.md => archives/agents/2025-11-30-codex-3149.md (100%) rename agents/codex-3150.md => archives/agents/2025-11-30-codex-3150.md (100%) rename agents/codex-3154.md => archives/agents/2025-11-30-codex-3154.md (100%) rename agents/codex-3158.md => archives/agents/2025-11-30-codex-3158.md (100%) rename agents/codex-3160.md => archives/agents/2025-11-30-codex-3160.md (100%) rename agents/codex-3166.md => archives/agents/2025-11-30-codex-3166.md (100%) rename agents/codex-3171.md => archives/agents/2025-11-30-codex-3171.md (100%) rename agents/codex-3176.md => archives/agents/2025-11-30-codex-3176.md (100%) rename agents/codex-3179.md => archives/agents/2025-11-30-codex-3179.md (100%) rename agents/codex-3183.md => archives/agents/2025-11-30-codex-3183.md (100%) rename agents/codex-3190.md => archives/agents/2025-11-30-codex-3190.md (100%) rename agents/codex-3193.md => archives/agents/2025-11-30-codex-3193.md (100%) rename agents/codex-3196.md => archives/agents/2025-11-30-codex-3196.md (100%) rename agents/codex-3203.md => archives/agents/2025-11-30-codex-3203.md (100%) rename agents/codex-3209.md => archives/agents/2025-11-30-codex-3209.md (100%) rename agents/codex-3213.md => archives/agents/2025-11-30-codex-3213.md (100%) rename agents/codex-3216.md => archives/agents/2025-11-30-codex-3216.md (100%) rename agents/codex-3218.md => archives/agents/2025-11-30-codex-3218.md (100%) rename agents/codex-3219.md => archives/agents/2025-11-30-codex-3219.md (100%) rename agents/codex-3225.md => archives/agents/2025-11-30-codex-3225.md (100%) rename agents/codex-3227.md => archives/agents/2025-11-30-codex-3227.md (100%) rename agents/codex-3228.md => archives/agents/2025-11-30-codex-3228.md (100%) rename agents/codex-3233.md => archives/agents/2025-11-30-codex-3233.md (100%) rename agents/codex-3235.md => archives/agents/2025-11-30-codex-3235.md (100%) rename agents/codex-3237.md => archives/agents/2025-11-30-codex-3237.md (100%) rename agents/codex-3238.md => archives/agents/2025-11-30-codex-3238.md (100%) rename agents/codex-3249.md => archives/agents/2025-11-30-codex-3249.md (100%) rename agents/codex-3253.md => archives/agents/2025-11-30-codex-3253.md (100%) rename agents/codex-3254.md => archives/agents/2025-11-30-codex-3254.md (100%) rename agents/codex-3255.md => archives/agents/2025-11-30-codex-3255.md (100%) rename agents/codex-3260.md => archives/agents/2025-11-30-codex-3260.md (100%) rename agents/codex-3261.md => archives/agents/2025-11-30-codex-3261.md (100%) rename agents/codex-3266.md => archives/agents/2025-11-30-codex-3266.md (100%) rename agents/codex-3279.md => archives/agents/2025-11-30-codex-3279.md (100%) rename agents/codex-3284.md => archives/agents/2025-11-30-codex-3284.md (100%) rename agents/codex-3309.md => archives/agents/2025-11-30-codex-3309.md (100%) rename agents/codex-3318.md => archives/agents/2025-11-30-codex-3318.md (100%) rename agents/codex-3319.md => archives/agents/2025-11-30-codex-3319.md (100%) rename agents/codex-3321.md => archives/agents/2025-11-30-codex-3321.md (100%) rename agents/codex-3331.md => archives/agents/2025-11-30-codex-3331.md (100%) rename agents/codex-3333.md => archives/agents/2025-11-30-codex-3333.md (100%) rename agents/codex-3335.md => archives/agents/2025-11-30-codex-3335.md (100%) rename agents/codex-3352.md => archives/agents/2025-11-30-codex-3352.md (100%) rename agents/codex-3363.md => archives/agents/2025-11-30-codex-3363.md (100%) rename agents/codex-3364.md => archives/agents/2025-11-30-codex-3364.md (100%) rename agents/codex-3377.md => archives/agents/2025-11-30-codex-3377.md (100%) rename agents/codex-3380.md => archives/agents/2025-11-30-codex-3380.md (100%) rename agents/codex-3384.md => archives/agents/2025-11-30-codex-3384.md (100%) rename agents/codex-3391.md => archives/agents/2025-11-30-codex-3391.md (100%) rename agents/codex-3393.md => archives/agents/2025-11-30-codex-3393.md (100%) rename agents/codex-3397.md => archives/agents/2025-11-30-codex-3397.md (100%) rename agents/codex-3401.md => archives/agents/2025-11-30-codex-3401.md (100%) rename agents/codex-3404.md => archives/agents/2025-11-30-codex-3404.md (100%) rename agents/codex-3408.md => archives/agents/2025-11-30-codex-3408.md (100%) rename agents/codex-3412.md => archives/agents/2025-11-30-codex-3412.md (100%) rename agents/codex-3415.md => archives/agents/2025-11-30-codex-3415.md (100%) rename agents/codex-3418.md => archives/agents/2025-11-30-codex-3418.md (100%) rename agents/codex-3420.md => archives/agents/2025-11-30-codex-3420.md (100%) rename agents/codex-3424.md => archives/agents/2025-11-30-codex-3424.md (100%) rename agents/codex-3428.md => archives/agents/2025-11-30-codex-3428.md (100%) rename agents/codex-3431.md => archives/agents/2025-11-30-codex-3431.md (100%) rename agents/codex-3442.md => archives/agents/2025-11-30-codex-3442.md (100%) rename agents/codex-3488.md => archives/agents/2025-11-30-codex-3488.md (100%) rename agents/codex-3490.md => archives/agents/2025-11-30-codex-3490.md (100%) rename agents/codex-3498.md => archives/agents/2025-11-30-codex-3498.md (100%) rename agents/codex-3499.md => archives/agents/2025-11-30-codex-3499.md (100%) rename agents/codex-3500.md => archives/agents/2025-11-30-codex-3500.md (100%) rename agents/codex-3504.md => archives/agents/2025-11-30-codex-3504.md (100%) rename agents/codex-3505.md => archives/agents/2025-11-30-codex-3505.md (100%) rename agents/codex-3511.md => archives/agents/2025-11-30-codex-3511.md (100%) rename agents/codex-3523.md => archives/agents/2025-11-30-codex-3523.md (100%) rename agents/codex-3525.md => archives/agents/2025-11-30-codex-3525.md (100%) rename agents/codex-3527.md => archives/agents/2025-11-30-codex-3527.md (100%) rename agents/codex-3532.md => archives/agents/2025-11-30-codex-3532.md (100%) rename agents/codex-3533.md => archives/agents/2025-11-30-codex-3533.md (100%) rename agents/codex-3538.md => archives/agents/2025-11-30-codex-3538.md (100%) rename agents/codex-3544.md => archives/agents/2025-11-30-codex-3544.md (100%) rename agents/codex-3545.md => archives/agents/2025-11-30-codex-3545.md (100%) rename agents/codex-3546.md => archives/agents/2025-11-30-codex-3546.md (100%) rename agents/codex-3547.md => archives/agents/2025-11-30-codex-3547.md (100%) rename agents/codex-3552.md => archives/agents/2025-11-30-codex-3552.md (100%) rename agents/codex-3557.md => archives/agents/2025-11-30-codex-3557.md (100%) rename agents/codex-3558.md => archives/agents/2025-11-30-codex-3558.md (100%) rename agents/codex-3559.md => archives/agents/2025-11-30-codex-3559.md (100%) rename agents/codex-3581.md => archives/agents/2025-11-30-codex-3581.md (100%) rename agents/codex-3582.md => archives/agents/2025-11-30-codex-3582.md (100%) rename agents/codex-3583.md => archives/agents/2025-11-30-codex-3583.md (100%) rename agents/codex-3584.md => archives/agents/2025-11-30-codex-3584.md (100%) rename agents/codex-3585.md => archives/agents/2025-11-30-codex-3585.md (100%) rename agents/codex-3586.md => archives/agents/2025-11-30-codex-3586.md (100%) rename agents/codex-3587.md => archives/agents/2025-11-30-codex-3587.md (100%) rename agents/codex-3589.md => archives/agents/2025-11-30-codex-3589.md (100%) rename agents/codex-3590.md => archives/agents/2025-11-30-codex-3590.md (100%) rename agents/codex-3592.md => archives/agents/2025-11-30-codex-3592.md (100%) rename agents/codex-3593.md => archives/agents/2025-11-30-codex-3593.md (100%) rename agents/codex-3594.md => archives/agents/2025-11-30-codex-3594.md (100%) rename agents/codex-3595.md => archives/agents/2025-11-30-codex-3595.md (100%) rename agents/codex-3637.md => archives/agents/2025-11-30-codex-3637.md (100%) rename agents/codex-3638.md => archives/agents/2025-11-30-codex-3638.md (100%) rename agents/codex-3639.md => archives/agents/2025-11-30-codex-3639.md (100%) rename agents/codex-3640.md => archives/agents/2025-11-30-codex-3640.md (100%) rename agents/codex-3641.md => archives/agents/2025-11-30-codex-3641.md (100%) rename agents/codex-3642.md => archives/agents/2025-11-30-codex-3642.md (100%) rename agents/codex-3643.md => archives/agents/2025-11-30-codex-3643.md (100%) rename agents/codex-3645.md => archives/agents/2025-11-30-codex-3645.md (100%) rename agents/codex-3646.md => archives/agents/2025-11-30-codex-3646.md (100%) rename agents/codex-3647.md => archives/agents/2025-11-30-codex-3647.md (100%) rename agents/codex-3648.md => archives/agents/2025-11-30-codex-3648.md (100%) rename agents/codex-3649.md => archives/agents/2025-11-30-codex-3649.md (100%) rename agents/codex-3650.md => archives/agents/2025-11-30-codex-3650.md (100%) rename agents/codex-3651.md => archives/agents/2025-11-30-codex-3651.md (100%) rename agents/codex-3679.md => archives/agents/2025-11-30-codex-3679.md (100%) rename agents/codex-3680.md => archives/agents/2025-11-30-codex-3680.md (100%) rename agents/codex-3681.md => archives/agents/2025-11-30-codex-3681.md (100%) rename agents/codex-3682.md => archives/agents/2025-11-30-codex-3682.md (100%) rename agents/codex-3683.md => archives/agents/2025-11-30-codex-3683.md (100%) rename agents/codex-3684.md => archives/agents/2025-11-30-codex-3684.md (100%) rename agents/codex-3685.md => archives/agents/2025-11-30-codex-3685.md (100%) rename agents/codex-3687.md => archives/agents/2025-11-30-codex-3687.md (100%) rename agents/codex-3688.md => archives/agents/2025-11-30-codex-3688.md (100%) rename agents/codex-3689.md => archives/agents/2025-11-30-codex-3689.md (100%) rename agents/codex-3690.md => archives/agents/2025-11-30-codex-3690.md (100%) rename agents/codex-3691.md => archives/agents/2025-11-30-codex-3691.md (100%) rename agents/codex-3692.md => archives/agents/2025-11-30-codex-3692.md (100%) rename agents/codex-3693.md => archives/agents/2025-11-30-codex-3693.md (100%) rename agents/codex-3701.md => archives/agents/2025-11-30-codex-3701.md (100%) rename agents/codex-3737.md => archives/agents/2025-11-30-codex-3737.md (100%) rename agents/codex-3738.md => archives/agents/2025-11-30-codex-3738.md (100%) rename agents/codex-3739.md => archives/agents/2025-11-30-codex-3739.md (100%) rename agents/codex-3754.md => archives/agents/2025-11-30-codex-3754.md (100%) rename agents/codex-3756.md => archives/agents/2025-11-30-codex-3756.md (100%) rename agents/codex-3770.md => archives/agents/2025-11-30-codex-3770.md (100%) rename agents/codex-3771.md => archives/agents/2025-11-30-codex-3771.md (100%) rename agents/codex-3773.md => archives/agents/2025-11-30-codex-3773.md (100%) rename agents/codex-3784.md => archives/agents/2025-11-30-codex-3784.md (100%) rename agents/codex-3797.md => archives/agents/2025-11-30-codex-3797.md (100%) rename agents/codex-3798.md => archives/agents/2025-11-30-codex-3798.md (100%) rename agents/codex-3799.md => archives/agents/2025-11-30-codex-3799.md (100%) rename agents/codex-3800.md => archives/agents/2025-11-30-codex-3800.md (100%) rename agents/codex-3801.md => archives/agents/2025-11-30-codex-3801.md (100%) rename agents/codex-3817.md => archives/agents/2025-11-30-codex-3817.md (100%) rename agents/codex-3818.md => archives/agents/2025-11-30-codex-3818.md (100%) rename agents/codex-3819.md => archives/agents/2025-11-30-codex-3819.md (100%) rename agents/codex-3820.md => archives/agents/2025-11-30-codex-3820.md (100%) rename agents/codex-3861.md => archives/agents/2025-11-30-codex-3861.md (100%) rename agents/codex-3878.md => archives/agents/2025-11-30-codex-3878.md (100%) rename agents/codex-3879.md => archives/agents/2025-11-30-codex-3879.md (100%) rename agents/codex-721.md => archives/agents/2025-11-30-codex-721.md (100%) rename agents/codex-730.md => archives/agents/2025-11-30-codex-730.md (100%) rename agents/codex-732.md => archives/agents/2025-11-30-codex-732.md (100%) rename agents/codex-734.md => archives/agents/2025-11-30-codex-734.md (100%) rename {.agents => archives/agents/ledgers}/issue-3011-ledger.yml (100%) rename {.agents => archives/agents/ledgers}/issue-3203-ledger.yml (100%) rename {.agents => archives/agents/ledgers}/issue-3209-ledger.yml (100%) rename {.agents => archives/agents/ledgers}/issue-3213-ledger.yml (100%) rename {.agents => archives/agents/ledgers}/issue-3218-ledger.yml (100%) rename {.agents => archives/agents/ledgers}/issue-3219-ledger.yml (100%) rename {.agents => archives/agents/ledgers}/issue-3279-ledger.yml (100%) rename {.agents => archives/agents/ledgers}/issue-3284-ledger.yml (100%) rename {.agents => archives/agents/ledgers}/issue-3309-ledger.yml (100%) rename {.agents => archives/agents/ledgers}/issue-3318-ledger.yml (100%) rename {.agents => archives/agents/ledgers}/issue-3321-ledger.yml (100%) rename {.agents => archives/agents/ledgers}/issue-3333-ledger.yml (100%) rename {.agents => archives/agents/ledgers}/issue-3352-ledger.yml (100%) rename {.agents => archives/agents/ledgers}/issue-3363-ledger.yml (100%) rename {.agents => archives/agents/ledgers}/issue-3428-ledger.yml (100%) rename {.agents => archives/agents/ledgers}/issue-3442-ledger.yml (100%) rename {.agents => archives/agents/ledgers}/issue-3490-ledger.yml (100%) rename {.agents => archives/agents/ledgers}/issue-3498-ledger.yml (100%) create mode 100755 scripts/archive_agents.sh diff --git a/agents/README.md b/agents/README.md index edf56917de..fb0b5a5682 100644 --- a/agents/README.md +++ b/agents/README.md @@ -1,9 +1,27 @@ # Agents instruction index -The files in this directory house the active Codex/agent guidance tied to in-flight issues. Historical bootstraps that referenced retired workflows now live in `../archives/agents/`. +This directory contains **active** Codex/agent guidance tied to **open** issues only. +Files for closed issues are archived to `archives/agents/` with a date prefix. -Use the following canonical sources when adding or updating instructions: -- `.github/workflows/README.md` — current workflow inventory and naming rules. -- `docs/ci/AGENTS_POLICY.md` — protection contract and verification steps for the agents workflows. +## Current active files -If an issue-specific instruction file no longer matches the live workflow names or policy versions, move it to `archives/agents/` with a date prefix and note the replacement source. +| File | Issue | Status | +|------|-------|--------| +| `codex-3572.md` | [#3572](https://github.com/stranske/Trend_Model_Project/issues/3572) | OPEN | + +## Maintenance + +See `MAINTENANCE.md` for archival criteria. When an issue closes: + +1. Run `scripts/archive_agents.sh` to auto-archive closed-issue files +2. Or manually: `mv codex-NNNN.md ../archives/agents/$(date +%Y-%m-%d)-codex-NNNN.md` + +## Canonical sources + +- `.github/workflows/README.md` — workflow inventory and naming rules +- `docs/ci/AGENTS_POLICY.md` — protection contract and verification steps + +## Archive history + +- **2025-11-30**: Bulk archived 415 codex files and 18 ledger files (all closed issues) +- **2025-11-22**: Archived 4 files referencing retired workflow names diff --git a/agents/codex-1018.md b/archives/agents/2025-11-30-codex-1018.md similarity index 100% rename from agents/codex-1018.md rename to archives/agents/2025-11-30-codex-1018.md diff --git a/agents/codex-1064.md b/archives/agents/2025-11-30-codex-1064.md similarity index 100% rename from agents/codex-1064.md rename to archives/agents/2025-11-30-codex-1064.md diff --git a/agents/codex-1137.md b/archives/agents/2025-11-30-codex-1137.md similarity index 100% rename from agents/codex-1137.md rename to archives/agents/2025-11-30-codex-1137.md diff --git a/agents/codex-1140.md b/archives/agents/2025-11-30-codex-1140.md similarity index 100% rename from agents/codex-1140.md rename to archives/agents/2025-11-30-codex-1140.md diff --git a/agents/codex-1142.md b/archives/agents/2025-11-30-codex-1142.md similarity index 100% rename from agents/codex-1142.md rename to archives/agents/2025-11-30-codex-1142.md diff --git a/agents/codex-1156.md b/archives/agents/2025-11-30-codex-1156.md similarity index 100% rename from agents/codex-1156.md rename to archives/agents/2025-11-30-codex-1156.md diff --git a/agents/codex-1157.md b/archives/agents/2025-11-30-codex-1157.md similarity index 100% rename from agents/codex-1157.md rename to archives/agents/2025-11-30-codex-1157.md diff --git a/agents/codex-1159.md b/archives/agents/2025-11-30-codex-1159.md similarity index 100% rename from agents/codex-1159.md rename to archives/agents/2025-11-30-codex-1159.md diff --git a/agents/codex-1161.md b/archives/agents/2025-11-30-codex-1161.md similarity index 100% rename from agents/codex-1161.md rename to archives/agents/2025-11-30-codex-1161.md diff --git a/agents/codex-1205.md b/archives/agents/2025-11-30-codex-1205.md similarity index 100% rename from agents/codex-1205.md rename to archives/agents/2025-11-30-codex-1205.md diff --git a/agents/codex-1207.md b/archives/agents/2025-11-30-codex-1207.md similarity index 100% rename from agents/codex-1207.md rename to archives/agents/2025-11-30-codex-1207.md diff --git a/agents/codex-1259.md b/archives/agents/2025-11-30-codex-1259.md similarity index 100% rename from agents/codex-1259.md rename to archives/agents/2025-11-30-codex-1259.md diff --git a/agents/codex-1342.md b/archives/agents/2025-11-30-codex-1342.md similarity index 100% rename from agents/codex-1342.md rename to archives/agents/2025-11-30-codex-1342.md diff --git a/agents/codex-1344.md b/archives/agents/2025-11-30-codex-1344.md similarity index 100% rename from agents/codex-1344.md rename to archives/agents/2025-11-30-codex-1344.md diff --git a/agents/codex-1345.md b/archives/agents/2025-11-30-codex-1345.md similarity index 100% rename from agents/codex-1345.md rename to archives/agents/2025-11-30-codex-1345.md diff --git a/agents/codex-1346.md b/archives/agents/2025-11-30-codex-1346.md similarity index 100% rename from agents/codex-1346.md rename to archives/agents/2025-11-30-codex-1346.md diff --git a/agents/codex-1347.md b/archives/agents/2025-11-30-codex-1347.md similarity index 100% rename from agents/codex-1347.md rename to archives/agents/2025-11-30-codex-1347.md diff --git a/agents/codex-1348.md b/archives/agents/2025-11-30-codex-1348.md similarity index 100% rename from agents/codex-1348.md rename to archives/agents/2025-11-30-codex-1348.md diff --git a/agents/codex-1350.md b/archives/agents/2025-11-30-codex-1350.md similarity index 100% rename from agents/codex-1350.md rename to archives/agents/2025-11-30-codex-1350.md diff --git a/agents/codex-1351.md b/archives/agents/2025-11-30-codex-1351.md similarity index 100% rename from agents/codex-1351.md rename to archives/agents/2025-11-30-codex-1351.md diff --git a/agents/codex-1386.md b/archives/agents/2025-11-30-codex-1386.md similarity index 100% rename from agents/codex-1386.md rename to archives/agents/2025-11-30-codex-1386.md diff --git a/agents/codex-1414.md b/archives/agents/2025-11-30-codex-1414.md similarity index 100% rename from agents/codex-1414.md rename to archives/agents/2025-11-30-codex-1414.md diff --git a/agents/codex-1415.md b/archives/agents/2025-11-30-codex-1415.md similarity index 100% rename from agents/codex-1415.md rename to archives/agents/2025-11-30-codex-1415.md diff --git a/agents/codex-1417.md b/archives/agents/2025-11-30-codex-1417.md similarity index 100% rename from agents/codex-1417.md rename to archives/agents/2025-11-30-codex-1417.md diff --git a/agents/codex-1418.md b/archives/agents/2025-11-30-codex-1418.md similarity index 100% rename from agents/codex-1418.md rename to archives/agents/2025-11-30-codex-1418.md diff --git a/agents/codex-1419.md b/archives/agents/2025-11-30-codex-1419.md similarity index 100% rename from agents/codex-1419.md rename to archives/agents/2025-11-30-codex-1419.md diff --git a/agents/codex-1420.md b/archives/agents/2025-11-30-codex-1420.md similarity index 100% rename from agents/codex-1420.md rename to archives/agents/2025-11-30-codex-1420.md diff --git a/agents/codex-1421.md b/archives/agents/2025-11-30-codex-1421.md similarity index 100% rename from agents/codex-1421.md rename to archives/agents/2025-11-30-codex-1421.md diff --git a/agents/codex-1422.md b/archives/agents/2025-11-30-codex-1422.md similarity index 100% rename from agents/codex-1422.md rename to archives/agents/2025-11-30-codex-1422.md diff --git a/agents/codex-1426.md b/archives/agents/2025-11-30-codex-1426.md similarity index 100% rename from agents/codex-1426.md rename to archives/agents/2025-11-30-codex-1426.md diff --git a/agents/codex-1436.md b/archives/agents/2025-11-30-codex-1436.md similarity index 100% rename from agents/codex-1436.md rename to archives/agents/2025-11-30-codex-1436.md diff --git a/agents/codex-1437.md b/archives/agents/2025-11-30-codex-1437.md similarity index 100% rename from agents/codex-1437.md rename to archives/agents/2025-11-30-codex-1437.md diff --git a/agents/codex-1438.md b/archives/agents/2025-11-30-codex-1438.md similarity index 100% rename from agents/codex-1438.md rename to archives/agents/2025-11-30-codex-1438.md diff --git a/agents/codex-1439.md b/archives/agents/2025-11-30-codex-1439.md similarity index 100% rename from agents/codex-1439.md rename to archives/agents/2025-11-30-codex-1439.md diff --git a/agents/codex-1440.md b/archives/agents/2025-11-30-codex-1440.md similarity index 100% rename from agents/codex-1440.md rename to archives/agents/2025-11-30-codex-1440.md diff --git a/agents/codex-1441.md b/archives/agents/2025-11-30-codex-1441.md similarity index 100% rename from agents/codex-1441.md rename to archives/agents/2025-11-30-codex-1441.md diff --git a/agents/codex-1491.md b/archives/agents/2025-11-30-codex-1491.md similarity index 100% rename from agents/codex-1491.md rename to archives/agents/2025-11-30-codex-1491.md diff --git a/agents/codex-1610.md b/archives/agents/2025-11-30-codex-1610.md similarity index 100% rename from agents/codex-1610.md rename to archives/agents/2025-11-30-codex-1610.md diff --git a/agents/codex-1630.md b/archives/agents/2025-11-30-codex-1630.md similarity index 100% rename from agents/codex-1630.md rename to archives/agents/2025-11-30-codex-1630.md diff --git a/agents/codex-1655.md b/archives/agents/2025-11-30-codex-1655.md similarity index 100% rename from agents/codex-1655.md rename to archives/agents/2025-11-30-codex-1655.md diff --git a/agents/codex-1656.md b/archives/agents/2025-11-30-codex-1656.md similarity index 100% rename from agents/codex-1656.md rename to archives/agents/2025-11-30-codex-1656.md diff --git a/agents/codex-1657.md b/archives/agents/2025-11-30-codex-1657.md similarity index 100% rename from agents/codex-1657.md rename to archives/agents/2025-11-30-codex-1657.md diff --git a/agents/codex-1658.md b/archives/agents/2025-11-30-codex-1658.md similarity index 100% rename from agents/codex-1658.md rename to archives/agents/2025-11-30-codex-1658.md diff --git a/agents/codex-1659.md b/archives/agents/2025-11-30-codex-1659.md similarity index 100% rename from agents/codex-1659.md rename to archives/agents/2025-11-30-codex-1659.md diff --git a/agents/codex-1660.md b/archives/agents/2025-11-30-codex-1660.md similarity index 100% rename from agents/codex-1660.md rename to archives/agents/2025-11-30-codex-1660.md diff --git a/agents/codex-1661.md b/archives/agents/2025-11-30-codex-1661.md similarity index 100% rename from agents/codex-1661.md rename to archives/agents/2025-11-30-codex-1661.md diff --git a/agents/codex-1662.md b/archives/agents/2025-11-30-codex-1662.md similarity index 100% rename from agents/codex-1662.md rename to archives/agents/2025-11-30-codex-1662.md diff --git a/agents/codex-1663.md b/archives/agents/2025-11-30-codex-1663.md similarity index 100% rename from agents/codex-1663.md rename to archives/agents/2025-11-30-codex-1663.md diff --git a/agents/codex-1664.md b/archives/agents/2025-11-30-codex-1664.md similarity index 100% rename from agents/codex-1664.md rename to archives/agents/2025-11-30-codex-1664.md diff --git a/agents/codex-1665.md b/archives/agents/2025-11-30-codex-1665.md similarity index 100% rename from agents/codex-1665.md rename to archives/agents/2025-11-30-codex-1665.md diff --git a/agents/codex-1666.md b/archives/agents/2025-11-30-codex-1666.md similarity index 100% rename from agents/codex-1666.md rename to archives/agents/2025-11-30-codex-1666.md diff --git a/agents/codex-1667.md b/archives/agents/2025-11-30-codex-1667.md similarity index 100% rename from agents/codex-1667.md rename to archives/agents/2025-11-30-codex-1667.md diff --git a/agents/codex-1668.md b/archives/agents/2025-11-30-codex-1668.md similarity index 100% rename from agents/codex-1668.md rename to archives/agents/2025-11-30-codex-1668.md diff --git a/agents/codex-1669.md b/archives/agents/2025-11-30-codex-1669.md similarity index 100% rename from agents/codex-1669.md rename to archives/agents/2025-11-30-codex-1669.md diff --git a/agents/codex-1674.md b/archives/agents/2025-11-30-codex-1674.md similarity index 100% rename from agents/codex-1674.md rename to archives/agents/2025-11-30-codex-1674.md diff --git a/agents/codex-1675.md b/archives/agents/2025-11-30-codex-1675.md similarity index 100% rename from agents/codex-1675.md rename to archives/agents/2025-11-30-codex-1675.md diff --git a/agents/codex-1676.md b/archives/agents/2025-11-30-codex-1676.md similarity index 100% rename from agents/codex-1676.md rename to archives/agents/2025-11-30-codex-1676.md diff --git a/agents/codex-1677.md b/archives/agents/2025-11-30-codex-1677.md similarity index 100% rename from agents/codex-1677.md rename to archives/agents/2025-11-30-codex-1677.md diff --git a/agents/codex-1678.md b/archives/agents/2025-11-30-codex-1678.md similarity index 100% rename from agents/codex-1678.md rename to archives/agents/2025-11-30-codex-1678.md diff --git a/agents/codex-1679.md b/archives/agents/2025-11-30-codex-1679.md similarity index 100% rename from agents/codex-1679.md rename to archives/agents/2025-11-30-codex-1679.md diff --git a/agents/codex-1680.md b/archives/agents/2025-11-30-codex-1680.md similarity index 100% rename from agents/codex-1680.md rename to archives/agents/2025-11-30-codex-1680.md diff --git a/agents/codex-1681.md b/archives/agents/2025-11-30-codex-1681.md similarity index 100% rename from agents/codex-1681.md rename to archives/agents/2025-11-30-codex-1681.md diff --git a/agents/codex-1682.md b/archives/agents/2025-11-30-codex-1682.md similarity index 100% rename from agents/codex-1682.md rename to archives/agents/2025-11-30-codex-1682.md diff --git a/agents/codex-1683.md b/archives/agents/2025-11-30-codex-1683.md similarity index 100% rename from agents/codex-1683.md rename to archives/agents/2025-11-30-codex-1683.md diff --git a/agents/codex-1684.md b/archives/agents/2025-11-30-codex-1684.md similarity index 100% rename from agents/codex-1684.md rename to archives/agents/2025-11-30-codex-1684.md diff --git a/agents/codex-1685.md b/archives/agents/2025-11-30-codex-1685.md similarity index 100% rename from agents/codex-1685.md rename to archives/agents/2025-11-30-codex-1685.md diff --git a/agents/codex-1686.md b/archives/agents/2025-11-30-codex-1686.md similarity index 100% rename from agents/codex-1686.md rename to archives/agents/2025-11-30-codex-1686.md diff --git a/agents/codex-1687.md b/archives/agents/2025-11-30-codex-1687.md similarity index 100% rename from agents/codex-1687.md rename to archives/agents/2025-11-30-codex-1687.md diff --git a/agents/codex-1688.md b/archives/agents/2025-11-30-codex-1688.md similarity index 100% rename from agents/codex-1688.md rename to archives/agents/2025-11-30-codex-1688.md diff --git a/agents/codex-2190.md b/archives/agents/2025-11-30-codex-2190.md similarity index 100% rename from agents/codex-2190.md rename to archives/agents/2025-11-30-codex-2190.md diff --git a/agents/codex-2191.md b/archives/agents/2025-11-30-codex-2191.md similarity index 100% rename from agents/codex-2191.md rename to archives/agents/2025-11-30-codex-2191.md diff --git a/agents/codex-2192.md b/archives/agents/2025-11-30-codex-2192.md similarity index 100% rename from agents/codex-2192.md rename to archives/agents/2025-11-30-codex-2192.md diff --git a/agents/codex-2193.md b/archives/agents/2025-11-30-codex-2193.md similarity index 100% rename from agents/codex-2193.md rename to archives/agents/2025-11-30-codex-2193.md diff --git a/agents/codex-2194.md b/archives/agents/2025-11-30-codex-2194.md similarity index 100% rename from agents/codex-2194.md rename to archives/agents/2025-11-30-codex-2194.md diff --git a/agents/codex-2195.md b/archives/agents/2025-11-30-codex-2195.md similarity index 100% rename from agents/codex-2195.md rename to archives/agents/2025-11-30-codex-2195.md diff --git a/agents/codex-2196.md b/archives/agents/2025-11-30-codex-2196.md similarity index 100% rename from agents/codex-2196.md rename to archives/agents/2025-11-30-codex-2196.md diff --git a/agents/codex-2197.md b/archives/agents/2025-11-30-codex-2197.md similarity index 100% rename from agents/codex-2197.md rename to archives/agents/2025-11-30-codex-2197.md diff --git a/agents/codex-2198.md b/archives/agents/2025-11-30-codex-2198.md similarity index 100% rename from agents/codex-2198.md rename to archives/agents/2025-11-30-codex-2198.md diff --git a/agents/codex-2199.md b/archives/agents/2025-11-30-codex-2199.md similarity index 100% rename from agents/codex-2199.md rename to archives/agents/2025-11-30-codex-2199.md diff --git a/agents/codex-2200.md b/archives/agents/2025-11-30-codex-2200.md similarity index 100% rename from agents/codex-2200.md rename to archives/agents/2025-11-30-codex-2200.md diff --git a/agents/codex-2201.md b/archives/agents/2025-11-30-codex-2201.md similarity index 100% rename from agents/codex-2201.md rename to archives/agents/2025-11-30-codex-2201.md diff --git a/agents/codex-2202.md b/archives/agents/2025-11-30-codex-2202.md similarity index 100% rename from agents/codex-2202.md rename to archives/agents/2025-11-30-codex-2202.md diff --git a/agents/codex-2376.md b/archives/agents/2025-11-30-codex-2376.md similarity index 100% rename from agents/codex-2376.md rename to archives/agents/2025-11-30-codex-2376.md diff --git a/agents/codex-2377.md b/archives/agents/2025-11-30-codex-2377.md similarity index 100% rename from agents/codex-2377.md rename to archives/agents/2025-11-30-codex-2377.md diff --git a/agents/codex-2378.md b/archives/agents/2025-11-30-codex-2378.md similarity index 100% rename from agents/codex-2378.md rename to archives/agents/2025-11-30-codex-2378.md diff --git a/agents/codex-2379.md b/archives/agents/2025-11-30-codex-2379.md similarity index 100% rename from agents/codex-2379.md rename to archives/agents/2025-11-30-codex-2379.md diff --git a/agents/codex-2380.md b/archives/agents/2025-11-30-codex-2380.md similarity index 100% rename from agents/codex-2380.md rename to archives/agents/2025-11-30-codex-2380.md diff --git a/agents/codex-2381.md b/archives/agents/2025-11-30-codex-2381.md similarity index 100% rename from agents/codex-2381.md rename to archives/agents/2025-11-30-codex-2381.md diff --git a/agents/codex-2382.md b/archives/agents/2025-11-30-codex-2382.md similarity index 100% rename from agents/codex-2382.md rename to archives/agents/2025-11-30-codex-2382.md diff --git a/agents/codex-2383.md b/archives/agents/2025-11-30-codex-2383.md similarity index 100% rename from agents/codex-2383.md rename to archives/agents/2025-11-30-codex-2383.md diff --git a/agents/codex-2384.md b/archives/agents/2025-11-30-codex-2384.md similarity index 100% rename from agents/codex-2384.md rename to archives/agents/2025-11-30-codex-2384.md diff --git a/agents/codex-2385.md b/archives/agents/2025-11-30-codex-2385.md similarity index 100% rename from agents/codex-2385.md rename to archives/agents/2025-11-30-codex-2385.md diff --git a/agents/codex-2386.md b/archives/agents/2025-11-30-codex-2386.md similarity index 100% rename from agents/codex-2386.md rename to archives/agents/2025-11-30-codex-2386.md diff --git a/agents/codex-2433.md b/archives/agents/2025-11-30-codex-2433.md similarity index 100% rename from agents/codex-2433.md rename to archives/agents/2025-11-30-codex-2433.md diff --git a/agents/codex-2434.md b/archives/agents/2025-11-30-codex-2434.md similarity index 100% rename from agents/codex-2434.md rename to archives/agents/2025-11-30-codex-2434.md diff --git a/agents/codex-2435.md b/archives/agents/2025-11-30-codex-2435.md similarity index 100% rename from agents/codex-2435.md rename to archives/agents/2025-11-30-codex-2435.md diff --git a/agents/codex-2436.md b/archives/agents/2025-11-30-codex-2436.md similarity index 100% rename from agents/codex-2436.md rename to archives/agents/2025-11-30-codex-2436.md diff --git a/agents/codex-2437.md b/archives/agents/2025-11-30-codex-2437.md similarity index 100% rename from agents/codex-2437.md rename to archives/agents/2025-11-30-codex-2437.md diff --git a/agents/codex-2438.md b/archives/agents/2025-11-30-codex-2438.md similarity index 100% rename from agents/codex-2438.md rename to archives/agents/2025-11-30-codex-2438.md diff --git a/agents/codex-2439.md b/archives/agents/2025-11-30-codex-2439.md similarity index 100% rename from agents/codex-2439.md rename to archives/agents/2025-11-30-codex-2439.md diff --git a/agents/codex-2461.md b/archives/agents/2025-11-30-codex-2461.md similarity index 100% rename from agents/codex-2461.md rename to archives/agents/2025-11-30-codex-2461.md diff --git a/agents/codex-2462.md b/archives/agents/2025-11-30-codex-2462.md similarity index 100% rename from agents/codex-2462.md rename to archives/agents/2025-11-30-codex-2462.md diff --git a/agents/codex-2463.md b/archives/agents/2025-11-30-codex-2463.md similarity index 100% rename from agents/codex-2463.md rename to archives/agents/2025-11-30-codex-2463.md diff --git a/agents/codex-2464.md b/archives/agents/2025-11-30-codex-2464.md similarity index 100% rename from agents/codex-2464.md rename to archives/agents/2025-11-30-codex-2464.md diff --git a/agents/codex-2465.md b/archives/agents/2025-11-30-codex-2465.md similarity index 100% rename from agents/codex-2465.md rename to archives/agents/2025-11-30-codex-2465.md diff --git a/agents/codex-2466.md b/archives/agents/2025-11-30-codex-2466.md similarity index 100% rename from agents/codex-2466.md rename to archives/agents/2025-11-30-codex-2466.md diff --git a/agents/codex-2492.md b/archives/agents/2025-11-30-codex-2492.md similarity index 100% rename from agents/codex-2492.md rename to archives/agents/2025-11-30-codex-2492.md diff --git a/agents/codex-2493.md b/archives/agents/2025-11-30-codex-2493.md similarity index 100% rename from agents/codex-2493.md rename to archives/agents/2025-11-30-codex-2493.md diff --git a/agents/codex-2494.md b/archives/agents/2025-11-30-codex-2494.md similarity index 100% rename from agents/codex-2494.md rename to archives/agents/2025-11-30-codex-2494.md diff --git a/agents/codex-2495.md b/archives/agents/2025-11-30-codex-2495.md similarity index 100% rename from agents/codex-2495.md rename to archives/agents/2025-11-30-codex-2495.md diff --git a/agents/codex-2496.md b/archives/agents/2025-11-30-codex-2496.md similarity index 100% rename from agents/codex-2496.md rename to archives/agents/2025-11-30-codex-2496.md diff --git a/agents/codex-2497.md b/archives/agents/2025-11-30-codex-2497.md similarity index 100% rename from agents/codex-2497.md rename to archives/agents/2025-11-30-codex-2497.md diff --git a/agents/codex-2498.md b/archives/agents/2025-11-30-codex-2498.md similarity index 100% rename from agents/codex-2498.md rename to archives/agents/2025-11-30-codex-2498.md diff --git a/agents/codex-2523.md b/archives/agents/2025-11-30-codex-2523.md similarity index 100% rename from agents/codex-2523.md rename to archives/agents/2025-11-30-codex-2523.md diff --git a/agents/codex-2524.md b/archives/agents/2025-11-30-codex-2524.md similarity index 100% rename from agents/codex-2524.md rename to archives/agents/2025-11-30-codex-2524.md diff --git a/agents/codex-2525.md b/archives/agents/2025-11-30-codex-2525.md similarity index 100% rename from agents/codex-2525.md rename to archives/agents/2025-11-30-codex-2525.md diff --git a/agents/codex-2526.md b/archives/agents/2025-11-30-codex-2526.md similarity index 100% rename from agents/codex-2526.md rename to archives/agents/2025-11-30-codex-2526.md diff --git a/agents/codex-2527.md b/archives/agents/2025-11-30-codex-2527.md similarity index 100% rename from agents/codex-2527.md rename to archives/agents/2025-11-30-codex-2527.md diff --git a/agents/codex-2528.md b/archives/agents/2025-11-30-codex-2528.md similarity index 100% rename from agents/codex-2528.md rename to archives/agents/2025-11-30-codex-2528.md diff --git a/agents/codex-2529.md b/archives/agents/2025-11-30-codex-2529.md similarity index 100% rename from agents/codex-2529.md rename to archives/agents/2025-11-30-codex-2529.md diff --git a/agents/codex-2560.md b/archives/agents/2025-11-30-codex-2560.md similarity index 100% rename from agents/codex-2560.md rename to archives/agents/2025-11-30-codex-2560.md diff --git a/agents/codex-2561.md b/archives/agents/2025-11-30-codex-2561.md similarity index 100% rename from agents/codex-2561.md rename to archives/agents/2025-11-30-codex-2561.md diff --git a/agents/codex-2562.md b/archives/agents/2025-11-30-codex-2562.md similarity index 100% rename from agents/codex-2562.md rename to archives/agents/2025-11-30-codex-2562.md diff --git a/agents/codex-2563.md b/archives/agents/2025-11-30-codex-2563.md similarity index 100% rename from agents/codex-2563.md rename to archives/agents/2025-11-30-codex-2563.md diff --git a/agents/codex-2564.md b/archives/agents/2025-11-30-codex-2564.md similarity index 100% rename from agents/codex-2564.md rename to archives/agents/2025-11-30-codex-2564.md diff --git a/agents/codex-2565.md b/archives/agents/2025-11-30-codex-2565.md similarity index 100% rename from agents/codex-2565.md rename to archives/agents/2025-11-30-codex-2565.md diff --git a/agents/codex-2566.md b/archives/agents/2025-11-30-codex-2566.md similarity index 100% rename from agents/codex-2566.md rename to archives/agents/2025-11-30-codex-2566.md diff --git a/agents/codex-2567.md b/archives/agents/2025-11-30-codex-2567.md similarity index 100% rename from agents/codex-2567.md rename to archives/agents/2025-11-30-codex-2567.md diff --git a/agents/codex-2609.md b/archives/agents/2025-11-30-codex-2609.md similarity index 100% rename from agents/codex-2609.md rename to archives/agents/2025-11-30-codex-2609.md diff --git a/agents/codex-2610.md b/archives/agents/2025-11-30-codex-2610.md similarity index 100% rename from agents/codex-2610.md rename to archives/agents/2025-11-30-codex-2610.md diff --git a/agents/codex-2611.md b/archives/agents/2025-11-30-codex-2611.md similarity index 100% rename from agents/codex-2611.md rename to archives/agents/2025-11-30-codex-2611.md diff --git a/agents/codex-2612.md b/archives/agents/2025-11-30-codex-2612.md similarity index 100% rename from agents/codex-2612.md rename to archives/agents/2025-11-30-codex-2612.md diff --git a/agents/codex-2614.md b/archives/agents/2025-11-30-codex-2614.md similarity index 100% rename from agents/codex-2614.md rename to archives/agents/2025-11-30-codex-2614.md diff --git a/agents/codex-2615.md b/archives/agents/2025-11-30-codex-2615.md similarity index 100% rename from agents/codex-2615.md rename to archives/agents/2025-11-30-codex-2615.md diff --git a/agents/codex-2616.md b/archives/agents/2025-11-30-codex-2616.md similarity index 100% rename from agents/codex-2616.md rename to archives/agents/2025-11-30-codex-2616.md diff --git a/agents/codex-2617.md b/archives/agents/2025-11-30-codex-2617.md similarity index 100% rename from agents/codex-2617.md rename to archives/agents/2025-11-30-codex-2617.md diff --git a/agents/codex-2618.md b/archives/agents/2025-11-30-codex-2618.md similarity index 100% rename from agents/codex-2618.md rename to archives/agents/2025-11-30-codex-2618.md diff --git a/agents/codex-2649.md b/archives/agents/2025-11-30-codex-2649.md similarity index 100% rename from agents/codex-2649.md rename to archives/agents/2025-11-30-codex-2649.md diff --git a/agents/codex-2650.md b/archives/agents/2025-11-30-codex-2650.md similarity index 100% rename from agents/codex-2650.md rename to archives/agents/2025-11-30-codex-2650.md diff --git a/agents/codex-2651.md b/archives/agents/2025-11-30-codex-2651.md similarity index 100% rename from agents/codex-2651.md rename to archives/agents/2025-11-30-codex-2651.md diff --git a/agents/codex-2652.md b/archives/agents/2025-11-30-codex-2652.md similarity index 100% rename from agents/codex-2652.md rename to archives/agents/2025-11-30-codex-2652.md diff --git a/agents/codex-2653.md b/archives/agents/2025-11-30-codex-2653.md similarity index 100% rename from agents/codex-2653.md rename to archives/agents/2025-11-30-codex-2653.md diff --git a/agents/codex-2654.md b/archives/agents/2025-11-30-codex-2654.md similarity index 100% rename from agents/codex-2654.md rename to archives/agents/2025-11-30-codex-2654.md diff --git a/agents/codex-2655.md b/archives/agents/2025-11-30-codex-2655.md similarity index 100% rename from agents/codex-2655.md rename to archives/agents/2025-11-30-codex-2655.md diff --git a/agents/codex-2656.md b/archives/agents/2025-11-30-codex-2656.md similarity index 100% rename from agents/codex-2656.md rename to archives/agents/2025-11-30-codex-2656.md diff --git a/agents/codex-2680.md b/archives/agents/2025-11-30-codex-2680.md similarity index 100% rename from agents/codex-2680.md rename to archives/agents/2025-11-30-codex-2680.md diff --git a/agents/codex-2681.md b/archives/agents/2025-11-30-codex-2681.md similarity index 100% rename from agents/codex-2681.md rename to archives/agents/2025-11-30-codex-2681.md diff --git a/agents/codex-2683.md b/archives/agents/2025-11-30-codex-2683.md similarity index 100% rename from agents/codex-2683.md rename to archives/agents/2025-11-30-codex-2683.md diff --git a/agents/codex-2685.md b/archives/agents/2025-11-30-codex-2685.md similarity index 100% rename from agents/codex-2685.md rename to archives/agents/2025-11-30-codex-2685.md diff --git a/agents/codex-2686.md b/archives/agents/2025-11-30-codex-2686.md similarity index 100% rename from agents/codex-2686.md rename to archives/agents/2025-11-30-codex-2686.md diff --git a/agents/codex-2687.md b/archives/agents/2025-11-30-codex-2687.md similarity index 100% rename from agents/codex-2687.md rename to archives/agents/2025-11-30-codex-2687.md diff --git a/agents/codex-2688.md b/archives/agents/2025-11-30-codex-2688.md similarity index 100% rename from agents/codex-2688.md rename to archives/agents/2025-11-30-codex-2688.md diff --git a/agents/codex-2718.md b/archives/agents/2025-11-30-codex-2718.md similarity index 100% rename from agents/codex-2718.md rename to archives/agents/2025-11-30-codex-2718.md diff --git a/agents/codex-2719.md b/archives/agents/2025-11-30-codex-2719.md similarity index 100% rename from agents/codex-2719.md rename to archives/agents/2025-11-30-codex-2719.md diff --git a/agents/codex-2720.md b/archives/agents/2025-11-30-codex-2720.md similarity index 100% rename from agents/codex-2720.md rename to archives/agents/2025-11-30-codex-2720.md diff --git a/agents/codex-2721.md b/archives/agents/2025-11-30-codex-2721.md similarity index 100% rename from agents/codex-2721.md rename to archives/agents/2025-11-30-codex-2721.md diff --git a/agents/codex-2722.md b/archives/agents/2025-11-30-codex-2722.md similarity index 100% rename from agents/codex-2722.md rename to archives/agents/2025-11-30-codex-2722.md diff --git a/agents/codex-2723.md b/archives/agents/2025-11-30-codex-2723.md similarity index 100% rename from agents/codex-2723.md rename to archives/agents/2025-11-30-codex-2723.md diff --git a/agents/codex-2724.md b/archives/agents/2025-11-30-codex-2724.md similarity index 100% rename from agents/codex-2724.md rename to archives/agents/2025-11-30-codex-2724.md diff --git a/agents/codex-2727.md b/archives/agents/2025-11-30-codex-2727.md similarity index 100% rename from agents/codex-2727.md rename to archives/agents/2025-11-30-codex-2727.md diff --git a/agents/codex-2728.md b/archives/agents/2025-11-30-codex-2728.md similarity index 100% rename from agents/codex-2728.md rename to archives/agents/2025-11-30-codex-2728.md diff --git a/agents/codex-2730.md b/archives/agents/2025-11-30-codex-2730.md similarity index 100% rename from agents/codex-2730.md rename to archives/agents/2025-11-30-codex-2730.md diff --git a/agents/codex-2731.md b/archives/agents/2025-11-30-codex-2731.md similarity index 100% rename from agents/codex-2731.md rename to archives/agents/2025-11-30-codex-2731.md diff --git a/agents/codex-2732.md b/archives/agents/2025-11-30-codex-2732.md similarity index 100% rename from agents/codex-2732.md rename to archives/agents/2025-11-30-codex-2732.md diff --git a/agents/codex-2733.md b/archives/agents/2025-11-30-codex-2733.md similarity index 100% rename from agents/codex-2733.md rename to archives/agents/2025-11-30-codex-2733.md diff --git a/agents/codex-2736.md b/archives/agents/2025-11-30-codex-2736.md similarity index 100% rename from agents/codex-2736.md rename to archives/agents/2025-11-30-codex-2736.md diff --git a/agents/codex-2739.md b/archives/agents/2025-11-30-codex-2739.md similarity index 100% rename from agents/codex-2739.md rename to archives/agents/2025-11-30-codex-2739.md diff --git a/agents/codex-2740.md b/archives/agents/2025-11-30-codex-2740.md similarity index 100% rename from agents/codex-2740.md rename to archives/agents/2025-11-30-codex-2740.md diff --git a/agents/codex-2801.md b/archives/agents/2025-11-30-codex-2801.md similarity index 100% rename from agents/codex-2801.md rename to archives/agents/2025-11-30-codex-2801.md diff --git a/agents/codex-2802.md b/archives/agents/2025-11-30-codex-2802.md similarity index 100% rename from agents/codex-2802.md rename to archives/agents/2025-11-30-codex-2802.md diff --git a/agents/codex-2811.md b/archives/agents/2025-11-30-codex-2811.md similarity index 100% rename from agents/codex-2811.md rename to archives/agents/2025-11-30-codex-2811.md diff --git a/agents/codex-2812.md b/archives/agents/2025-11-30-codex-2812.md similarity index 100% rename from agents/codex-2812.md rename to archives/agents/2025-11-30-codex-2812.md diff --git a/agents/codex-2813.md b/archives/agents/2025-11-30-codex-2813.md similarity index 100% rename from agents/codex-2813.md rename to archives/agents/2025-11-30-codex-2813.md diff --git a/agents/codex-2814.md b/archives/agents/2025-11-30-codex-2814.md similarity index 100% rename from agents/codex-2814.md rename to archives/agents/2025-11-30-codex-2814.md diff --git a/agents/codex-2815.md b/archives/agents/2025-11-30-codex-2815.md similarity index 100% rename from agents/codex-2815.md rename to archives/agents/2025-11-30-codex-2815.md diff --git a/agents/codex-2816.md b/archives/agents/2025-11-30-codex-2816.md similarity index 100% rename from agents/codex-2816.md rename to archives/agents/2025-11-30-codex-2816.md diff --git a/agents/codex-2820.md b/archives/agents/2025-11-30-codex-2820.md similarity index 100% rename from agents/codex-2820.md rename to archives/agents/2025-11-30-codex-2820.md diff --git a/agents/codex-2821.md b/archives/agents/2025-11-30-codex-2821.md similarity index 100% rename from agents/codex-2821.md rename to archives/agents/2025-11-30-codex-2821.md diff --git a/agents/codex-2822.md b/archives/agents/2025-11-30-codex-2822.md similarity index 100% rename from agents/codex-2822.md rename to archives/agents/2025-11-30-codex-2822.md diff --git a/agents/codex-2823.md b/archives/agents/2025-11-30-codex-2823.md similarity index 100% rename from agents/codex-2823.md rename to archives/agents/2025-11-30-codex-2823.md diff --git a/agents/codex-2846.md b/archives/agents/2025-11-30-codex-2846.md similarity index 100% rename from agents/codex-2846.md rename to archives/agents/2025-11-30-codex-2846.md diff --git a/agents/codex-2847.md b/archives/agents/2025-11-30-codex-2847.md similarity index 100% rename from agents/codex-2847.md rename to archives/agents/2025-11-30-codex-2847.md diff --git a/agents/codex-2848.md b/archives/agents/2025-11-30-codex-2848.md similarity index 100% rename from agents/codex-2848.md rename to archives/agents/2025-11-30-codex-2848.md diff --git a/agents/codex-2849.md b/archives/agents/2025-11-30-codex-2849.md similarity index 100% rename from agents/codex-2849.md rename to archives/agents/2025-11-30-codex-2849.md diff --git a/agents/codex-2850.md b/archives/agents/2025-11-30-codex-2850.md similarity index 100% rename from agents/codex-2850.md rename to archives/agents/2025-11-30-codex-2850.md diff --git a/agents/codex-2851.md b/archives/agents/2025-11-30-codex-2851.md similarity index 100% rename from agents/codex-2851.md rename to archives/agents/2025-11-30-codex-2851.md diff --git a/agents/codex-2853.md b/archives/agents/2025-11-30-codex-2853.md similarity index 100% rename from agents/codex-2853.md rename to archives/agents/2025-11-30-codex-2853.md diff --git a/agents/codex-2854.md b/archives/agents/2025-11-30-codex-2854.md similarity index 100% rename from agents/codex-2854.md rename to archives/agents/2025-11-30-codex-2854.md diff --git a/agents/codex-2878.md b/archives/agents/2025-11-30-codex-2878.md similarity index 100% rename from agents/codex-2878.md rename to archives/agents/2025-11-30-codex-2878.md diff --git a/agents/codex-2882.md b/archives/agents/2025-11-30-codex-2882.md similarity index 100% rename from agents/codex-2882.md rename to archives/agents/2025-11-30-codex-2882.md diff --git a/agents/codex-2883.md b/archives/agents/2025-11-30-codex-2883.md similarity index 100% rename from agents/codex-2883.md rename to archives/agents/2025-11-30-codex-2883.md diff --git a/agents/codex-2884.md b/archives/agents/2025-11-30-codex-2884.md similarity index 100% rename from agents/codex-2884.md rename to archives/agents/2025-11-30-codex-2884.md diff --git a/agents/codex-2885.md b/archives/agents/2025-11-30-codex-2885.md similarity index 100% rename from agents/codex-2885.md rename to archives/agents/2025-11-30-codex-2885.md diff --git a/agents/codex-2886.md b/archives/agents/2025-11-30-codex-2886.md similarity index 100% rename from agents/codex-2886.md rename to archives/agents/2025-11-30-codex-2886.md diff --git a/agents/codex-2913.md b/archives/agents/2025-11-30-codex-2913.md similarity index 100% rename from agents/codex-2913.md rename to archives/agents/2025-11-30-codex-2913.md diff --git a/agents/codex-2914.md b/archives/agents/2025-11-30-codex-2914.md similarity index 100% rename from agents/codex-2914.md rename to archives/agents/2025-11-30-codex-2914.md diff --git a/agents/codex-2915.md b/archives/agents/2025-11-30-codex-2915.md similarity index 100% rename from agents/codex-2915.md rename to archives/agents/2025-11-30-codex-2915.md diff --git a/agents/codex-2916.md b/archives/agents/2025-11-30-codex-2916.md similarity index 100% rename from agents/codex-2916.md rename to archives/agents/2025-11-30-codex-2916.md diff --git a/agents/codex-2917.md b/archives/agents/2025-11-30-codex-2917.md similarity index 100% rename from agents/codex-2917.md rename to archives/agents/2025-11-30-codex-2917.md diff --git a/agents/codex-2918.md b/archives/agents/2025-11-30-codex-2918.md similarity index 100% rename from agents/codex-2918.md rename to archives/agents/2025-11-30-codex-2918.md diff --git a/agents/codex-2919.md b/archives/agents/2025-11-30-codex-2919.md similarity index 100% rename from agents/codex-2919.md rename to archives/agents/2025-11-30-codex-2919.md diff --git a/agents/codex-2940.md b/archives/agents/2025-11-30-codex-2940.md similarity index 100% rename from agents/codex-2940.md rename to archives/agents/2025-11-30-codex-2940.md diff --git a/agents/codex-2942.md b/archives/agents/2025-11-30-codex-2942.md similarity index 100% rename from agents/codex-2942.md rename to archives/agents/2025-11-30-codex-2942.md diff --git a/agents/codex-2945.md b/archives/agents/2025-11-30-codex-2945.md similarity index 100% rename from agents/codex-2945.md rename to archives/agents/2025-11-30-codex-2945.md diff --git a/agents/codex-2955.md b/archives/agents/2025-11-30-codex-2955.md similarity index 100% rename from agents/codex-2955.md rename to archives/agents/2025-11-30-codex-2955.md diff --git a/agents/codex-2957.md b/archives/agents/2025-11-30-codex-2957.md similarity index 100% rename from agents/codex-2957.md rename to archives/agents/2025-11-30-codex-2957.md diff --git a/agents/codex-2958.md b/archives/agents/2025-11-30-codex-2958.md similarity index 100% rename from agents/codex-2958.md rename to archives/agents/2025-11-30-codex-2958.md diff --git a/agents/codex-2959.md b/archives/agents/2025-11-30-codex-2959.md similarity index 100% rename from agents/codex-2959.md rename to archives/agents/2025-11-30-codex-2959.md diff --git a/agents/codex-2960.md b/archives/agents/2025-11-30-codex-2960.md similarity index 100% rename from agents/codex-2960.md rename to archives/agents/2025-11-30-codex-2960.md diff --git a/agents/codex-2961.md b/archives/agents/2025-11-30-codex-2961.md similarity index 100% rename from agents/codex-2961.md rename to archives/agents/2025-11-30-codex-2961.md diff --git a/agents/codex-2962.md b/archives/agents/2025-11-30-codex-2962.md similarity index 100% rename from agents/codex-2962.md rename to archives/agents/2025-11-30-codex-2962.md diff --git a/agents/codex-2963.md b/archives/agents/2025-11-30-codex-2963.md similarity index 100% rename from agents/codex-2963.md rename to archives/agents/2025-11-30-codex-2963.md diff --git a/agents/codex-2964.md b/archives/agents/2025-11-30-codex-2964.md similarity index 100% rename from agents/codex-2964.md rename to archives/agents/2025-11-30-codex-2964.md diff --git a/agents/codex-2994.md b/archives/agents/2025-11-30-codex-2994.md similarity index 100% rename from agents/codex-2994.md rename to archives/agents/2025-11-30-codex-2994.md diff --git a/agents/codex-2995.md b/archives/agents/2025-11-30-codex-2995.md similarity index 100% rename from agents/codex-2995.md rename to archives/agents/2025-11-30-codex-2995.md diff --git a/agents/codex-2996.md b/archives/agents/2025-11-30-codex-2996.md similarity index 100% rename from agents/codex-2996.md rename to archives/agents/2025-11-30-codex-2996.md diff --git a/agents/codex-2997.md b/archives/agents/2025-11-30-codex-2997.md similarity index 100% rename from agents/codex-2997.md rename to archives/agents/2025-11-30-codex-2997.md diff --git a/agents/codex-2998.md b/archives/agents/2025-11-30-codex-2998.md similarity index 100% rename from agents/codex-2998.md rename to archives/agents/2025-11-30-codex-2998.md diff --git a/agents/codex-3006.md b/archives/agents/2025-11-30-codex-3006.md similarity index 100% rename from agents/codex-3006.md rename to archives/agents/2025-11-30-codex-3006.md diff --git a/agents/codex-3007.md b/archives/agents/2025-11-30-codex-3007.md similarity index 100% rename from agents/codex-3007.md rename to archives/agents/2025-11-30-codex-3007.md diff --git a/agents/codex-3008.md b/archives/agents/2025-11-30-codex-3008.md similarity index 100% rename from agents/codex-3008.md rename to archives/agents/2025-11-30-codex-3008.md diff --git a/agents/codex-3009.md b/archives/agents/2025-11-30-codex-3009.md similarity index 100% rename from agents/codex-3009.md rename to archives/agents/2025-11-30-codex-3009.md diff --git a/agents/codex-3010.md b/archives/agents/2025-11-30-codex-3010.md similarity index 100% rename from agents/codex-3010.md rename to archives/agents/2025-11-30-codex-3010.md diff --git a/agents/codex-3011.md b/archives/agents/2025-11-30-codex-3011.md similarity index 100% rename from agents/codex-3011.md rename to archives/agents/2025-11-30-codex-3011.md diff --git a/agents/codex-3013.md b/archives/agents/2025-11-30-codex-3013.md similarity index 100% rename from agents/codex-3013.md rename to archives/agents/2025-11-30-codex-3013.md diff --git a/agents/codex-3017.md b/archives/agents/2025-11-30-codex-3017.md similarity index 100% rename from agents/codex-3017.md rename to archives/agents/2025-11-30-codex-3017.md diff --git a/agents/codex-3019.md b/archives/agents/2025-11-30-codex-3019.md similarity index 100% rename from agents/codex-3019.md rename to archives/agents/2025-11-30-codex-3019.md diff --git a/agents/codex-3038.md b/archives/agents/2025-11-30-codex-3038.md similarity index 100% rename from agents/codex-3038.md rename to archives/agents/2025-11-30-codex-3038.md diff --git a/agents/codex-3039.md b/archives/agents/2025-11-30-codex-3039.md similarity index 100% rename from agents/codex-3039.md rename to archives/agents/2025-11-30-codex-3039.md diff --git a/agents/codex-3040.md b/archives/agents/2025-11-30-codex-3040.md similarity index 100% rename from agents/codex-3040.md rename to archives/agents/2025-11-30-codex-3040.md diff --git a/agents/codex-3041.md b/archives/agents/2025-11-30-codex-3041.md similarity index 100% rename from agents/codex-3041.md rename to archives/agents/2025-11-30-codex-3041.md diff --git a/agents/codex-3042.md b/archives/agents/2025-11-30-codex-3042.md similarity index 100% rename from agents/codex-3042.md rename to archives/agents/2025-11-30-codex-3042.md diff --git a/agents/codex-3053.md b/archives/agents/2025-11-30-codex-3053.md similarity index 100% rename from agents/codex-3053.md rename to archives/agents/2025-11-30-codex-3053.md diff --git a/agents/codex-3054.md b/archives/agents/2025-11-30-codex-3054.md similarity index 100% rename from agents/codex-3054.md rename to archives/agents/2025-11-30-codex-3054.md diff --git a/agents/codex-3055.md b/archives/agents/2025-11-30-codex-3055.md similarity index 100% rename from agents/codex-3055.md rename to archives/agents/2025-11-30-codex-3055.md diff --git a/agents/codex-3056.md b/archives/agents/2025-11-30-codex-3056.md similarity index 100% rename from agents/codex-3056.md rename to archives/agents/2025-11-30-codex-3056.md diff --git a/agents/codex-3057.md b/archives/agents/2025-11-30-codex-3057.md similarity index 100% rename from agents/codex-3057.md rename to archives/agents/2025-11-30-codex-3057.md diff --git a/agents/codex-3058.md b/archives/agents/2025-11-30-codex-3058.md similarity index 100% rename from agents/codex-3058.md rename to archives/agents/2025-11-30-codex-3058.md diff --git a/agents/codex-3073.md b/archives/agents/2025-11-30-codex-3073.md similarity index 100% rename from agents/codex-3073.md rename to archives/agents/2025-11-30-codex-3073.md diff --git a/agents/codex-3074.md b/archives/agents/2025-11-30-codex-3074.md similarity index 100% rename from agents/codex-3074.md rename to archives/agents/2025-11-30-codex-3074.md diff --git a/agents/codex-3075.md b/archives/agents/2025-11-30-codex-3075.md similarity index 100% rename from agents/codex-3075.md rename to archives/agents/2025-11-30-codex-3075.md diff --git a/agents/codex-3076.md b/archives/agents/2025-11-30-codex-3076.md similarity index 100% rename from agents/codex-3076.md rename to archives/agents/2025-11-30-codex-3076.md diff --git a/agents/codex-3077.md b/archives/agents/2025-11-30-codex-3077.md similarity index 100% rename from agents/codex-3077.md rename to archives/agents/2025-11-30-codex-3077.md diff --git a/agents/codex-3078.md b/archives/agents/2025-11-30-codex-3078.md similarity index 100% rename from agents/codex-3078.md rename to archives/agents/2025-11-30-codex-3078.md diff --git a/agents/codex-3085.md b/archives/agents/2025-11-30-codex-3085.md similarity index 100% rename from agents/codex-3085.md rename to archives/agents/2025-11-30-codex-3085.md diff --git a/agents/codex-3092.md b/archives/agents/2025-11-30-codex-3092.md similarity index 100% rename from agents/codex-3092.md rename to archives/agents/2025-11-30-codex-3092.md diff --git a/agents/codex-3093.md b/archives/agents/2025-11-30-codex-3093.md similarity index 100% rename from agents/codex-3093.md rename to archives/agents/2025-11-30-codex-3093.md diff --git a/agents/codex-3094.md b/archives/agents/2025-11-30-codex-3094.md similarity index 100% rename from agents/codex-3094.md rename to archives/agents/2025-11-30-codex-3094.md diff --git a/agents/codex-3095.md b/archives/agents/2025-11-30-codex-3095.md similarity index 100% rename from agents/codex-3095.md rename to archives/agents/2025-11-30-codex-3095.md diff --git a/agents/codex-3096.md b/archives/agents/2025-11-30-codex-3096.md similarity index 100% rename from agents/codex-3096.md rename to archives/agents/2025-11-30-codex-3096.md diff --git a/agents/codex-3098.md b/archives/agents/2025-11-30-codex-3098.md similarity index 100% rename from agents/codex-3098.md rename to archives/agents/2025-11-30-codex-3098.md diff --git a/agents/codex-3099.md b/archives/agents/2025-11-30-codex-3099.md similarity index 100% rename from agents/codex-3099.md rename to archives/agents/2025-11-30-codex-3099.md diff --git a/agents/codex-3100.md b/archives/agents/2025-11-30-codex-3100.md similarity index 100% rename from agents/codex-3100.md rename to archives/agents/2025-11-30-codex-3100.md diff --git a/agents/codex-3101.md b/archives/agents/2025-11-30-codex-3101.md similarity index 100% rename from agents/codex-3101.md rename to archives/agents/2025-11-30-codex-3101.md diff --git a/agents/codex-3118.md b/archives/agents/2025-11-30-codex-3118.md similarity index 100% rename from agents/codex-3118.md rename to archives/agents/2025-11-30-codex-3118.md diff --git a/agents/codex-3119.md b/archives/agents/2025-11-30-codex-3119.md similarity index 100% rename from agents/codex-3119.md rename to archives/agents/2025-11-30-codex-3119.md diff --git a/agents/codex-3122.md b/archives/agents/2025-11-30-codex-3122.md similarity index 100% rename from agents/codex-3122.md rename to archives/agents/2025-11-30-codex-3122.md diff --git a/agents/codex-3126.md b/archives/agents/2025-11-30-codex-3126.md similarity index 100% rename from agents/codex-3126.md rename to archives/agents/2025-11-30-codex-3126.md diff --git a/agents/codex-3129.md b/archives/agents/2025-11-30-codex-3129.md similarity index 100% rename from agents/codex-3129.md rename to archives/agents/2025-11-30-codex-3129.md diff --git a/agents/codex-3131.md b/archives/agents/2025-11-30-codex-3131.md similarity index 100% rename from agents/codex-3131.md rename to archives/agents/2025-11-30-codex-3131.md diff --git a/agents/codex-3135.md b/archives/agents/2025-11-30-codex-3135.md similarity index 100% rename from agents/codex-3135.md rename to archives/agents/2025-11-30-codex-3135.md diff --git a/agents/codex-3138.md b/archives/agents/2025-11-30-codex-3138.md similarity index 100% rename from agents/codex-3138.md rename to archives/agents/2025-11-30-codex-3138.md diff --git a/agents/codex-3139.md b/archives/agents/2025-11-30-codex-3139.md similarity index 100% rename from agents/codex-3139.md rename to archives/agents/2025-11-30-codex-3139.md diff --git a/agents/codex-3144.md b/archives/agents/2025-11-30-codex-3144.md similarity index 100% rename from agents/codex-3144.md rename to archives/agents/2025-11-30-codex-3144.md diff --git a/agents/codex-3149.md b/archives/agents/2025-11-30-codex-3149.md similarity index 100% rename from agents/codex-3149.md rename to archives/agents/2025-11-30-codex-3149.md diff --git a/agents/codex-3150.md b/archives/agents/2025-11-30-codex-3150.md similarity index 100% rename from agents/codex-3150.md rename to archives/agents/2025-11-30-codex-3150.md diff --git a/agents/codex-3154.md b/archives/agents/2025-11-30-codex-3154.md similarity index 100% rename from agents/codex-3154.md rename to archives/agents/2025-11-30-codex-3154.md diff --git a/agents/codex-3158.md b/archives/agents/2025-11-30-codex-3158.md similarity index 100% rename from agents/codex-3158.md rename to archives/agents/2025-11-30-codex-3158.md diff --git a/agents/codex-3160.md b/archives/agents/2025-11-30-codex-3160.md similarity index 100% rename from agents/codex-3160.md rename to archives/agents/2025-11-30-codex-3160.md diff --git a/agents/codex-3166.md b/archives/agents/2025-11-30-codex-3166.md similarity index 100% rename from agents/codex-3166.md rename to archives/agents/2025-11-30-codex-3166.md diff --git a/agents/codex-3171.md b/archives/agents/2025-11-30-codex-3171.md similarity index 100% rename from agents/codex-3171.md rename to archives/agents/2025-11-30-codex-3171.md diff --git a/agents/codex-3176.md b/archives/agents/2025-11-30-codex-3176.md similarity index 100% rename from agents/codex-3176.md rename to archives/agents/2025-11-30-codex-3176.md diff --git a/agents/codex-3179.md b/archives/agents/2025-11-30-codex-3179.md similarity index 100% rename from agents/codex-3179.md rename to archives/agents/2025-11-30-codex-3179.md diff --git a/agents/codex-3183.md b/archives/agents/2025-11-30-codex-3183.md similarity index 100% rename from agents/codex-3183.md rename to archives/agents/2025-11-30-codex-3183.md diff --git a/agents/codex-3190.md b/archives/agents/2025-11-30-codex-3190.md similarity index 100% rename from agents/codex-3190.md rename to archives/agents/2025-11-30-codex-3190.md diff --git a/agents/codex-3193.md b/archives/agents/2025-11-30-codex-3193.md similarity index 100% rename from agents/codex-3193.md rename to archives/agents/2025-11-30-codex-3193.md diff --git a/agents/codex-3196.md b/archives/agents/2025-11-30-codex-3196.md similarity index 100% rename from agents/codex-3196.md rename to archives/agents/2025-11-30-codex-3196.md diff --git a/agents/codex-3203.md b/archives/agents/2025-11-30-codex-3203.md similarity index 100% rename from agents/codex-3203.md rename to archives/agents/2025-11-30-codex-3203.md diff --git a/agents/codex-3209.md b/archives/agents/2025-11-30-codex-3209.md similarity index 100% rename from agents/codex-3209.md rename to archives/agents/2025-11-30-codex-3209.md diff --git a/agents/codex-3213.md b/archives/agents/2025-11-30-codex-3213.md similarity index 100% rename from agents/codex-3213.md rename to archives/agents/2025-11-30-codex-3213.md diff --git a/agents/codex-3216.md b/archives/agents/2025-11-30-codex-3216.md similarity index 100% rename from agents/codex-3216.md rename to archives/agents/2025-11-30-codex-3216.md diff --git a/agents/codex-3218.md b/archives/agents/2025-11-30-codex-3218.md similarity index 100% rename from agents/codex-3218.md rename to archives/agents/2025-11-30-codex-3218.md diff --git a/agents/codex-3219.md b/archives/agents/2025-11-30-codex-3219.md similarity index 100% rename from agents/codex-3219.md rename to archives/agents/2025-11-30-codex-3219.md diff --git a/agents/codex-3225.md b/archives/agents/2025-11-30-codex-3225.md similarity index 100% rename from agents/codex-3225.md rename to archives/agents/2025-11-30-codex-3225.md diff --git a/agents/codex-3227.md b/archives/agents/2025-11-30-codex-3227.md similarity index 100% rename from agents/codex-3227.md rename to archives/agents/2025-11-30-codex-3227.md diff --git a/agents/codex-3228.md b/archives/agents/2025-11-30-codex-3228.md similarity index 100% rename from agents/codex-3228.md rename to archives/agents/2025-11-30-codex-3228.md diff --git a/agents/codex-3233.md b/archives/agents/2025-11-30-codex-3233.md similarity index 100% rename from agents/codex-3233.md rename to archives/agents/2025-11-30-codex-3233.md diff --git a/agents/codex-3235.md b/archives/agents/2025-11-30-codex-3235.md similarity index 100% rename from agents/codex-3235.md rename to archives/agents/2025-11-30-codex-3235.md diff --git a/agents/codex-3237.md b/archives/agents/2025-11-30-codex-3237.md similarity index 100% rename from agents/codex-3237.md rename to archives/agents/2025-11-30-codex-3237.md diff --git a/agents/codex-3238.md b/archives/agents/2025-11-30-codex-3238.md similarity index 100% rename from agents/codex-3238.md rename to archives/agents/2025-11-30-codex-3238.md diff --git a/agents/codex-3249.md b/archives/agents/2025-11-30-codex-3249.md similarity index 100% rename from agents/codex-3249.md rename to archives/agents/2025-11-30-codex-3249.md diff --git a/agents/codex-3253.md b/archives/agents/2025-11-30-codex-3253.md similarity index 100% rename from agents/codex-3253.md rename to archives/agents/2025-11-30-codex-3253.md diff --git a/agents/codex-3254.md b/archives/agents/2025-11-30-codex-3254.md similarity index 100% rename from agents/codex-3254.md rename to archives/agents/2025-11-30-codex-3254.md diff --git a/agents/codex-3255.md b/archives/agents/2025-11-30-codex-3255.md similarity index 100% rename from agents/codex-3255.md rename to archives/agents/2025-11-30-codex-3255.md diff --git a/agents/codex-3260.md b/archives/agents/2025-11-30-codex-3260.md similarity index 100% rename from agents/codex-3260.md rename to archives/agents/2025-11-30-codex-3260.md diff --git a/agents/codex-3261.md b/archives/agents/2025-11-30-codex-3261.md similarity index 100% rename from agents/codex-3261.md rename to archives/agents/2025-11-30-codex-3261.md diff --git a/agents/codex-3266.md b/archives/agents/2025-11-30-codex-3266.md similarity index 100% rename from agents/codex-3266.md rename to archives/agents/2025-11-30-codex-3266.md diff --git a/agents/codex-3279.md b/archives/agents/2025-11-30-codex-3279.md similarity index 100% rename from agents/codex-3279.md rename to archives/agents/2025-11-30-codex-3279.md diff --git a/agents/codex-3284.md b/archives/agents/2025-11-30-codex-3284.md similarity index 100% rename from agents/codex-3284.md rename to archives/agents/2025-11-30-codex-3284.md diff --git a/agents/codex-3309.md b/archives/agents/2025-11-30-codex-3309.md similarity index 100% rename from agents/codex-3309.md rename to archives/agents/2025-11-30-codex-3309.md diff --git a/agents/codex-3318.md b/archives/agents/2025-11-30-codex-3318.md similarity index 100% rename from agents/codex-3318.md rename to archives/agents/2025-11-30-codex-3318.md diff --git a/agents/codex-3319.md b/archives/agents/2025-11-30-codex-3319.md similarity index 100% rename from agents/codex-3319.md rename to archives/agents/2025-11-30-codex-3319.md diff --git a/agents/codex-3321.md b/archives/agents/2025-11-30-codex-3321.md similarity index 100% rename from agents/codex-3321.md rename to archives/agents/2025-11-30-codex-3321.md diff --git a/agents/codex-3331.md b/archives/agents/2025-11-30-codex-3331.md similarity index 100% rename from agents/codex-3331.md rename to archives/agents/2025-11-30-codex-3331.md diff --git a/agents/codex-3333.md b/archives/agents/2025-11-30-codex-3333.md similarity index 100% rename from agents/codex-3333.md rename to archives/agents/2025-11-30-codex-3333.md diff --git a/agents/codex-3335.md b/archives/agents/2025-11-30-codex-3335.md similarity index 100% rename from agents/codex-3335.md rename to archives/agents/2025-11-30-codex-3335.md diff --git a/agents/codex-3352.md b/archives/agents/2025-11-30-codex-3352.md similarity index 100% rename from agents/codex-3352.md rename to archives/agents/2025-11-30-codex-3352.md diff --git a/agents/codex-3363.md b/archives/agents/2025-11-30-codex-3363.md similarity index 100% rename from agents/codex-3363.md rename to archives/agents/2025-11-30-codex-3363.md diff --git a/agents/codex-3364.md b/archives/agents/2025-11-30-codex-3364.md similarity index 100% rename from agents/codex-3364.md rename to archives/agents/2025-11-30-codex-3364.md diff --git a/agents/codex-3377.md b/archives/agents/2025-11-30-codex-3377.md similarity index 100% rename from agents/codex-3377.md rename to archives/agents/2025-11-30-codex-3377.md diff --git a/agents/codex-3380.md b/archives/agents/2025-11-30-codex-3380.md similarity index 100% rename from agents/codex-3380.md rename to archives/agents/2025-11-30-codex-3380.md diff --git a/agents/codex-3384.md b/archives/agents/2025-11-30-codex-3384.md similarity index 100% rename from agents/codex-3384.md rename to archives/agents/2025-11-30-codex-3384.md diff --git a/agents/codex-3391.md b/archives/agents/2025-11-30-codex-3391.md similarity index 100% rename from agents/codex-3391.md rename to archives/agents/2025-11-30-codex-3391.md diff --git a/agents/codex-3393.md b/archives/agents/2025-11-30-codex-3393.md similarity index 100% rename from agents/codex-3393.md rename to archives/agents/2025-11-30-codex-3393.md diff --git a/agents/codex-3397.md b/archives/agents/2025-11-30-codex-3397.md similarity index 100% rename from agents/codex-3397.md rename to archives/agents/2025-11-30-codex-3397.md diff --git a/agents/codex-3401.md b/archives/agents/2025-11-30-codex-3401.md similarity index 100% rename from agents/codex-3401.md rename to archives/agents/2025-11-30-codex-3401.md diff --git a/agents/codex-3404.md b/archives/agents/2025-11-30-codex-3404.md similarity index 100% rename from agents/codex-3404.md rename to archives/agents/2025-11-30-codex-3404.md diff --git a/agents/codex-3408.md b/archives/agents/2025-11-30-codex-3408.md similarity index 100% rename from agents/codex-3408.md rename to archives/agents/2025-11-30-codex-3408.md diff --git a/agents/codex-3412.md b/archives/agents/2025-11-30-codex-3412.md similarity index 100% rename from agents/codex-3412.md rename to archives/agents/2025-11-30-codex-3412.md diff --git a/agents/codex-3415.md b/archives/agents/2025-11-30-codex-3415.md similarity index 100% rename from agents/codex-3415.md rename to archives/agents/2025-11-30-codex-3415.md diff --git a/agents/codex-3418.md b/archives/agents/2025-11-30-codex-3418.md similarity index 100% rename from agents/codex-3418.md rename to archives/agents/2025-11-30-codex-3418.md diff --git a/agents/codex-3420.md b/archives/agents/2025-11-30-codex-3420.md similarity index 100% rename from agents/codex-3420.md rename to archives/agents/2025-11-30-codex-3420.md diff --git a/agents/codex-3424.md b/archives/agents/2025-11-30-codex-3424.md similarity index 100% rename from agents/codex-3424.md rename to archives/agents/2025-11-30-codex-3424.md diff --git a/agents/codex-3428.md b/archives/agents/2025-11-30-codex-3428.md similarity index 100% rename from agents/codex-3428.md rename to archives/agents/2025-11-30-codex-3428.md diff --git a/agents/codex-3431.md b/archives/agents/2025-11-30-codex-3431.md similarity index 100% rename from agents/codex-3431.md rename to archives/agents/2025-11-30-codex-3431.md diff --git a/agents/codex-3442.md b/archives/agents/2025-11-30-codex-3442.md similarity index 100% rename from agents/codex-3442.md rename to archives/agents/2025-11-30-codex-3442.md diff --git a/agents/codex-3488.md b/archives/agents/2025-11-30-codex-3488.md similarity index 100% rename from agents/codex-3488.md rename to archives/agents/2025-11-30-codex-3488.md diff --git a/agents/codex-3490.md b/archives/agents/2025-11-30-codex-3490.md similarity index 100% rename from agents/codex-3490.md rename to archives/agents/2025-11-30-codex-3490.md diff --git a/agents/codex-3498.md b/archives/agents/2025-11-30-codex-3498.md similarity index 100% rename from agents/codex-3498.md rename to archives/agents/2025-11-30-codex-3498.md diff --git a/agents/codex-3499.md b/archives/agents/2025-11-30-codex-3499.md similarity index 100% rename from agents/codex-3499.md rename to archives/agents/2025-11-30-codex-3499.md diff --git a/agents/codex-3500.md b/archives/agents/2025-11-30-codex-3500.md similarity index 100% rename from agents/codex-3500.md rename to archives/agents/2025-11-30-codex-3500.md diff --git a/agents/codex-3504.md b/archives/agents/2025-11-30-codex-3504.md similarity index 100% rename from agents/codex-3504.md rename to archives/agents/2025-11-30-codex-3504.md diff --git a/agents/codex-3505.md b/archives/agents/2025-11-30-codex-3505.md similarity index 100% rename from agents/codex-3505.md rename to archives/agents/2025-11-30-codex-3505.md diff --git a/agents/codex-3511.md b/archives/agents/2025-11-30-codex-3511.md similarity index 100% rename from agents/codex-3511.md rename to archives/agents/2025-11-30-codex-3511.md diff --git a/agents/codex-3523.md b/archives/agents/2025-11-30-codex-3523.md similarity index 100% rename from agents/codex-3523.md rename to archives/agents/2025-11-30-codex-3523.md diff --git a/agents/codex-3525.md b/archives/agents/2025-11-30-codex-3525.md similarity index 100% rename from agents/codex-3525.md rename to archives/agents/2025-11-30-codex-3525.md diff --git a/agents/codex-3527.md b/archives/agents/2025-11-30-codex-3527.md similarity index 100% rename from agents/codex-3527.md rename to archives/agents/2025-11-30-codex-3527.md diff --git a/agents/codex-3532.md b/archives/agents/2025-11-30-codex-3532.md similarity index 100% rename from agents/codex-3532.md rename to archives/agents/2025-11-30-codex-3532.md diff --git a/agents/codex-3533.md b/archives/agents/2025-11-30-codex-3533.md similarity index 100% rename from agents/codex-3533.md rename to archives/agents/2025-11-30-codex-3533.md diff --git a/agents/codex-3538.md b/archives/agents/2025-11-30-codex-3538.md similarity index 100% rename from agents/codex-3538.md rename to archives/agents/2025-11-30-codex-3538.md diff --git a/agents/codex-3544.md b/archives/agents/2025-11-30-codex-3544.md similarity index 100% rename from agents/codex-3544.md rename to archives/agents/2025-11-30-codex-3544.md diff --git a/agents/codex-3545.md b/archives/agents/2025-11-30-codex-3545.md similarity index 100% rename from agents/codex-3545.md rename to archives/agents/2025-11-30-codex-3545.md diff --git a/agents/codex-3546.md b/archives/agents/2025-11-30-codex-3546.md similarity index 100% rename from agents/codex-3546.md rename to archives/agents/2025-11-30-codex-3546.md diff --git a/agents/codex-3547.md b/archives/agents/2025-11-30-codex-3547.md similarity index 100% rename from agents/codex-3547.md rename to archives/agents/2025-11-30-codex-3547.md diff --git a/agents/codex-3552.md b/archives/agents/2025-11-30-codex-3552.md similarity index 100% rename from agents/codex-3552.md rename to archives/agents/2025-11-30-codex-3552.md diff --git a/agents/codex-3557.md b/archives/agents/2025-11-30-codex-3557.md similarity index 100% rename from agents/codex-3557.md rename to archives/agents/2025-11-30-codex-3557.md diff --git a/agents/codex-3558.md b/archives/agents/2025-11-30-codex-3558.md similarity index 100% rename from agents/codex-3558.md rename to archives/agents/2025-11-30-codex-3558.md diff --git a/agents/codex-3559.md b/archives/agents/2025-11-30-codex-3559.md similarity index 100% rename from agents/codex-3559.md rename to archives/agents/2025-11-30-codex-3559.md diff --git a/agents/codex-3581.md b/archives/agents/2025-11-30-codex-3581.md similarity index 100% rename from agents/codex-3581.md rename to archives/agents/2025-11-30-codex-3581.md diff --git a/agents/codex-3582.md b/archives/agents/2025-11-30-codex-3582.md similarity index 100% rename from agents/codex-3582.md rename to archives/agents/2025-11-30-codex-3582.md diff --git a/agents/codex-3583.md b/archives/agents/2025-11-30-codex-3583.md similarity index 100% rename from agents/codex-3583.md rename to archives/agents/2025-11-30-codex-3583.md diff --git a/agents/codex-3584.md b/archives/agents/2025-11-30-codex-3584.md similarity index 100% rename from agents/codex-3584.md rename to archives/agents/2025-11-30-codex-3584.md diff --git a/agents/codex-3585.md b/archives/agents/2025-11-30-codex-3585.md similarity index 100% rename from agents/codex-3585.md rename to archives/agents/2025-11-30-codex-3585.md diff --git a/agents/codex-3586.md b/archives/agents/2025-11-30-codex-3586.md similarity index 100% rename from agents/codex-3586.md rename to archives/agents/2025-11-30-codex-3586.md diff --git a/agents/codex-3587.md b/archives/agents/2025-11-30-codex-3587.md similarity index 100% rename from agents/codex-3587.md rename to archives/agents/2025-11-30-codex-3587.md diff --git a/agents/codex-3589.md b/archives/agents/2025-11-30-codex-3589.md similarity index 100% rename from agents/codex-3589.md rename to archives/agents/2025-11-30-codex-3589.md diff --git a/agents/codex-3590.md b/archives/agents/2025-11-30-codex-3590.md similarity index 100% rename from agents/codex-3590.md rename to archives/agents/2025-11-30-codex-3590.md diff --git a/agents/codex-3592.md b/archives/agents/2025-11-30-codex-3592.md similarity index 100% rename from agents/codex-3592.md rename to archives/agents/2025-11-30-codex-3592.md diff --git a/agents/codex-3593.md b/archives/agents/2025-11-30-codex-3593.md similarity index 100% rename from agents/codex-3593.md rename to archives/agents/2025-11-30-codex-3593.md diff --git a/agents/codex-3594.md b/archives/agents/2025-11-30-codex-3594.md similarity index 100% rename from agents/codex-3594.md rename to archives/agents/2025-11-30-codex-3594.md diff --git a/agents/codex-3595.md b/archives/agents/2025-11-30-codex-3595.md similarity index 100% rename from agents/codex-3595.md rename to archives/agents/2025-11-30-codex-3595.md diff --git a/agents/codex-3637.md b/archives/agents/2025-11-30-codex-3637.md similarity index 100% rename from agents/codex-3637.md rename to archives/agents/2025-11-30-codex-3637.md diff --git a/agents/codex-3638.md b/archives/agents/2025-11-30-codex-3638.md similarity index 100% rename from agents/codex-3638.md rename to archives/agents/2025-11-30-codex-3638.md diff --git a/agents/codex-3639.md b/archives/agents/2025-11-30-codex-3639.md similarity index 100% rename from agents/codex-3639.md rename to archives/agents/2025-11-30-codex-3639.md diff --git a/agents/codex-3640.md b/archives/agents/2025-11-30-codex-3640.md similarity index 100% rename from agents/codex-3640.md rename to archives/agents/2025-11-30-codex-3640.md diff --git a/agents/codex-3641.md b/archives/agents/2025-11-30-codex-3641.md similarity index 100% rename from agents/codex-3641.md rename to archives/agents/2025-11-30-codex-3641.md diff --git a/agents/codex-3642.md b/archives/agents/2025-11-30-codex-3642.md similarity index 100% rename from agents/codex-3642.md rename to archives/agents/2025-11-30-codex-3642.md diff --git a/agents/codex-3643.md b/archives/agents/2025-11-30-codex-3643.md similarity index 100% rename from agents/codex-3643.md rename to archives/agents/2025-11-30-codex-3643.md diff --git a/agents/codex-3645.md b/archives/agents/2025-11-30-codex-3645.md similarity index 100% rename from agents/codex-3645.md rename to archives/agents/2025-11-30-codex-3645.md diff --git a/agents/codex-3646.md b/archives/agents/2025-11-30-codex-3646.md similarity index 100% rename from agents/codex-3646.md rename to archives/agents/2025-11-30-codex-3646.md diff --git a/agents/codex-3647.md b/archives/agents/2025-11-30-codex-3647.md similarity index 100% rename from agents/codex-3647.md rename to archives/agents/2025-11-30-codex-3647.md diff --git a/agents/codex-3648.md b/archives/agents/2025-11-30-codex-3648.md similarity index 100% rename from agents/codex-3648.md rename to archives/agents/2025-11-30-codex-3648.md diff --git a/agents/codex-3649.md b/archives/agents/2025-11-30-codex-3649.md similarity index 100% rename from agents/codex-3649.md rename to archives/agents/2025-11-30-codex-3649.md diff --git a/agents/codex-3650.md b/archives/agents/2025-11-30-codex-3650.md similarity index 100% rename from agents/codex-3650.md rename to archives/agents/2025-11-30-codex-3650.md diff --git a/agents/codex-3651.md b/archives/agents/2025-11-30-codex-3651.md similarity index 100% rename from agents/codex-3651.md rename to archives/agents/2025-11-30-codex-3651.md diff --git a/agents/codex-3679.md b/archives/agents/2025-11-30-codex-3679.md similarity index 100% rename from agents/codex-3679.md rename to archives/agents/2025-11-30-codex-3679.md diff --git a/agents/codex-3680.md b/archives/agents/2025-11-30-codex-3680.md similarity index 100% rename from agents/codex-3680.md rename to archives/agents/2025-11-30-codex-3680.md diff --git a/agents/codex-3681.md b/archives/agents/2025-11-30-codex-3681.md similarity index 100% rename from agents/codex-3681.md rename to archives/agents/2025-11-30-codex-3681.md diff --git a/agents/codex-3682.md b/archives/agents/2025-11-30-codex-3682.md similarity index 100% rename from agents/codex-3682.md rename to archives/agents/2025-11-30-codex-3682.md diff --git a/agents/codex-3683.md b/archives/agents/2025-11-30-codex-3683.md similarity index 100% rename from agents/codex-3683.md rename to archives/agents/2025-11-30-codex-3683.md diff --git a/agents/codex-3684.md b/archives/agents/2025-11-30-codex-3684.md similarity index 100% rename from agents/codex-3684.md rename to archives/agents/2025-11-30-codex-3684.md diff --git a/agents/codex-3685.md b/archives/agents/2025-11-30-codex-3685.md similarity index 100% rename from agents/codex-3685.md rename to archives/agents/2025-11-30-codex-3685.md diff --git a/agents/codex-3687.md b/archives/agents/2025-11-30-codex-3687.md similarity index 100% rename from agents/codex-3687.md rename to archives/agents/2025-11-30-codex-3687.md diff --git a/agents/codex-3688.md b/archives/agents/2025-11-30-codex-3688.md similarity index 100% rename from agents/codex-3688.md rename to archives/agents/2025-11-30-codex-3688.md diff --git a/agents/codex-3689.md b/archives/agents/2025-11-30-codex-3689.md similarity index 100% rename from agents/codex-3689.md rename to archives/agents/2025-11-30-codex-3689.md diff --git a/agents/codex-3690.md b/archives/agents/2025-11-30-codex-3690.md similarity index 100% rename from agents/codex-3690.md rename to archives/agents/2025-11-30-codex-3690.md diff --git a/agents/codex-3691.md b/archives/agents/2025-11-30-codex-3691.md similarity index 100% rename from agents/codex-3691.md rename to archives/agents/2025-11-30-codex-3691.md diff --git a/agents/codex-3692.md b/archives/agents/2025-11-30-codex-3692.md similarity index 100% rename from agents/codex-3692.md rename to archives/agents/2025-11-30-codex-3692.md diff --git a/agents/codex-3693.md b/archives/agents/2025-11-30-codex-3693.md similarity index 100% rename from agents/codex-3693.md rename to archives/agents/2025-11-30-codex-3693.md diff --git a/agents/codex-3701.md b/archives/agents/2025-11-30-codex-3701.md similarity index 100% rename from agents/codex-3701.md rename to archives/agents/2025-11-30-codex-3701.md diff --git a/agents/codex-3737.md b/archives/agents/2025-11-30-codex-3737.md similarity index 100% rename from agents/codex-3737.md rename to archives/agents/2025-11-30-codex-3737.md diff --git a/agents/codex-3738.md b/archives/agents/2025-11-30-codex-3738.md similarity index 100% rename from agents/codex-3738.md rename to archives/agents/2025-11-30-codex-3738.md diff --git a/agents/codex-3739.md b/archives/agents/2025-11-30-codex-3739.md similarity index 100% rename from agents/codex-3739.md rename to archives/agents/2025-11-30-codex-3739.md diff --git a/agents/codex-3754.md b/archives/agents/2025-11-30-codex-3754.md similarity index 100% rename from agents/codex-3754.md rename to archives/agents/2025-11-30-codex-3754.md diff --git a/agents/codex-3756.md b/archives/agents/2025-11-30-codex-3756.md similarity index 100% rename from agents/codex-3756.md rename to archives/agents/2025-11-30-codex-3756.md diff --git a/agents/codex-3770.md b/archives/agents/2025-11-30-codex-3770.md similarity index 100% rename from agents/codex-3770.md rename to archives/agents/2025-11-30-codex-3770.md diff --git a/agents/codex-3771.md b/archives/agents/2025-11-30-codex-3771.md similarity index 100% rename from agents/codex-3771.md rename to archives/agents/2025-11-30-codex-3771.md diff --git a/agents/codex-3773.md b/archives/agents/2025-11-30-codex-3773.md similarity index 100% rename from agents/codex-3773.md rename to archives/agents/2025-11-30-codex-3773.md diff --git a/agents/codex-3784.md b/archives/agents/2025-11-30-codex-3784.md similarity index 100% rename from agents/codex-3784.md rename to archives/agents/2025-11-30-codex-3784.md diff --git a/agents/codex-3797.md b/archives/agents/2025-11-30-codex-3797.md similarity index 100% rename from agents/codex-3797.md rename to archives/agents/2025-11-30-codex-3797.md diff --git a/agents/codex-3798.md b/archives/agents/2025-11-30-codex-3798.md similarity index 100% rename from agents/codex-3798.md rename to archives/agents/2025-11-30-codex-3798.md diff --git a/agents/codex-3799.md b/archives/agents/2025-11-30-codex-3799.md similarity index 100% rename from agents/codex-3799.md rename to archives/agents/2025-11-30-codex-3799.md diff --git a/agents/codex-3800.md b/archives/agents/2025-11-30-codex-3800.md similarity index 100% rename from agents/codex-3800.md rename to archives/agents/2025-11-30-codex-3800.md diff --git a/agents/codex-3801.md b/archives/agents/2025-11-30-codex-3801.md similarity index 100% rename from agents/codex-3801.md rename to archives/agents/2025-11-30-codex-3801.md diff --git a/agents/codex-3817.md b/archives/agents/2025-11-30-codex-3817.md similarity index 100% rename from agents/codex-3817.md rename to archives/agents/2025-11-30-codex-3817.md diff --git a/agents/codex-3818.md b/archives/agents/2025-11-30-codex-3818.md similarity index 100% rename from agents/codex-3818.md rename to archives/agents/2025-11-30-codex-3818.md diff --git a/agents/codex-3819.md b/archives/agents/2025-11-30-codex-3819.md similarity index 100% rename from agents/codex-3819.md rename to archives/agents/2025-11-30-codex-3819.md diff --git a/agents/codex-3820.md b/archives/agents/2025-11-30-codex-3820.md similarity index 100% rename from agents/codex-3820.md rename to archives/agents/2025-11-30-codex-3820.md diff --git a/agents/codex-3861.md b/archives/agents/2025-11-30-codex-3861.md similarity index 100% rename from agents/codex-3861.md rename to archives/agents/2025-11-30-codex-3861.md diff --git a/agents/codex-3878.md b/archives/agents/2025-11-30-codex-3878.md similarity index 100% rename from agents/codex-3878.md rename to archives/agents/2025-11-30-codex-3878.md diff --git a/agents/codex-3879.md b/archives/agents/2025-11-30-codex-3879.md similarity index 100% rename from agents/codex-3879.md rename to archives/agents/2025-11-30-codex-3879.md diff --git a/agents/codex-721.md b/archives/agents/2025-11-30-codex-721.md similarity index 100% rename from agents/codex-721.md rename to archives/agents/2025-11-30-codex-721.md diff --git a/agents/codex-730.md b/archives/agents/2025-11-30-codex-730.md similarity index 100% rename from agents/codex-730.md rename to archives/agents/2025-11-30-codex-730.md diff --git a/agents/codex-732.md b/archives/agents/2025-11-30-codex-732.md similarity index 100% rename from agents/codex-732.md rename to archives/agents/2025-11-30-codex-732.md diff --git a/agents/codex-734.md b/archives/agents/2025-11-30-codex-734.md similarity index 100% rename from agents/codex-734.md rename to archives/agents/2025-11-30-codex-734.md diff --git a/archives/agents/README.md b/archives/agents/README.md index c1eaafc615..8add20e463 100644 --- a/archives/agents/README.md +++ b/archives/agents/README.md @@ -1,10 +1,29 @@ # Archived agent instruction files -Legacy agent guidance that referenced retired workflow names or superseded policy drafts lives here for historical context. Current automation and protection rules are documented in: +Legacy agent guidance that referenced retired workflow names, superseded policy drafts, or **closed issues** lives here for historical context. Current automation and protection rules are documented in: - `.github/workflows/README.md` for the active workflow topology and naming policy. - `docs/ci/AGENTS_POLICY.md` for the protection contract covering the agents workflows. +## Archive structure + +``` +archives/agents/ +├── ledgers/ # YAML task-tracking ledgers from .agents/ +│ └── issue-NNNN-ledger.yml +├── YYYY-MM-DD-codex-NNNN.md # Archived instruction files +└── README.md +``` + +## Archived on 2025-11-30 (bulk cleanup) + +**Ledgers** (18 files → `ledgers/`): +- All issue ledgers from `.agents/` — issues #3011, #3203, #3209, #3213, #3218, #3219, #3279, #3284, #3309, #3318, #3321, #3333, #3352, #3363, #3428, #3442, #3490, #3498 — all CLOSED + +**Instruction files** (415 files): +- All codex-*.md files referencing closed issues, numbered #721 through #3879 +- Excludes only `codex-3572.md` which remains active (issue OPEN) + ## Archived on 2025-11-22 - `2025-11-22-codex-2682.md` – instructions focused on removing the old Agents 61/62 consumer workflows, which are no longer present. - `2025-11-22-codex-2684.md` – bootstrap plan for drafting the original agents policy file that has since been published and maintained elsewhere. diff --git a/.agents/issue-3011-ledger.yml b/archives/agents/ledgers/issue-3011-ledger.yml similarity index 100% rename from .agents/issue-3011-ledger.yml rename to archives/agents/ledgers/issue-3011-ledger.yml diff --git a/.agents/issue-3203-ledger.yml b/archives/agents/ledgers/issue-3203-ledger.yml similarity index 100% rename from .agents/issue-3203-ledger.yml rename to archives/agents/ledgers/issue-3203-ledger.yml diff --git a/.agents/issue-3209-ledger.yml b/archives/agents/ledgers/issue-3209-ledger.yml similarity index 100% rename from .agents/issue-3209-ledger.yml rename to archives/agents/ledgers/issue-3209-ledger.yml diff --git a/.agents/issue-3213-ledger.yml b/archives/agents/ledgers/issue-3213-ledger.yml similarity index 100% rename from .agents/issue-3213-ledger.yml rename to archives/agents/ledgers/issue-3213-ledger.yml diff --git a/.agents/issue-3218-ledger.yml b/archives/agents/ledgers/issue-3218-ledger.yml similarity index 100% rename from .agents/issue-3218-ledger.yml rename to archives/agents/ledgers/issue-3218-ledger.yml diff --git a/.agents/issue-3219-ledger.yml b/archives/agents/ledgers/issue-3219-ledger.yml similarity index 100% rename from .agents/issue-3219-ledger.yml rename to archives/agents/ledgers/issue-3219-ledger.yml diff --git a/.agents/issue-3279-ledger.yml b/archives/agents/ledgers/issue-3279-ledger.yml similarity index 100% rename from .agents/issue-3279-ledger.yml rename to archives/agents/ledgers/issue-3279-ledger.yml diff --git a/.agents/issue-3284-ledger.yml b/archives/agents/ledgers/issue-3284-ledger.yml similarity index 100% rename from .agents/issue-3284-ledger.yml rename to archives/agents/ledgers/issue-3284-ledger.yml diff --git a/.agents/issue-3309-ledger.yml b/archives/agents/ledgers/issue-3309-ledger.yml similarity index 100% rename from .agents/issue-3309-ledger.yml rename to archives/agents/ledgers/issue-3309-ledger.yml diff --git a/.agents/issue-3318-ledger.yml b/archives/agents/ledgers/issue-3318-ledger.yml similarity index 100% rename from .agents/issue-3318-ledger.yml rename to archives/agents/ledgers/issue-3318-ledger.yml diff --git a/.agents/issue-3321-ledger.yml b/archives/agents/ledgers/issue-3321-ledger.yml similarity index 100% rename from .agents/issue-3321-ledger.yml rename to archives/agents/ledgers/issue-3321-ledger.yml diff --git a/.agents/issue-3333-ledger.yml b/archives/agents/ledgers/issue-3333-ledger.yml similarity index 100% rename from .agents/issue-3333-ledger.yml rename to archives/agents/ledgers/issue-3333-ledger.yml diff --git a/.agents/issue-3352-ledger.yml b/archives/agents/ledgers/issue-3352-ledger.yml similarity index 100% rename from .agents/issue-3352-ledger.yml rename to archives/agents/ledgers/issue-3352-ledger.yml diff --git a/.agents/issue-3363-ledger.yml b/archives/agents/ledgers/issue-3363-ledger.yml similarity index 100% rename from .agents/issue-3363-ledger.yml rename to archives/agents/ledgers/issue-3363-ledger.yml diff --git a/.agents/issue-3428-ledger.yml b/archives/agents/ledgers/issue-3428-ledger.yml similarity index 100% rename from .agents/issue-3428-ledger.yml rename to archives/agents/ledgers/issue-3428-ledger.yml diff --git a/.agents/issue-3442-ledger.yml b/archives/agents/ledgers/issue-3442-ledger.yml similarity index 100% rename from .agents/issue-3442-ledger.yml rename to archives/agents/ledgers/issue-3442-ledger.yml diff --git a/.agents/issue-3490-ledger.yml b/archives/agents/ledgers/issue-3490-ledger.yml similarity index 100% rename from .agents/issue-3490-ledger.yml rename to archives/agents/ledgers/issue-3490-ledger.yml diff --git a/.agents/issue-3498-ledger.yml b/archives/agents/ledgers/issue-3498-ledger.yml similarity index 100% rename from .agents/issue-3498-ledger.yml rename to archives/agents/ledgers/issue-3498-ledger.yml diff --git a/scripts/archive_agents.sh b/scripts/archive_agents.sh new file mode 100755 index 0000000000..0d5fb51365 --- /dev/null +++ b/scripts/archive_agents.sh @@ -0,0 +1,85 @@ +#!/usr/bin/env bash +# archive_agents.sh — Archive codex instruction files for closed issues +# +# Usage: +# ./scripts/archive_agents.sh # Dry-run (shows what would be archived) +# ./scripts/archive_agents.sh --apply # Actually move files +# +# Requirements: gh CLI authenticated with repo access + +set -euo pipefail + +AGENTS_DIR="agents" +ARCHIVE_DIR="archives/agents" +DATE=$(date +%Y-%m-%d) +DRY_RUN=true + +if [[ "${1:-}" == "--apply" ]]; then + DRY_RUN=false +fi + +cd "$(git rev-parse --show-toplevel)" + +echo "=== Agent Archive Script ===" +echo "Date prefix: $DATE" +echo "Mode: $(if $DRY_RUN; then echo 'DRY-RUN (use --apply to move files)'; else echo 'APPLY'; fi)" +echo "" + +to_archive=() +to_keep=() + +for f in "$AGENTS_DIR"/codex-*.md; do + [[ -f "$f" ]] || continue + num=$(basename "$f" | grep -oE '[0-9]+') + + # Check issue state + state=$(gh issue view "$num" --json state -q '.state' 2>/dev/null || echo "NOT_FOUND") + + if [[ "$state" == "OPEN" ]]; then + to_keep+=("codex-${num}.md (Issue #${num} OPEN)") + else + to_archive+=("$f|$num|$state") + fi +done + +echo "=== Files to KEEP (open issues) ===" +if [[ ${#to_keep[@]} -eq 0 ]]; then + echo " (none)" +else + for item in "${to_keep[@]}"; do + echo " ✓ $item" + done +fi +echo "" + +echo "=== Files to ARCHIVE (closed/not-found issues) ===" +if [[ ${#to_archive[@]} -eq 0 ]]; then + echo " (none)" +else + for item in "${to_archive[@]}"; do + IFS='|' read -r file num state <<< "$item" + target="${ARCHIVE_DIR}/${DATE}-codex-${num}.md" + echo " → $file → $target (Issue #${num}: $state)" + done +fi +echo "" + +if $DRY_RUN; then + echo "=== DRY-RUN complete ===" + echo "Run with --apply to actually move ${#to_archive[@]} files" +else + if [[ ${#to_archive[@]} -eq 0 ]]; then + echo "Nothing to archive." + exit 0 + fi + + echo "=== Archiving ${#to_archive[@]} files ===" + for item in "${to_archive[@]}"; do + IFS='|' read -r file num state <<< "$item" + target="${ARCHIVE_DIR}/${DATE}-codex-${num}.md" + mv "$file" "$target" + echo " ✓ Moved $file → $target" + done + echo "" + echo "=== Done! Archived ${#to_archive[@]} files ===" +fi From 64ed6a1931ddbfd55e926078f5bab34ba8ff2c08 Mon Sep 17 00:00:00 2001 From: stranske Date: Sun, 30 Nov 2025 03:04:21 +0000 Subject: [PATCH 15/40] docs: update directory index for agent archival --- docs/directory-index/ROOT.md | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/docs/directory-index/ROOT.md b/docs/directory-index/ROOT.md index 296cef1b11..3d59c874d8 100644 --- a/docs/directory-index/ROOT.md +++ b/docs/directory-index/ROOT.md @@ -74,9 +74,9 @@ | Folder | Purpose | Index | |--------|---------|-------| -| `agents/` | Codex agent session logs | [View](agents.md) | +| `agents/` | Active Codex instruction files (1 active, rest archived) | [View](agents.md) | | `analysis/` | Analysis modules and results helpers | [View](analysis.md) | -| `archives/` | Historical artifacts and retired code | [View](archives.md) | +| `archives/` | Historical artifacts and retired code (incl. 415+ agent files) | [View](archives.md) | | `assets/` | Static assets (images, templates) | [View](assets.md) | | `config/` | YAML configuration files | [View](config.md) | | `data/` | Reference datasets and raw data | [View](data.md) | From 66911a2bc165190d6eafd79535ed7bed735b835a Mon Sep 17 00:00:00 2001 From: stranske Date: Sun, 30 Nov 2025 03:11:03 +0000 Subject: [PATCH 16/40] chore: archive unused GitHub actions Archive 4 actions no longer referenced by any workflow: - apply-autofix: wrapper for autofix+commit (now handled by reusable-18) - autofix-commit-push: duplicate of apply-autofix - update-residual-history: residual tracking removed from autofix flow - codex-bootstrap: superseded by codex-bootstrap-lite Fixed duplicate key in archived codex-bootstrap/action.yml Remaining active actions: - autofix: core formatting action - build-pr-comment: used by reusable-18-autofix.yml - codex-bootstrap-lite: used by reusable-16-agents.yml - signature-verify: used by health-43-ci-signature-guard.yml --- .../2025-11-30-apply-autofix}/action.yml | 0 .../action.yml | 0 .../2025-11-30-codex-bootstrap}/action.yml | 4 +- .../action.yml | 0 archives/github-actions/README.md | 43 +++++++++++++++++++ 5 files changed, 45 insertions(+), 2 deletions(-) rename {.github/actions/apply-autofix => archives/github-actions/2025-11-30-apply-autofix}/action.yml (100%) rename {.github/actions/autofix-commit-push => archives/github-actions/2025-11-30-autofix-commit-push}/action.yml (100%) rename {.github/actions/codex-bootstrap => archives/github-actions/2025-11-30-codex-bootstrap}/action.yml (99%) rename {.github/actions/update-residual-history => archives/github-actions/2025-11-30-update-residual-history}/action.yml (100%) create mode 100644 archives/github-actions/README.md diff --git a/.github/actions/apply-autofix/action.yml b/archives/github-actions/2025-11-30-apply-autofix/action.yml similarity index 100% rename from .github/actions/apply-autofix/action.yml rename to archives/github-actions/2025-11-30-apply-autofix/action.yml diff --git a/.github/actions/autofix-commit-push/action.yml b/archives/github-actions/2025-11-30-autofix-commit-push/action.yml similarity index 100% rename from .github/actions/autofix-commit-push/action.yml rename to archives/github-actions/2025-11-30-autofix-commit-push/action.yml diff --git a/.github/actions/codex-bootstrap/action.yml b/archives/github-actions/2025-11-30-codex-bootstrap/action.yml similarity index 99% rename from .github/actions/codex-bootstrap/action.yml rename to archives/github-actions/2025-11-30-codex-bootstrap/action.yml index abc2cb6054..239de27a04 100644 --- a/.github/actions/codex-bootstrap/action.yml +++ b/archives/github-actions/2025-11-30-codex-bootstrap/action.yml @@ -25,8 +25,8 @@ inputs: description: "Allow fallback to GITHUB_TOKEN when PAT is missing" default: "true" required: false - codex_command: - description: "Command to post to the PR to trigger Codex" + codex_command_legacy: + description: "Command to post to the PR to trigger Codex (duplicate key, kept for archive)" default: "codex: start" required: false base_branch: diff --git a/.github/actions/update-residual-history/action.yml b/archives/github-actions/2025-11-30-update-residual-history/action.yml similarity index 100% rename from .github/actions/update-residual-history/action.yml rename to archives/github-actions/2025-11-30-update-residual-history/action.yml diff --git a/archives/github-actions/README.md b/archives/github-actions/README.md new file mode 100644 index 0000000000..d573e38406 --- /dev/null +++ b/archives/github-actions/README.md @@ -0,0 +1,43 @@ +# Archived GitHub Actions + +Composite actions that are no longer referenced by any active workflow. + +## Archive Structure + +``` +archives/github-actions/ +├── YYYY-MM-DD-action-name/ # Archived action directory +│ └── action.yml +└── README.md +``` + +## Archived on 2025-11-30 + +### `apply-autofix` +- **Purpose**: Wrapper that ran `autofix` action then committed/pushed changes +- **Reason**: Not used by any workflow; `reusable-18-autofix.yml` handles the full autofix loop directly +- **Dependencies**: Used `autofix` action internally + +### `autofix-commit-push` +- **Purpose**: Similar to `apply-autofix` but with simpler commit message handling +- **Reason**: Not used by any workflow; duplicate of `apply-autofix` functionality +- **Dependencies**: Used `autofix` action internally + +### `update-residual-history` +- **Purpose**: Appended autofix residual classification to `ci/autofix/history.json` +- **Reason**: Not used by any workflow; residual tracking was removed from autofix flow +- **Dependencies**: Required `scripts/update_residual_history.py` (also unused) + +### `codex-bootstrap` +- **Purpose**: Original verbose Codex bootstrap action with complex fallback logic +- **Reason**: Replaced by `codex-bootstrap-lite` which is simpler and actively used +- **Superseded by**: `.github/actions/codex-bootstrap-lite/` + +## Active Actions (kept in `.github/actions/`) + +| Action | Used By | Purpose | +|--------|---------|---------| +| `autofix` | `build-pr-comment`, archived wrappers | Core formatting action (ruff, black, isort) | +| `build-pr-comment` | `reusable-18-autofix.yml` | Builds PR comment from autofix results | +| `codex-bootstrap-lite` | `reusable-16-agents.yml` | Minimal Codex PR bootstrap | +| `signature-verify` | `health-43-ci-signature-guard.yml` | Verify CI signature files | From 43559a8840c1486f1021aaa2fca651a99dfbd413 Mon Sep 17 00:00:00 2001 From: stranske Date: Sun, 30 Nov 2025 03:24:49 +0000 Subject: [PATCH 17/40] docs: update WORKFLOW_GUIDE.md with 16 missing workflows Add documentation for workflows that were missing from the guide: - PR Checks: pr-11-ci-smoke.yml, autofix.yml - Agents: agents-guard.yml, agents-moderate-connector.yml, agents-pr-meta.yml, agents-keepalive-branch-sync.yml, agents-keepalive-dispatch-handler.yml, agents-debug-issue-event.yml, agents-64-verify-agent-assignment.yml - Health: health-40-sweep.yml, health-50-security-scan.yml - Maintenance: maint-46-post-ci.yml, maint-50-tool-version-check.yml, maint-51-dependency-refresh.yml, maint-52-validate-workflows.yml, maint-60-release.yml, maint-coverage-guard.yml - Reusables: reusable-agents-issue-bridge.yml Part of root folder cleanup effort. --- docs/WORKFLOW_GUIDE.md | 44 ++++++++++++++++++++++++++++-------------- 1 file changed, 30 insertions(+), 14 deletions(-) diff --git a/docs/WORKFLOW_GUIDE.md b/docs/WORKFLOW_GUIDE.md index c70713f6aa..9237e5441a 100644 --- a/docs/WORKFLOW_GUIDE.md +++ b/docs/WORKFLOW_GUIDE.md @@ -17,13 +17,13 @@ operational detail for the kept set. | Prefix | Purpose | Active Examples | | ------ | ------- | ---------------- | -| `pr-` | Pull-request CI wrappers | `pr-00-gate.yml` | -| `maint-` | Post-CI maintenance and self-tests | `maint-45-cosmetic-repair.yml`, `maint-keepalive.yml` | -| `health-` | Repository health & policy checks | `health-40-sweep.yml`, `health-40-repo-selfcheck.yml`, `health-41-repo-health.yml`, `health-42-actionlint.yml`, `health-43-ci-signature-guard.yml`, `health-44-gate-branch-protection.yml` | -| `agents-` | Agent orchestration entry points | `agents-70-orchestrator.yml`, `agents-71-codex-belt-dispatcher.yml`, `agents-72-codex-belt-worker.yml`, `agents-73-codex-belt-conveyor.yml` | -| `reusable-` | Reusable composites invoked by other workflows | `reusable-10-ci-python.yml`, `reusable-12-ci-docker.yml`, `reusable-18-autofix.yml`, `reusable-16-agents.yml` | +| `pr-` | Pull-request CI wrappers | `pr-00-gate.yml`, `pr-11-ci-smoke.yml` | +| `maint-` | Post-CI maintenance and self-tests | `maint-45-cosmetic-repair.yml`, `maint-46-post-ci.yml`, `maint-47-disable-legacy-workflows.yml`, `maint-50-tool-version-check.yml`, `maint-51-dependency-refresh.yml`, `maint-52-validate-workflows.yml`, `maint-60-release.yml`, `maint-coverage-guard.yml` | +| `health-` | Repository health & policy checks | `health-40-sweep.yml`, `health-40-repo-selfcheck.yml`, `health-41-repo-health.yml`, `health-42-actionlint.yml`, `health-43-ci-signature-guard.yml`, `health-44-gate-branch-protection.yml`, `health-50-security-scan.yml` | +| `agents-` | Agent orchestration entry points | `agents-63-issue-intake.yml`, `agents-64-verify-agent-assignment.yml`, `agents-70-orchestrator.yml`, `agents-71-codex-belt-dispatcher.yml`, `agents-72-codex-belt-worker.yml`, `agents-73-codex-belt-conveyor.yml`, `agents-guard.yml`, `agents-pr-meta.yml`, `agents-moderate-connector.yml`, `agents-keepalive-*.yml`, `agents-debug-issue-event.yml` | +| `reusable-` | Reusable composites invoked by other workflows | `reusable-10-ci-python.yml`, `reusable-12-ci-docker.yml`, `reusable-16-agents.yml`, `reusable-18-autofix.yml`, `reusable-agents-issue-bridge.yml` | | `selftest-` | Manual self-tests & experiments | `selftest-reusable-ci.yml` | -| `autofix-` assets | Shared configuration for autofix tooling | `autofix-versions.env` | +| `autofix.yml` | CI autofix loop | `autofix.yml` | **Naming checklist** 1. Choose the correct prefix for the workflow's scope. @@ -40,35 +40,51 @@ The active roster below mirrors the **Keep** list in the [Workflow System Overvi ### PR Checks - **`pr-00-gate.yml`** — Required orchestrator that calls the reusable Python (3.11/3.12) and Docker smoke workflows, then fails fast if any leg does not succeed. A lightweight `detect_doc_only` job mirrors the former PR‑14 filters (Markdown, `docs/`, `assets/`) to skip heavy legs and post the friendly notice when a PR is documentation-only. +- **`pr-11-ci-smoke.yml`** — Minimal invariant CI that runs on push/PR to phase-2-dev and main. Installs the project, validates imports, and runs `pytest tests/test_invariants.py` for fast regression detection. _Inline Gate helper_ - **Gate summary job (`pr-00-gate.yml`)** — Post-CI job that downloads artifacts, computes coverage deltas, runs the label-gated autofix routine, and updates the PR summary comment with a stable marker. ### Maintenance & Repo Health -- **`maint-keepalive.yml`** — Twice-daily cron plus manual dispatch heartbeat that posts a timestamped comment (with the run URL) to the Ops heartbeat issue using the `ACTIONS_BOT_PAT` secret. Fails fast when `OPS_HEARTBEAT_ISSUE` or the PAT are missing so misconfiguration surfaces immediately. +- **`maint-45-cosmetic-repair.yml`** — Manual dispatch utility that runs `pytest -q`, applies guard-gated cosmetic fixes via `scripts/ci_cosmetic_repair.py`, and opens a labelled PR when changes exist. +- **`maint-46-post-ci.yml`** — Post-CI summary recovery workflow triggered by `workflow_run` on Gate completion. Propagates Gate commit status and posts summaries when the Gate's own summary job doesn't complete. +- **`maint-47-disable-legacy-workflows.yml`** — Manual dispatch utility to disable retired workflows that still appear in the Actions UI. +- **`maint-50-tool-version-check.yml`** — Scheduled + manual dispatch workflow that checks for tool version updates. +- **`maint-51-dependency-refresh.yml`** — Scheduled + manual dispatch workflow for dependency updates. +- **`maint-52-validate-workflows.yml`** — PR/push workflow that validates workflow YAML syntax and structure. +- **`maint-60-release.yml`** — Tag-triggered release workflow for publishing packages. +- **`maint-coverage-guard.yml`** — Daily cron + dispatch workflow that monitors Gate coverage artifacts and maintains the rolling coverage baseline breach issue. - **`health-40-sweep.yml`** — Weekly sweep that fans out to Actionlint and branch-protection verification. Pull requests trigger the Actionlint leg (paths-filter gated) while schedule/manual runs execute both checks to keep the enforcement snapshots fresh. +- **`health-40-repo-selfcheck.yml`** — Read-only governance probe that surfaces label coverage and branch-protection visibility gaps in the run summary. +- **`health-41-repo-health.yml`** — Weekly repository health sweep that writes a single run-summary report covering stale branches, unassigned issues, and default-branch protection drift, with optional `workflow_dispatch` reruns. - **`health-42-actionlint.yml`** — Underlying Actionlint job invoked by the sweep (and still runnable via manual dispatch when you need a focused lint dry run). - **`health-43-ci-signature-guard.yml`** — Guards the CI manifest with signed fixture checks. - **`health-44-gate-branch-protection.yml`** — Enforces branch-protection policy via `tools/enforce_gate_branch_protection.py` when the PAT is configured (now triggered on PRs or by the consolidated sweep). - -_Additional opt-in utilities_ -- **`health-41-repo-health.yml`** — Weekly repository health sweep that writes a single run-summary report covering stale branches, unassigned issues, and default-branch protection drift, with optional `workflow_dispatch` reruns. -- **`health-40-repo-selfcheck.yml`** — Read-only governance probe that surfaces label coverage and branch-protection visibility gaps in the run summary. -- **`maint-45-cosmetic-repair.yml`** — Manual dispatch utility that runs `pytest -q`, applies guard-gated cosmetic fixes via `scripts/ci_cosmetic_repair.py`, and opens a labelled PR when changes exist. +- **`health-50-security-scan.yml`** — Security scanning workflow triggered on push, PR, and schedule. Runs vulnerability checks and security audits. ### Agents & Issues -- **`agents-70-orchestrator.yml`** — 20-minute cron plus manual dispatch entry point for readiness, Codex bootstrap, diagnostics, verification, and keepalive sweeps. Delegates to `reusable-16-agents.yml` and accepts extended options via `options_json`. - **`agents-63-issue-intake.yml`** — Canonical front door that seeds Codex bootstrap PRs on `agent:codex`/`agents:codex` labels, exposes manual dispatch inputs, and services ChatGPT sync via `workflow_call`. +- **`agents-64-verify-agent-assignment.yml`** — Workflow-call validator ensuring `agent:codex` issues remain assigned to approved automation accounts. +- **`agents-70-orchestrator.yml`** — 20-minute cron plus manual dispatch entry point for readiness, Codex bootstrap, diagnostics, verification, and keepalive sweeps. Delegates to `reusable-16-agents.yml` and accepts extended options via `options_json`. - **`agents-71-codex-belt-dispatcher.yml`** — Cron + manual dispatcher that selects the next `agent:codex` + `status:ready` issue, prepares the deterministic `codex/issue-*` branch, labels the source issue as in-progress, and repository-dispatches the worker. - **`agents-72-codex-belt-worker.yml`** — Repository-dispatch consumer that re-validates labels, ensures the branch diverges from the base (empty commit when needed), and opens or refreshes the Codex automation PR with labels, assignees, and activation comment. - **`agents-73-codex-belt-conveyor.yml`** — Gate follower that squash-merges successful belt PRs, deletes the branch, closes the originating issue, posts audit breadcrumbs, and re-dispatches the dispatcher so the queue keeps moving. -- **`agents-64-verify-agent-assignment.yml`** — Workflow-call validator ensuring `agent:codex` issues remain assigned to approved automation accounts. +- **`agents-guard.yml`** (aka Health 45 Agents Guard) — PR workflow that validates agent-related labels and permissions. +- **`agents-pr-meta.yml`** — PR metadata manager that serializes Codex activation commands and PR body decoration through dedicated jobs sharing a concurrency group keyed by PR number. +- **`agents-moderate-connector.yml`** — Comment moderation workflow that filters connector-authored comments based on allow/deny lists. +- **`agents-keepalive-branch-sync.yml`** — Dispatch-triggered utility that syncs PR branches with their base branch (merges base into head). +- **`agents-keepalive-dispatch-handler.yml`** — Repository dispatch handler for keepalive events. +- **`agents-debug-issue-event.yml`** — Debug workflow that dumps GitHub context on issue events (labeled, unlabeled, opened, reopened). Useful for troubleshooting label triggers. + +### Autofix +- **`autofix.yml`** — CI Autofix Loop triggered on `pull_request` and `pull_request_target`. Runs formatting fixes and commits changes back to the PR branch. ### Reusable Composites - **`reusable-10-ci-python.yml`** — Python lint/type/test reusable invoked by Gate and downstream repositories. - **`reusable-12-ci-docker.yml`** — Docker smoke reusable invoked by Gate and external consumers. - **`reusable-16-agents.yml`** — Reusable agent automation stack. - **`reusable-18-autofix.yml`** — Autofix harness used by the Gate summary job. +- **`reusable-agents-issue-bridge.yml`** — Reusable workflow for bridging issues to agent automation, called by `agents-63-issue-intake.yml`. ### Self-tests - **`selftest-reusable-ci.yml`** — Manual entry point that houses the verification matrix and comment/summary/dual-runtime publication logic. From 06649f25b86f79e59942cc5cff9b490059128418 Mon Sep 17 00:00:00 2001 From: stranske Date: Sun, 30 Nov 2025 03:28:55 +0000 Subject: [PATCH 18/40] chore: clean up analysis and assets folders - Archive analysis/health44-pr-run-review.md (investigation notes) - Remove empty placeholder PNG files from assets/screenshots/ - Consolidate placeholder markdown files into README.md - Create archives/analysis/README.md documenting archived files --- .../health44-pr-run-review.md | 0 archives/analysis/README.md | 7 +++ assets/screenshots/README.md | 53 ++++++++++--------- .../preset-selection-placeholder.md | 8 --- .../results-dashboard-placeholder.md | 8 --- assets/screenshots/template-section.png | 0 assets/screenshots/upload-interface.png | 0 .../screenshots/upload-process-placeholder.md | 7 --- 8 files changed, 34 insertions(+), 49 deletions(-) rename {analysis => archives/analysis/2025-11-30-investigation-notes}/health44-pr-run-review.md (100%) create mode 100644 archives/analysis/README.md delete mode 100644 assets/screenshots/preset-selection-placeholder.md delete mode 100644 assets/screenshots/results-dashboard-placeholder.md delete mode 100644 assets/screenshots/template-section.png delete mode 100644 assets/screenshots/upload-interface.png delete mode 100644 assets/screenshots/upload-process-placeholder.md diff --git a/analysis/health44-pr-run-review.md b/archives/analysis/2025-11-30-investigation-notes/health44-pr-run-review.md similarity index 100% rename from analysis/health44-pr-run-review.md rename to archives/analysis/2025-11-30-investigation-notes/health44-pr-run-review.md diff --git a/archives/analysis/README.md b/archives/analysis/README.md new file mode 100644 index 0000000000..81f4dec958 --- /dev/null +++ b/archives/analysis/README.md @@ -0,0 +1,7 @@ +# Archived Analysis Files + +Investigation notes and temporary analysis files archived from the `analysis/` folder. + +## 2025-11-30-investigation-notes + +- `health44-pr-run-review.md` - Investigation of Health 44 workflow hang issue (PR #3822) diff --git a/assets/screenshots/README.md b/assets/screenshots/README.md index 903364f9ab..4a791abbd2 100644 --- a/assets/screenshots/README.md +++ b/assets/screenshots/README.md @@ -1,42 +1,43 @@ -# Screenshot Placeholders +# Screenshots -This directory contains screenshots for the quickstart guide and documentation. +This directory holds screenshots for the quickstart guide and documentation. -## Screenshots Needed: +## Screenshots Needed -1. **upload-interface.png** - Shows the file upload interface and column mapping -2. **template-section.png** - Shows the template download section -3. **preset-selection.png** - Shows the three preset options (Conservative, Balanced, Aggressive) -4. **results-dashboard.png** - Shows the analysis results with charts and metrics +| Screenshot | Description | +|------------|-------------| +| `upload-interface.png` | File upload interface with drag-and-drop and column mapping | +| `template-section.png` | Template download section with sample data preview | +| `preset-selection.png` | Configuration page showing Conservative/Balanced/Aggressive presets | +| `results-dashboard.png` | Analysis results with charts, metrics, and download buttons | -## Creating Screenshots: - -To create these screenshots: +## Creating Screenshots 1. Start the Streamlit app: `./scripts/run_streamlit.sh` 2. Navigate through the workflow 3. Take screenshots at key steps 4. Save as PNG files in this directory -## Workflow to Screenshot: +## Screenshot Details -### Upload Interface (upload-interface.png): -- Main page with file uploader -- Drag-and-drop interface visible -- Upload button and file selection dialog +### upload-interface.png +- Streamlit file uploader interface +- CSV file selection dialog +- Column mapping showing Date and Fund columns -### Template Section (template-section.png): +### template-section.png - Template download section expanded - Sample data preview visible - Download button for CSV template -### Preset Selection (preset-selection.png): -- Configuration page with preset dropdown -- Conservative, Balanced, Aggressive options visible -- Description text for each preset - -### Results Dashboard (results-dashboard.png): -- Analysis results page -- Portfolio performance chart -- Key metrics displayed (Sharpe ratio, returns, etc.) -- Download buttons visible \ No newline at end of file +### preset-selection.png +- Configuration page dropdown with preset options +- Conservative (8% risk target, 60 month lookback) +- Balanced (10% risk target, 36 month lookback) +- Aggressive (15% risk target, 24 month lookback) + +### results-dashboard.png +- Portfolio performance line chart +- Key metrics: Sharpe Ratio, Annual Return, Max Drawdown +- Selected funds list with individual performance +- Download buttons for CSV, Excel, JSON exports \ No newline at end of file diff --git a/assets/screenshots/preset-selection-placeholder.md b/assets/screenshots/preset-selection-placeholder.md deleted file mode 100644 index 99f60cdd6f..0000000000 --- a/assets/screenshots/preset-selection-placeholder.md +++ /dev/null @@ -1,8 +0,0 @@ -Preset Selection Screenshot Placeholder - -This would show: -- Configuration page dropdown with preset options -- Conservative (8% risk target, 60 month lookback) -- Balanced (10% risk target, 36 month lookback) -- Aggressive (15% risk target, 24 month lookback) -- Description text for each preset explaining strategy \ No newline at end of file diff --git a/assets/screenshots/results-dashboard-placeholder.md b/assets/screenshots/results-dashboard-placeholder.md deleted file mode 100644 index 9a3d3b9204..0000000000 --- a/assets/screenshots/results-dashboard-placeholder.md +++ /dev/null @@ -1,8 +0,0 @@ -Results Dashboard Screenshot Placeholder - -This would show: -- Portfolio performance line chart over time -- Key metrics box: Sharpe Ratio, Annual Return, Max Drawdown -- Selected funds list with individual performance -- Benchmark comparison chart -- Download buttons for CSV, Excel, JSON exports \ No newline at end of file diff --git a/assets/screenshots/template-section.png b/assets/screenshots/template-section.png deleted file mode 100644 index e69de29bb2..0000000000 diff --git a/assets/screenshots/upload-interface.png b/assets/screenshots/upload-interface.png deleted file mode 100644 index e69de29bb2..0000000000 diff --git a/assets/screenshots/upload-process-placeholder.md b/assets/screenshots/upload-process-placeholder.md deleted file mode 100644 index b2d1877fa5..0000000000 --- a/assets/screenshots/upload-process-placeholder.md +++ /dev/null @@ -1,7 +0,0 @@ -Upload Process Screenshot Placeholder - -This would show: -- Streamlit file uploader interface -- CSV file selection dialog -- Column mapping interface showing Date, Fund columns -- Upload confirmation message \ No newline at end of file From 8890d988951592ba033b443e619e71b1a550be4e Mon Sep 17 00:00:00 2001 From: stranske Date: Sun, 30 Nov 2025 03:32:33 +0000 Subject: [PATCH 19/40] chore: clean up .github root files - Fix CODEOWNERS stale references: - Update agents-63-chatgpt-issue-sync.yml -> agents-63-issue-intake.yml - Remove agents-63-codex-issue-bridge.yml (no longer exists) - Remove /Old/** (folder no longer exists) - Archive orphaned labeler.yml (no workflow was using it) - Remove stale pr-path-labeler.yml reference from workflows README --- .github/CODEOWNERS | 4 +--- .github/workflows/README.md | 1 - .../github-config/2025-11-30-orphaned}/labeler.yml | 0 archives/github-config/README.md | 9 +++++++++ 4 files changed, 10 insertions(+), 4 deletions(-) rename {.github => archives/github-config/2025-11-30-orphaned}/labeler.yml (100%) create mode 100644 archives/github-config/README.md diff --git a/.github/CODEOWNERS b/.github/CODEOWNERS index 5867e1cd8a..9c2e0cae2f 100644 --- a/.github/CODEOWNERS +++ b/.github/CODEOWNERS @@ -28,7 +28,6 @@ # Documentation and notebooks /docs/** @stranske -/Old/** @stranske /notebooks/** @stranske /*.ipynb @stranske @@ -36,8 +35,7 @@ /.github/workflows/** @stranske # Critical agent workflows require owner approval -/.github/workflows/agents-63-chatgpt-issue-sync.yml @stranske -/.github/workflows/agents-63-codex-issue-bridge.yml @stranske +/.github/workflows/agents-63-issue-intake.yml @stranske /.github/workflows/agents-70-orchestrator.yml @stranske /Dockerfile @stranske /docker-compose.yml @stranske diff --git a/.github/workflows/README.md b/.github/workflows/README.md index aef1f8856c..3f538086fa 100644 --- a/.github/workflows/README.md +++ b/.github/workflows/README.md @@ -19,7 +19,6 @@ Core layers: - Governance & Health: `health-40-repo-selfcheck.yml`, `health-41-repo-health.yml`, `health-42-actionlint.yml`, `health-43-ci-signature-guard.yml`, `health-44-gate-branch-protection.yml`, labelers, dependency review, CodeQL. - Keepalive heartbeat (`maint-keepalive.yml`): twice-daily cron + dispatch workflow that posts a timestamped comment (with run link) to the Ops heartbeat issue using `ACTIONS_BOT_PAT` and fails fast if either the issue variable or PAT is missing. - Coverage guard (`maint-coverage-guard.yml`): daily cron + dispatch workflow that fetches the latest Gate coverage artifacts, compares them to the configured baseline, and maintains the rolling `[coverage] baseline breach` issue. -- Path Labeling: `pr-path-labeler.yml` auto-categorizes PRs. ### 1.1 Current CI Topology (Issue #2439) The CI stack now routes every pull request through a single Gate workflow that orchestrates the reusable CI and Docker checks: diff --git a/.github/labeler.yml b/archives/github-config/2025-11-30-orphaned/labeler.yml similarity index 100% rename from .github/labeler.yml rename to archives/github-config/2025-11-30-orphaned/labeler.yml diff --git a/archives/github-config/README.md b/archives/github-config/README.md new file mode 100644 index 0000000000..8c61bd9b73 --- /dev/null +++ b/archives/github-config/README.md @@ -0,0 +1,9 @@ +# Archived GitHub Config Files + +Configuration files archived from `.github/` folder. + +## 2025-11-30-orphaned + +- `labeler.yml` - Path-based label configuration that was orphaned (no workflow used it) + - The README.md referenced a `pr-path-labeler.yml` workflow that doesn't exist + - To restore: create a workflow using `actions/labeler` that references this config From bb6d379745ab7358591ca8333f3b6df4fab7e77e Mon Sep 17 00:00:00 2001 From: stranske Date: Sun, 30 Nov 2025 03:33:57 +0000 Subject: [PATCH 20/40] docs: update INDEX.md with repository structure overview Add comprehensive repository structure section documenting: - Core directories (src, tests, config, scripts, docs, analysis, assets, demo) - Automation & CI directories (.github/workflows, .github/actions, .github config) - Archives directories with contents from recent cleanup work - archives/agents/ (433 Codex task files) - archives/github-actions/ (4 retired actions) - archives/github-config/ (orphaned labeler.yml) - archives/analysis/ (investigation notes) --- docs/INDEX.md | 31 +++++++++++++++++++++++++++++++ 1 file changed, 31 insertions(+) diff --git a/docs/INDEX.md b/docs/INDEX.md index 4d994a2822..07104892e4 100644 --- a/docs/INDEX.md +++ b/docs/INDEX.md @@ -2,6 +2,37 @@ Use this index to find the current contributor guides and to understand which overlapping docs remain for historical context. +## Repository Structure + +### Core Directories +| Directory | Purpose | Key Files | +| --- | --- | --- | +| `src/` | Main source code | `trend_analysis/` package, `trend_portfolio_app/` | +| `tests/` | Unit and integration tests | pytest test files | +| `config/` | Configuration files | `defaults.yml`, `demo.yml` | +| `scripts/` | Utility and CI scripts | `setup_env.sh`, `run_tests.sh` | +| `docs/` | Documentation | Guides, references, CI docs | +| `analysis/` | Analysis helpers | `cv.py`, `results.py`, `tearsheet.py` | +| `assets/` | Static assets | `screenshots/` for documentation | +| `demo/` | Demo data and outputs | Generated demo datasets | + +### Automation & CI +| Directory | Purpose | Key Files | +| --- | --- | --- | +| `.github/workflows/` | GitHub Actions workflows | 36 workflow files (see `WORKFLOW_GUIDE.md`) | +| `.github/actions/` | Custom composite actions | `autofix/`, `build-pr-comment/`, `codex-bootstrap-lite/`, `signature-verify/` | +| `.github/` | GitHub config | `CODEOWNERS`, `agents.json`, `copilot-instructions.md` | + +### Archives +| Directory | Purpose | Contents | +| --- | --- | --- | +| `archives/agents/` | Archived Codex task files | 433 files from closed issues | +| `archives/github-actions/` | Retired GitHub Actions | `apply-autofix/`, `autofix-commit-push/`, `codex-bootstrap/`, `update-residual-history/` | +| `archives/github-config/` | Orphaned GitHub config | `labeler.yml` (no workflow used it) | +| `archives/analysis/` | Investigation notes | `health44-pr-run-review.md` | +| `archives/docs/` | Archived documentation | Historical guides and reports | +| `archives/reports/` | Archived reports | Testing summaries, release notes | + ## Overlapping docs and their scopes | Document | Audience | Scope/status | | --- | --- | --- | From ced7fce7b9c8417fd340a81ca0bdfb9fbd73e7b0 Mon Sep 17 00:00:00 2001 From: stranske Date: Sun, 30 Nov 2025 04:46:02 +0000 Subject: [PATCH 21/40] docs: update INDEX.md with 2025-11-30 cleanup details Document the organization work done on: - agents/ folder (415 codex files, 18 ledger files archived) - .github/actions/ (4 unused actions archived) - .github/ root (CODEOWNERS fixed, labeler.yml archived) - analysis/ (investigation notes archived) - assets/ (empty placeholders removed) --- docs/INDEX.md | 34 ++++++++++++++++++++++++++++++---- 1 file changed, 30 insertions(+), 4 deletions(-) diff --git a/docs/INDEX.md b/docs/INDEX.md index 07104892e4..d875f7251e 100644 --- a/docs/INDEX.md +++ b/docs/INDEX.md @@ -26,13 +26,39 @@ Use this index to find the current contributor guides and to understand which ov ### Archives | Directory | Purpose | Contents | | --- | --- | --- | -| `archives/agents/` | Archived Codex task files | 433 files from closed issues | -| `archives/github-actions/` | Retired GitHub Actions | `apply-autofix/`, `autofix-commit-push/`, `codex-bootstrap/`, `update-residual-history/` | -| `archives/github-config/` | Orphaned GitHub config | `labeler.yml` (no workflow used it) | -| `archives/analysis/` | Investigation notes | `health44-pr-run-review.md` | +| `archives/agents/` | Archived Codex task files | 433 files from closed issues (archived 2025-11-30) | +| `archives/github-actions/` | Retired GitHub Actions | 4 unused actions (archived 2025-11-30) | +| `archives/github-config/` | Orphaned GitHub config | `labeler.yml` - no workflow used it (archived 2025-11-30) | +| `archives/analysis/` | Investigation notes | `health44-pr-run-review.md` (archived 2025-11-30) | | `archives/docs/` | Archived documentation | Historical guides and reports | | `archives/reports/` | Archived reports | Testing summaries, release notes | +#### Archive Details (2025-11-30 Cleanup) + +**agents/ folder cleanup:** +- Archived 415 `codex-*.md` task files for closed issues +- Archived 18 `ledger-*.md` files for closed issues +- Kept active task files for open issues + +**`.github/actions/` cleanup:** +- Archived `apply-autofix/` - superseded by `autofix/` +- Archived `autofix-commit-push/` - superseded by `autofix/` +- Archived `codex-bootstrap/` - superseded by `codex-bootstrap-lite/` +- Archived `update-residual-history/` - no longer referenced +- Kept: `autofix/`, `build-pr-comment/`, `codex-bootstrap-lite/`, `signature-verify/` + +**`.github/` root cleanup:** +- Fixed CODEOWNERS stale workflow references +- Archived orphaned `labeler.yml` (no `pr-path-labeler.yml` workflow exists) + +**`analysis/` folder cleanup:** +- Archived `health44-pr-run-review.md` investigation notes +- Kept active code: `cv.py`, `results.py`, `tearsheet.py`, `__init__.py` + +**`assets/` folder cleanup:** +- Removed empty placeholder PNG files (0 bytes) +- Consolidated placeholder descriptions into `screenshots/README.md` + ## Overlapping docs and their scopes | Document | Audience | Scope/status | | --- | --- | --- | From 6d921fb2daa9410988a5db8aab06fdc0f4f2fd5d Mon Sep 17 00:00:00 2001 From: stranske Date: Sun, 30 Nov 2025 04:49:57 +0000 Subject: [PATCH 22/40] docs: update INDEX.md with config, examples, notebooks review Document reviewed folders (no changes needed): - config/ - Well-organized with presets/, universe/, documented in ConfigMap.md - examples/ - Active demo scripts, legacy_streamlit_app kept for reference - notebooks/ - Single maintained notebook, old ones already archived --- docs/INDEX.md | 26 +++++++++++++++++++++++++- 1 file changed, 25 insertions(+), 1 deletion(-) diff --git a/docs/INDEX.md b/docs/INDEX.md index d875f7251e..f5d199d591 100644 --- a/docs/INDEX.md +++ b/docs/INDEX.md @@ -9,12 +9,14 @@ Use this index to find the current contributor guides and to understand which ov | --- | --- | --- | | `src/` | Main source code | `trend_analysis/` package, `trend_portfolio_app/` | | `tests/` | Unit and integration tests | pytest test files | -| `config/` | Configuration files | `defaults.yml`, `demo.yml` | +| `config/` | Configuration files | `defaults.yml`, `demo.yml`, `presets/`, `universe/` | | `scripts/` | Utility and CI scripts | `setup_env.sh`, `run_tests.sh` | | `docs/` | Documentation | Guides, references, CI docs | | `analysis/` | Analysis helpers | `cv.py`, `results.py`, `tearsheet.py` | | `assets/` | Static assets | `screenshots/` for documentation | | `demo/` | Demo data and outputs | Generated demo datasets | +| `examples/` | Usage examples | Demo scripts, legacy streamlit app | +| `notebooks/` | Jupyter notebooks | `Vol_Adj_Trend_Analysis1.5.TrEx.ipynb` (maintained) | ### Automation & CI | Directory | Purpose | Key Files | @@ -30,6 +32,7 @@ Use this index to find the current contributor guides and to understand which ov | `archives/github-actions/` | Retired GitHub Actions | 4 unused actions (archived 2025-11-30) | | `archives/github-config/` | Orphaned GitHub config | `labeler.yml` - no workflow used it (archived 2025-11-30) | | `archives/analysis/` | Investigation notes | `health44-pr-run-review.md` (archived 2025-11-30) | +| `archives/notebooks/` | Superseded notebooks | Old notebook versions in `2025/` | | `archives/docs/` | Archived documentation | Historical guides and reports | | `archives/reports/` | Archived reports | Testing summaries, release notes | @@ -59,6 +62,27 @@ Use this index to find the current contributor guides and to understand which ov - Removed empty placeholder PNG files (0 bytes) - Consolidated placeholder descriptions into `screenshots/README.md` +### Folders Reviewed (No Changes Needed) + +**`config/` folder (reviewed 2025-11-30):** +- Well-organized with clear structure +- `defaults.yml` - Master configuration schema +- `demo.yml` - Demo/test configuration +- `presets/` - User presets: `aggressive.yml`, `balanced.yml`, `conservative.yml`, `cash_constrained.yml` +- `universe/` - Universe definitions: `core.yml`, `core_plus_benchmarks.yml`, `managed_futures_min.yml` +- Specialized configs for backtesting, walk-forward analysis, etc. +- Fully documented in `docs/ConfigMap.md` + +**`examples/` folder (reviewed 2025-11-30):** +- Contains usage examples with clear README documentation +- Active scripts: `demo_robust_weighting.py`, `demo_turnover_cap.py`, `debug_fund_selection.py`, `integration_example.py`, `portfolio_analysis_report.py` +- `legacy_streamlit_app/` - Historical prototype kept for reference (documented in README_APP.md) + +**`notebooks/` folder (reviewed 2025-11-30):** +- Single maintained notebook: `Vol_Adj_Trend_Analysis1.5.TrEx.ipynb` +- Old notebooks already archived to `archives/notebooks/2025/` +- Clear README with maintenance expectations + ## Overlapping docs and their scopes | Document | Audience | Scope/status | | --- | --- | --- | From 3ccf089580b7bb5252dc8b87c572dc44b0a99c9a Mon Sep 17 00:00:00 2001 From: stranske Date: Sun, 30 Nov 2025 04:55:07 +0000 Subject: [PATCH 23/40] chore: clean up perf and reports folders - Archive reports/code_review.md (one-off analysis from PR #3877) - Fix broken symlink perf/perf_baseline.json with placeholder JSON - Update docs/performance_benchmark.md to reflect actual file location - Update docs/INDEX.md with perf/ and reports/ review notes --- .../reports/2025-11-29-code-review}/code_review.md | 0 docs/INDEX.md | 10 ++++++++++ docs/performance_benchmark.md | 6 ++---- perf/perf_baseline.json | 2 +- 4 files changed, 13 insertions(+), 5 deletions(-) rename {reports => archives/reports/2025-11-29-code-review}/code_review.md (100%) mode change 120000 => 100644 perf/perf_baseline.json diff --git a/reports/code_review.md b/archives/reports/2025-11-29-code-review/code_review.md similarity index 100% rename from reports/code_review.md rename to archives/reports/2025-11-29-code-review/code_review.md diff --git a/docs/INDEX.md b/docs/INDEX.md index f5d199d591..f0c79898e6 100644 --- a/docs/INDEX.md +++ b/docs/INDEX.md @@ -83,6 +83,16 @@ Use this index to find the current contributor guides and to understand which ov - Old notebooks already archived to `archives/notebooks/2025/` - Clear README with maintenance expectations +**`perf/` folder (reviewed 2025-11-30):** +- `perf_baseline.json` - Placeholder for performance regression baseline (not yet generated) +- `runs/` - Transient runtime logs (git-ignored) +- Fixed broken symlink that pointed to non-existent archive path +- Referenced workflow `maint-52-perf-benchmark.yml` does not exist yet + +**`reports/` folder (reviewed 2025-11-30):** +- `tearsheet.md` - Generated output from `analysis/tearsheet.py` (active, referenced in README) +- Archived `code_review.md` - one-off analysis from PR #3877 + ## Overlapping docs and their scopes | Document | Audience | Scope/status | | --- | --- | --- | diff --git a/docs/performance_benchmark.md b/docs/performance_benchmark.md index 8fc9fe0bc2..6d5dd6b7c5 100644 --- a/docs/performance_benchmark.md +++ b/docs/performance_benchmark.md @@ -18,10 +18,8 @@ runtime increases by more than `PERF_REGRESSION_PCT` (default 15%). Equal or smaller increases pass (non-strict comparator). ## Baseline -Stored at `archives/generated/2025/perf/perf_baseline.json` (generated with -rows=1200, cols=35, runs=4). The legacy path `perf/perf_baseline.json` remains -available via a symlink for CI and helper script compatibility. To regenerate -after intentional optimisation: +Stored at `perf/perf_baseline.json`. To generate a baseline after intentional +optimisation: ```bash python scripts/benchmark_performance.py \ diff --git a/perf/perf_baseline.json b/perf/perf_baseline.json deleted file mode 120000 index 0cc8d83535..0000000000 --- a/perf/perf_baseline.json +++ /dev/null @@ -1 +0,0 @@ -../archives/generated/2025/perf/perf_baseline.json \ No newline at end of file diff --git a/perf/perf_baseline.json b/perf/perf_baseline.json new file mode 100644 index 0000000000..7ff8c8cad4 --- /dev/null +++ b/perf/perf_baseline.json @@ -0,0 +1 @@ +{"_note": "Baseline not yet generated. Run: python scripts/benchmark_performance.py --rows 1200 --cols 35 --runs 4 --output perf/perf_baseline.json"} From 11d542f8a9660e3adec0d1c41f55e8e532d5bc88 Mon Sep 17 00:00:00 2001 From: stranske Date: Sun, 30 Nov 2025 05:01:46 +0000 Subject: [PATCH 24/40] chore: review scripts folder and archive one-off fix - Archive scripts/demo_export_fix.py (no references found) - Update docs/INDEX.md with scripts/ folder review notes - Update archives/scripts/README.md with new archived file scripts/ folder is well-organized with 74 scripts: - CI/Workflow scripts actively used by GitHub Actions - Core dev scripts documented in scripts/README.md - Validation tier scripts for development workflow - Performance testing scripts --- .../scripts/2025-11-30-one-off}/demo_export_fix.py | 0 archives/scripts/README.md | 5 +++++ docs/INDEX.md | 9 +++++++++ 3 files changed, 14 insertions(+) rename {scripts => archives/scripts/2025-11-30-one-off}/demo_export_fix.py (100%) diff --git a/scripts/demo_export_fix.py b/archives/scripts/2025-11-30-one-off/demo_export_fix.py similarity index 100% rename from scripts/demo_export_fix.py rename to archives/scripts/2025-11-30-one-off/demo_export_fix.py diff --git a/archives/scripts/README.md b/archives/scripts/README.md index 309d2868fa..2ecf7ee7b9 100644 --- a/archives/scripts/README.md +++ b/archives/scripts/README.md @@ -13,5 +13,10 @@ directories, so they are treated as rarely used or historical utilities. unified `trend` CLI. Last-known use: pre-unified CLI era; retained only as a reference. +## 2025-11-30-one-off + +- `demo_export_fix.py` — one-off demo export fix script; no references found + in workflows, docs, or other scripts. + If you need to revive any of these scripts, please re-home them under a supported workflow and add the appropriate documentation and ownership notes. diff --git a/docs/INDEX.md b/docs/INDEX.md index f0c79898e6..3c2a25ccd9 100644 --- a/docs/INDEX.md +++ b/docs/INDEX.md @@ -93,6 +93,15 @@ Use this index to find the current contributor guides and to understand which ov - `tearsheet.md` - Generated output from `analysis/tearsheet.py` (active, referenced in README) - Archived `code_review.md` - one-off analysis from PR #3877 +**`scripts/` folder (reviewed 2025-11-30):** +- **74 scripts** organized by category (see `scripts/README.md`) +- CI/Workflow scripts: `ci_*.py`, `ledger_*.py`, `sync_*.py`, `coverage_*.py` +- Core dev scripts: `setup_env.sh`, `run_tests.sh`, `run_streamlit.sh`, `generate_demo.py` +- Validation tiers: `dev_check.sh`, `validate_fast.sh`, `check_branch.sh` +- Performance: `benchmark_performance.py`, `compare_perf.py` +- Utilities: `archive_agents.sh`, `git_hooks.sh`, `docker_smoke.sh` +- Archived `demo_export_fix.py` - one-off fix script + ## Overlapping docs and their scopes | Document | Audience | Scope/status | | --- | --- | --- | From 82890271afba204e2de2842d8c6b82b48fe9345d Mon Sep 17 00:00:00 2001 From: stranske Date: Sun, 30 Nov 2025 05:12:31 +0000 Subject: [PATCH 25/40] chore: review streamlit_app and fix old path references - Update tests/test_streamlit_smoke_ci.py to use current streamlit_app/ path - Remove references to old app/streamlit/pages/ path - Update docs/INDEX.md with streamlit_app/ folder review streamlit_app/ structure: - Canonical pages: 1_Data, 2_Model, 3_Run, 4_Results - Legacy shims kept for test compatibility: 1_Upload, 2_Configure, 3_Results --- docs/INDEX.md | 12 ++++++++++++ tests/test_streamlit_smoke_ci.py | 5 ++--- 2 files changed, 14 insertions(+), 3 deletions(-) diff --git a/docs/INDEX.md b/docs/INDEX.md index 3c2a25ccd9..e956ae7503 100644 --- a/docs/INDEX.md +++ b/docs/INDEX.md @@ -102,6 +102,18 @@ Use this index to find the current contributor guides and to understand which ov - Utilities: `archive_agents.sh`, `git_hooks.sh`, `docker_smoke.sh` - Archived `demo_export_fix.py` - one-off fix script +**`streamlit_app/` folder (reviewed 2025-11-30):** +- Primary Streamlit UI for the Trend Portfolio Simulator +- `app.py` - Main entry point with demo button +- `components/` - Reusable UI components (charts, validation, caching) +- `pages/` - Multipage app structure: + - `1_Data.py` (canonical), `1_Upload.py` (legacy shim) + - `2_Model.py` (canonical), `2_Configure.py` (legacy shim) + - `3_Run.py` (canonical), `3_Results.py` (shim → 4_Results) + - `4_Results.py` (canonical results display) +- Shim files kept for backward test compatibility +- Updated tests to remove references to old `app/streamlit/` path + ## Overlapping docs and their scopes | Document | Audience | Scope/status | | --- | --- | --- | diff --git a/tests/test_streamlit_smoke_ci.py b/tests/test_streamlit_smoke_ci.py index e3fae3cc7a..a3b485ed69 100644 --- a/tests/test_streamlit_smoke_ci.py +++ b/tests/test_streamlit_smoke_ci.py @@ -219,7 +219,6 @@ def test_streamlit_app_pages_accessible(streamlit_app): def test_streamlit_app_run_page_exists(): """Test that the Run page file exists and can be imported.""" run_page_paths = [ - Path(__file__).parent.parent / "app" / "streamlit" / "pages" / "03_Run.py", Path(__file__).parent.parent / "streamlit_app" / "pages" / "3_Run.py", ] @@ -265,7 +264,7 @@ def test_error_handling_components(): def test_progress_reporting_components(): """Test that progress reporting components exist in the Run page.""" run_page_path = ( - Path(__file__).parent.parent / "app" / "streamlit" / "pages" / "03_Run.py" + Path(__file__).parent.parent / "streamlit_app" / "pages" / "3_Run.py" ) if not run_page_path.exists(): @@ -327,7 +326,7 @@ def test_end_to_end_analysis_simulation(demo_data, demo_config): def test_run_page_imports_successfully(): """Test that the Run page can be imported without errors.""" run_page_path = ( - Path(__file__).parent.parent / "app" / "streamlit" / "pages" / "03_Run.py" + Path(__file__).parent.parent / "streamlit_app" / "pages" / "3_Run.py" ) if not run_page_path.exists(): From db4264e332bd1eb0ecef3594acf28407509aadf6 Mon Sep 17 00:00:00 2001 From: stranske Date: Sun, 30 Nov 2025 05:36:22 +0000 Subject: [PATCH 26/40] test: reorganize workflow tests into tests/workflows/ Separate workflow/CI automation tests from core tests for future repo split: - Create tests/workflows/ directory with __init__.py - Move 33 workflow test files (test_workflow_*, test_autofix_*, test_ci_*, test_keepalive_*, test_agents_*, test_codex_belt_*, test_chatgpt_topics_*, test_issue_bridge_*, test_reusable_ci_*, test_disable_legacy_*) - Move tests/github_scripts/ to tests/workflows/github_scripts/ - Move workflow fixtures (agents_pr_meta/, keepalive/, keepalive_post_work/, orchestrator/) to tests/workflows/fixtures/ - Keep core fixture score_frame_2025-06-30.csv in tests/fixtures/ - Fix path references in harness JS files (parents[2] -> parents[3]) - Fix .github script paths in harness files - Update cross-module imports (test_disable_legacy_workflows.py) - Update docs/INDEX.md with tests/ folder organization 369 workflow tests pass after reorganization. Core tests unaffected - 3704 total tests pass. --- docs/INDEX.md | 30 +- .../agents_pr_meta/after_markers.json | 20 - .../agents_pr_meta/autofix_instruction.json | 29 - .../agents_pr_meta/automation_autofix.json | 18 - tests/fixtures/agents_pr_meta/dispatch.json | 17 - .../agents_pr_meta/html_entities.json | 20 - .../agents_pr_meta/manual_repeat.json | 24 - .../fixtures/agents_pr_meta/manual_round.json | 24 - .../agents_pr_meta/missing_marker.json | 15 - .../agents_pr_meta/missing_round.json | 15 - .../fixtures/agents_pr_meta/unauthorised.json | 13 - tests/fixtures/keepalive/command_pending.json | 42 - tests/fixtures/keepalive/dedupe.json | 26 - tests/fixtures/keepalive/dry_run.json | 26 - tests/fixtures/keepalive/gate_trigger.json | 27 - tests/fixtures/keepalive/idle_threshold.json | 63 -- .../fixtures/keepalive/legacy_keepalive.json | 33 - .../keepalive/missing_dispatch_token.json | 34 - tests/fixtures/keepalive/missing_label.json | 26 - .../fixtures/keepalive/non_codex_branch.json | 27 - tests/fixtures/keepalive/paged_comments.json | 862 ------------------ tests/fixtures/keepalive/paused.json | 42 - tests/fixtures/keepalive/refresh.json | 33 - tests/fixtures/keepalive/skip_opt_out.json | 20 - .../keepalive/unauthorised_author.json | 29 - .../keepalive_post_work/create_pr.json | 28 - .../keepalive_post_work/escalation.json | 22 - .../fork_missing_head_repo.json | 18 - .../keepalive_post_work/fork_sync.json | 32 - .../keepalive_post_work/head_change.json | 18 - .../keepalive_post_work/update_branch.json | 21 - .../orchestrator/options_passthrough.json | 14 - tests/workflows/__init__.py | 1 + .../fixtures/agents_pr_meta/harness.js | 2 +- .../fixtures/keepalive/guard_analysis.js | 2 +- .../fixtures/keepalive/harness.js | 2 +- .../fixtures/keepalive_post_work/harness.js | 2 +- .../fixtures/orchestrator/resolve_harness.js | 2 +- .../github_scripts/__init__.py | 0 .../github_scripts/test_decode_raw_input.py | 2 +- .../github_scripts/test_fallback_split.py | 2 +- .../github_scripts/test_gate_summary.py | 2 +- .../github_scripts/test_health_summarize.py | 2 +- .../test_parse_chatgpt_topics.py | 2 +- .../test_restore_branch_snapshots.py | 2 +- tests/{ => workflows}/test_agents_guard.py | 2 +- .../test_agents_orchestrator_resolve.py | 0 .../test_agents_pr_meta_keepalive.py | 0 .../test_autofix_full_pipeline.py | 0 .../{ => workflows}/test_autofix_pipeline.py | 0 .../test_autofix_pipeline_diverse.py | 0 .../test_autofix_pipeline_live_docs.py | 6 +- .../test_autofix_pipeline_tools.py | 0 .../test_autofix_pr_comment.py | 0 .../test_autofix_probe_module.py | 0 .../test_autofix_repo_regressions.py | 0 tests/{ => workflows}/test_autofix_samples.py | 0 .../test_autofix_trigger_scenario2.py | 0 .../test_chatgpt_topics_parser.py | 2 +- .../test_ci_cosmetic_repair.py | 0 .../{ => workflows}/test_ci_coverage_delta.py | 0 tests/{ => workflows}/test_ci_history.py | 0 tests/{ => workflows}/test_ci_metrics.py | 0 tests/{ => workflows}/test_ci_probe_faults.py | 0 .../test_codex_belt_pipeline.py | 0 .../test_disable_legacy_workflows.py | 2 +- .../test_issue_bridge_triggers.py | 2 +- .../test_keepalive_guard_utils.py | 4 +- .../test_keepalive_post_work.py | 0 .../test_keepalive_workflow.py | 0 .../test_reusable_ci_workflow.py | 0 .../test_workflow_agents_consolidation.py | 0 .../test_workflow_archival_issue2823.py | 0 .../test_workflow_autofix_guard.py | 0 .../test_workflow_multi_failure.py | 0 .../test_workflow_multi_failure_demo.py | 0 tests/{ => workflows}/test_workflow_naming.py | 0 .../test_workflow_selftest_consolidation.py | 0 78 files changed, 52 insertions(+), 1657 deletions(-) delete mode 100644 tests/fixtures/agents_pr_meta/after_markers.json delete mode 100644 tests/fixtures/agents_pr_meta/autofix_instruction.json delete mode 100644 tests/fixtures/agents_pr_meta/automation_autofix.json delete mode 100644 tests/fixtures/agents_pr_meta/dispatch.json delete mode 100644 tests/fixtures/agents_pr_meta/html_entities.json delete mode 100644 tests/fixtures/agents_pr_meta/manual_repeat.json delete mode 100644 tests/fixtures/agents_pr_meta/manual_round.json delete mode 100644 tests/fixtures/agents_pr_meta/missing_marker.json delete mode 100644 tests/fixtures/agents_pr_meta/missing_round.json delete mode 100644 tests/fixtures/agents_pr_meta/unauthorised.json delete mode 100644 tests/fixtures/keepalive/command_pending.json delete mode 100644 tests/fixtures/keepalive/dedupe.json delete mode 100644 tests/fixtures/keepalive/dry_run.json delete mode 100644 tests/fixtures/keepalive/gate_trigger.json delete mode 100644 tests/fixtures/keepalive/idle_threshold.json delete mode 100644 tests/fixtures/keepalive/legacy_keepalive.json delete mode 100644 tests/fixtures/keepalive/missing_dispatch_token.json delete mode 100644 tests/fixtures/keepalive/missing_label.json delete mode 100644 tests/fixtures/keepalive/non_codex_branch.json delete mode 100644 tests/fixtures/keepalive/paged_comments.json delete mode 100644 tests/fixtures/keepalive/paused.json delete mode 100644 tests/fixtures/keepalive/refresh.json delete mode 100644 tests/fixtures/keepalive/skip_opt_out.json delete mode 100644 tests/fixtures/keepalive/unauthorised_author.json delete mode 100644 tests/fixtures/keepalive_post_work/create_pr.json delete mode 100644 tests/fixtures/keepalive_post_work/escalation.json delete mode 100644 tests/fixtures/keepalive_post_work/fork_missing_head_repo.json delete mode 100644 tests/fixtures/keepalive_post_work/fork_sync.json delete mode 100644 tests/fixtures/keepalive_post_work/head_change.json delete mode 100644 tests/fixtures/keepalive_post_work/update_branch.json delete mode 100644 tests/fixtures/orchestrator/options_passthrough.json create mode 100644 tests/workflows/__init__.py rename tests/{ => workflows}/fixtures/agents_pr_meta/harness.js (98%) rename tests/{ => workflows}/fixtures/keepalive/guard_analysis.js (89%) rename tests/{ => workflows}/fixtures/keepalive/harness.js (99%) rename tests/{ => workflows}/fixtures/keepalive_post_work/harness.js (99%) rename tests/{ => workflows}/fixtures/orchestrator/resolve_harness.js (94%) rename tests/{ => workflows}/github_scripts/__init__.py (100%) rename tests/{ => workflows}/github_scripts/test_decode_raw_input.py (99%) rename tests/{ => workflows}/github_scripts/test_fallback_split.py (98%) rename tests/{ => workflows}/github_scripts/test_gate_summary.py (99%) rename tests/{ => workflows}/github_scripts/test_health_summarize.py (99%) rename tests/{ => workflows}/github_scripts/test_parse_chatgpt_topics.py (99%) rename tests/{ => workflows}/github_scripts/test_restore_branch_snapshots.py (99%) rename tests/{ => workflows}/test_agents_guard.py (99%) rename tests/{ => workflows}/test_agents_orchestrator_resolve.py (100%) rename tests/{ => workflows}/test_agents_pr_meta_keepalive.py (100%) rename tests/{ => workflows}/test_autofix_full_pipeline.py (100%) rename tests/{ => workflows}/test_autofix_pipeline.py (100%) rename tests/{ => workflows}/test_autofix_pipeline_diverse.py (100%) rename tests/{ => workflows}/test_autofix_pipeline_live_docs.py (98%) rename tests/{ => workflows}/test_autofix_pipeline_tools.py (100%) rename tests/{ => workflows}/test_autofix_pr_comment.py (100%) rename tests/{ => workflows}/test_autofix_probe_module.py (100%) rename tests/{ => workflows}/test_autofix_repo_regressions.py (100%) rename tests/{ => workflows}/test_autofix_samples.py (100%) rename tests/{ => workflows}/test_autofix_trigger_scenario2.py (100%) rename tests/{ => workflows}/test_chatgpt_topics_parser.py (99%) rename tests/{ => workflows}/test_ci_cosmetic_repair.py (100%) rename tests/{ => workflows}/test_ci_coverage_delta.py (100%) rename tests/{ => workflows}/test_ci_history.py (100%) rename tests/{ => workflows}/test_ci_metrics.py (100%) rename tests/{ => workflows}/test_ci_probe_faults.py (100%) rename tests/{ => workflows}/test_codex_belt_pipeline.py (100%) rename tests/{ => workflows}/test_disable_legacy_workflows.py (98%) rename tests/{ => workflows}/test_issue_bridge_triggers.py (99%) rename tests/{ => workflows}/test_keepalive_guard_utils.py (95%) rename tests/{ => workflows}/test_keepalive_post_work.py (100%) rename tests/{ => workflows}/test_keepalive_workflow.py (100%) rename tests/{ => workflows}/test_reusable_ci_workflow.py (100%) rename tests/{ => workflows}/test_workflow_agents_consolidation.py (100%) rename tests/{ => workflows}/test_workflow_archival_issue2823.py (100%) rename tests/{ => workflows}/test_workflow_autofix_guard.py (100%) rename tests/{ => workflows}/test_workflow_multi_failure.py (100%) rename tests/{ => workflows}/test_workflow_multi_failure_demo.py (100%) rename tests/{ => workflows}/test_workflow_naming.py (100%) rename tests/{ => workflows}/test_workflow_selftest_consolidation.py (100%) diff --git a/docs/INDEX.md b/docs/INDEX.md index e956ae7503..709d0b78b2 100644 --- a/docs/INDEX.md +++ b/docs/INDEX.md @@ -8,7 +8,7 @@ Use this index to find the current contributor guides and to understand which ov | Directory | Purpose | Key Files | | --- | --- | --- | | `src/` | Main source code | `trend_analysis/` package, `trend_portfolio_app/` | -| `tests/` | Unit and integration tests | pytest test files | +| `tests/` | Unit and integration tests | See tests/ organization below | | `config/` | Configuration files | `defaults.yml`, `demo.yml`, `presets/`, `universe/` | | `scripts/` | Utility and CI scripts | `setup_env.sh`, `run_tests.sh` | | `docs/` | Documentation | Guides, references, CI docs | @@ -114,6 +114,34 @@ Use this index to find the current contributor guides and to understand which ov - Shim files kept for backward test compatibility - Updated tests to remove references to old `app/streamlit/` path +**`tests/` folder (reorganized 2025-11-30):** +- **3707+ tests** across multiple categories +- **Major reorganization**: Workflow/CI tests separated into `tests/workflows/` for future repo split + +| Subfolder | Purpose | Contents | +| --- | --- | --- | +| `tests/workflows/` | **Workflow system tests** | 33 test files, `github_scripts/`, `fixtures/` | +| `tests/app/` | Streamlit app tests | 10 test files | +| `tests/backtesting/` | Backtesting tests | 2 test files | +| `tests/trend_analysis/` | Core analysis tests | 8 test files | +| `tests/scripts/` | Script tests | 6 test files | +| `tests/tools/` | Tool tests | 4 test files | +| `tests/unit/` | Unit tests | `util/` subfolder | +| `tests/smoke/` | Smoke tests | 3 test files | +| `tests/soft_coverage/` | Coverage tracking | 4 test files | +| `tests/golden/` | Golden master tests | 2 test files | +| `tests/fixtures/` | Core test fixtures | `score_frame_2025-06-30.csv` | +| `tests/data/` | Test data files | 6 files | +| `tests/proxy/` | Proxy tests | 1 test file | + +**Workflow tests reorganization details:** +- Created `tests/workflows/` to separate CI/automation tests from core tests +- Moved 33 workflow-related test files (`test_workflow_*.py`, `test_autofix_*.py`, `test_ci_*.py`, `test_keepalive_*.py`, `test_agents_*.py`, etc.) +- Moved `tests/github_scripts/` → `tests/workflows/github_scripts/` +- Moved workflow fixtures (`agents_pr_meta/`, `keepalive/`, `keepalive_post_work/`, `orchestrator/`) to `tests/workflows/fixtures/` +- Updated path references in harness JS files and test imports +- Core fixture `score_frame_2025-06-30.csv` remains in `tests/fixtures/` + ## Overlapping docs and their scopes | Document | Audience | Scope/status | | --- | --- | --- | diff --git a/tests/fixtures/agents_pr_meta/after_markers.json b/tests/fixtures/agents_pr_meta/after_markers.json deleted file mode 100644 index 2ac1154b21..0000000000 --- a/tests/fixtures/agents_pr_meta/after_markers.json +++ /dev/null @@ -1,20 +0,0 @@ -{ - "comment": { - "id": 9988776655, - "html_url": "https://github.com/stranske/Trend_Model_Project/pull/4000#issuecomment-9988776655", - "body": "<- After: keepalive-round: 5 -->\n<- After: codex-keepalive-marker -->\n<- After: keepalive-trace: manual-test-2025-11-05-01-35 -->\n\n@codex please continue", - "user": { "login": "stranske" } - }, - "issue": { "number": 4000 }, - "pull": { - "number": 4000, - "title": "feat: ensure keepalive detection", - "body": "Related to #3260", - "head": { "ref": "codex/issue-3260-keepalive" }, - "base": { "ref": "phase-2-dev" } - }, - "reactions": [], - "env": { - "ALLOWED_LOGINS": "stranske" - } -} diff --git a/tests/fixtures/agents_pr_meta/autofix_instruction.json b/tests/fixtures/agents_pr_meta/autofix_instruction.json deleted file mode 100644 index 7dd60a3cc5..0000000000 --- a/tests/fixtures/agents_pr_meta/autofix_instruction.json +++ /dev/null @@ -1,29 +0,0 @@ -{ - "comment": { - "id": 6002001, - "body": "@codex use the scope, acceptance criteria, and task list so the keepalive workflow continues nudging until everything is complete. Work through the tasks, checking them off only after each acceptance criterion is satisfied, but check during each comment implementation and check off tasks and acceptance criteria that have been satisfied and repost the current version of the initial scope, task list and acceptance criteria each time that any have been newly completed.", - "user": { - "login": "chatgpt-codex-connector" - } - }, - "issue": { - "number": 3273 - }, - "pull": { - "number": 3273, - "head": { - "ref": "fix/keepalive-autofix" - }, - "base": { - "ref": "phase-2-dev" - }, - "title": "Keepalive auto fix scenario (#3260)", - "body": "Testing auto insertion of keepalive markers referencing (#3260)." - }, - "comments": [ - { - "id": 6002001, - "body": "@codex use the scope, acceptance criteria, and task list so the keepalive workflow continues nudging until everything is complete. Work through the tasks, checking them off only after each acceptance criterion is satisfied, but check during each comment implementation and check off tasks and acceptance criteria that have been satisfied and repost the current version of the initial scope, task list and acceptance criteria each time that any have been newly completed." - } - ] -} diff --git a/tests/fixtures/agents_pr_meta/automation_autofix.json b/tests/fixtures/agents_pr_meta/automation_autofix.json deleted file mode 100644 index d912ad5fcc..0000000000 --- a/tests/fixtures/agents_pr_meta/automation_autofix.json +++ /dev/null @@ -1,18 +0,0 @@ -{ - "comment": { - "id": 3492705833, - "body": "Autofix attempt 1/2 for PR #3289.\n\n- Trigger: https://github.com/stranske/Trend_Model_Project/actions/runs/19112108436\n- Branch: autofix/3289-09774fb\n- Head SHA: 09774fb\n- Result: no changes required\n\n", - "user": { "login": "stranske" }, - "html_url": "https://github.com/stranske/Trend_Model_Project/pull/3289#issuecomment-3492705833" - }, - "issue": { "number": 3289 }, - "pull": { - "number": 3289, - "title": "chore(codex): bootstrap PR for issue #3279", - "head": { "ref": "codex/issue-3279" }, - "base": { "ref": "phase-2-dev" } - }, - "env": { - "ALLOWED_LOGINS": "stranske" - } -} diff --git a/tests/fixtures/agents_pr_meta/dispatch.json b/tests/fixtures/agents_pr_meta/dispatch.json deleted file mode 100644 index dd24edb5c7..0000000000 --- a/tests/fixtures/agents_pr_meta/dispatch.json +++ /dev/null @@ -1,17 +0,0 @@ -{ - "comment": { - "id": 987654321, - "html_url": "https://github.com/stranske/Trend_Model_Project/pull/3230#issuecomment-987654321", - "body": "\n\n\n\n@codex continue please", - "user": { "login": "stranske" } - }, - "issue": { "number": 3230 }, - "pull": { - "number": 3230, - "title": "chore(codex): bootstrap (#3227)", - "body": "Implements #3227", - "head": { "ref": "codex/issue-3227-keepalive" }, - "base": { "ref": "phase-2-dev" } - }, - "reactions": [] -} diff --git a/tests/fixtures/agents_pr_meta/html_entities.json b/tests/fixtures/agents_pr_meta/html_entities.json deleted file mode 100644 index b6bd2c159f..0000000000 --- a/tests/fixtures/agents_pr_meta/html_entities.json +++ /dev/null @@ -1,20 +0,0 @@ -{ - "comment": { - "id": 9988776656, - "html_url": "https://github.com/stranske/Trend_Model_Project/pull/4001#issuecomment-9988776656", - "body": "&lt;!-- codex-keepalive-marker --&gt;\n&lt;- After: keepalive-round: 6 --&gt;\n&lt;- After: keepalive-trace: double-sanitized-check --&gt;\n\n@codex please continue", - "user": { "login": "stranske" } - }, - "issue": { "number": 4001 }, - "pull": { - "number": 4001, - "title": "feat: ensure keepalive detection", - "body": "Related to #3260", - "head": { "ref": "codex/issue-3260-keepalive" }, - "base": { "ref": "phase-2-dev" } - }, - "reactions": [], - "env": { - "ALLOWED_LOGINS": "stranske" - } -} diff --git a/tests/fixtures/agents_pr_meta/manual_repeat.json b/tests/fixtures/agents_pr_meta/manual_repeat.json deleted file mode 100644 index 88fc161b4b..0000000000 --- a/tests/fixtures/agents_pr_meta/manual_repeat.json +++ /dev/null @@ -1,24 +0,0 @@ -{ - "comment": { - "id": 7002001, - "body": "@codex use the scope, acceptance criteria, and task list so the keepalive workflow continues nudging until everything is complete. Work through the tasks, checking them off only after each acceptance criterion is satisfied, but check during each comment implementation and check off tasks and acceptance criteria that have been satisfied and repost the current version of the initial scope, task list and acceptance criteria each time that any have been newly completed.", - "user": { "login": "stranske" }, - "html_url": "https://github.com/stranske/Trend_Model_Project/pull/4003#issuecomment-7002001" - }, - "comments": [ - { - "id": 6002001, - "body": "\n\n\n@codex initial instruction" - } - ], - "issue": { "number": 4003 }, - "pull": { - "number": 4003, - "title": "fix: keepalive manual repeat", - "head": { "ref": "codex/issue-4003" }, - "base": { "ref": "phase-2-dev" } - }, - "env": { - "ALLOWED_LOGINS": "stranske" - } -} diff --git a/tests/fixtures/agents_pr_meta/manual_round.json b/tests/fixtures/agents_pr_meta/manual_round.json deleted file mode 100644 index 17c4205836..0000000000 --- a/tests/fixtures/agents_pr_meta/manual_round.json +++ /dev/null @@ -1,24 +0,0 @@ -{ - "comment": { - "id": 5002001, - "body": "@codex use the scope, acceptance criteria, and task list so the keepalive workflow continues nudging until everything is complete. Work through the tasks, checking them off only after each acceptance criterion is satisfied, but check during each comment implementation and check off tasks and acceptance criteria that have been satisfied and repost the current version of the initial scope, task list and acceptance criteria each time that any have been newly completed.", - "user": { "login": "stranske" }, - "html_url": "https://github.com/stranske/Trend_Model_Project/pull/4002#issuecomment-5002001" - }, - "comments": [ - { - "id": 4002000, - "body": "\n\n\nInitial instruction" - } - ], - "issue": { "number": 4002 }, - "pull": { - "number": 4002, - "title": "fix: ensure keepalive automation", - "head": { "ref": "codex/issue-4002" }, - "base": { "ref": "phase-2-dev" } - }, - "env": { - "ALLOWED_LOGINS": "stranske" - } -} diff --git a/tests/fixtures/agents_pr_meta/missing_marker.json b/tests/fixtures/agents_pr_meta/missing_marker.json deleted file mode 100644 index c12f389223..0000000000 --- a/tests/fixtures/agents_pr_meta/missing_marker.json +++ /dev/null @@ -1,15 +0,0 @@ -{ - "comment": { - "body": "\nNo sentinel here", - "user": { "login": "stranske" }, - "html_url": "https://github.com/stranske/Trend_Model_Project/pull/4001#issuecomment-4001001", - "id": 4001001 - }, - "issue": { "number": 4001 }, - "pull": { - "number": 4001, - "title": "feat: update (#4001)", - "head": { "ref": "codex/issue-4001" }, - "base": { "ref": "main" } - } -} diff --git a/tests/fixtures/agents_pr_meta/missing_round.json b/tests/fixtures/agents_pr_meta/missing_round.json deleted file mode 100644 index 078a105fc9..0000000000 --- a/tests/fixtures/agents_pr_meta/missing_round.json +++ /dev/null @@ -1,15 +0,0 @@ -{ - "comment": { - "id": 1122334455, - "body": "\n\n@codex missing round marker", - "user": { "login": "stranske" }, - "html_url": "https://github.com/stranske/Trend_Model_Project/pull/4001#issuecomment-1122334455" - }, - "issue": { "number": 4001 }, - "pull": { - "number": 4001, - "title": "feat: update (#4001)", - "head": { "ref": "codex/issue-4001" }, - "base": { "ref": "main" } - } -} diff --git a/tests/fixtures/agents_pr_meta/unauthorised.json b/tests/fixtures/agents_pr_meta/unauthorised.json deleted file mode 100644 index 59ecfdd4f8..0000000000 --- a/tests/fixtures/agents_pr_meta/unauthorised.json +++ /dev/null @@ -1,13 +0,0 @@ -{ - "comment": { - "body": "\n\n\n@codex status?", - "user": { "login": "helper-bot" } - }, - "issue": { "number": 512 }, - "pull": { - "number": 512, - "title": "chore: helper (#512)", - "head": { "ref": "codex/issue-512" }, - "base": { "ref": "main" } - } -} diff --git a/tests/fixtures/keepalive/command_pending.json b/tests/fixtures/keepalive/command_pending.json deleted file mode 100644 index a2e8decaf5..0000000000 --- a/tests/fixtures/keepalive/command_pending.json +++ /dev/null @@ -1,42 +0,0 @@ -{ - "repo": {"owner": "stranske", "repo": "Trend_Model_Project"}, - "now": "2024-05-18T12:00:00Z", - "env": { - "OPTIONS_JSON": "{}", - "DRY_RUN": "false" - }, - "pulls": [ - { - "number": 606, - "labels": ["agents:keepalive", "agent:codex"], - "comments": [ - { - "user": {"login": "triage-bot"}, - "body": "@codex plan-and-execute", - "created_at": "2024-05-18T11:55:00Z" - }, - { - "user": {"login": "chatgpt-codex-connector"}, - "body": "Daily update\n- [ ] Refresh datasets", - "created_at": "2024-05-18T11:40:00Z" - } - ] - }, - { - "number": 707, - "labels": ["agents:keepalive", "agent:codex"], - "comments": [ - { - "user": {"login": "triage-bot"}, - "body": "@codex plan-and-execute", - "created_at": "2024-05-18T10:40:00Z" - }, - { - "user": {"login": "chatgpt-codex-connector"}, - "body": "Checklist\n- [ ] Extract scripts\n- [x] Prepare branch", - "created_at": "2024-05-18T10:30:00Z" - } - ] - } - ] -} diff --git a/tests/fixtures/keepalive/dedupe.json b/tests/fixtures/keepalive/dedupe.json deleted file mode 100644 index a9626348e0..0000000000 --- a/tests/fixtures/keepalive/dedupe.json +++ /dev/null @@ -1,26 +0,0 @@ -{ - "repo": {"owner": "stranske", "repo": "Trend_Model_Project"}, - "now": "2024-05-18T12:00:00Z", - "env": { - "OPTIONS_JSON": "{\"keepalive_labels\": \"agent:codex, Agent:Codex ,agent:triage,AGENT:TRIAGE\", \"keepalive_agent_logins\": \"chatgpt-codex-connector,ChatGPT-Codex-Connector,Helper-Bot,helper-bot\"}", - "DRY_RUN": "false" - }, - "pulls": [ - { - "number": 505, - "labels": ["agent:codex", "agent:triage"], - "comments": [ - { - "user": {"login": "triage-bot"}, - "body": "@codex plan-and-execute", - "created_at": "2024-05-18T07:30:00Z" - }, - { - "user": {"login": "chatgpt-codex-connector"}, - "body": "Checklist\n- [ ] Update notebook", - "created_at": "2024-05-18T08:00:00Z" - } - ] - } - ] -} diff --git a/tests/fixtures/keepalive/dry_run.json b/tests/fixtures/keepalive/dry_run.json deleted file mode 100644 index ce655e9f0b..0000000000 --- a/tests/fixtures/keepalive/dry_run.json +++ /dev/null @@ -1,26 +0,0 @@ -{ - "repo": {"owner": "stranske", "repo": "Trend_Model_Project"}, - "now": "2024-05-18T12:00:00Z", - "env": { - "OPTIONS_JSON": "{}", - "DRY_RUN": "true" - }, - "pulls": [ - { - "number": 404, - "labels": ["agents:keepalive", "agent:codex"], - "comments": [ - { - "user": {"login": "triage-bot"}, - "body": "@codex plan-and-execute", - "created_at": "2024-05-18T09:15:00Z" - }, - { - "user": {"login": "chatgpt-codex-connector"}, - "body": "Status\n- [ ] Finish report", - "created_at": "2024-05-18T09:45:00Z" - } - ] - } - ] -} diff --git a/tests/fixtures/keepalive/gate_trigger.json b/tests/fixtures/keepalive/gate_trigger.json deleted file mode 100644 index daad1b237b..0000000000 --- a/tests/fixtures/keepalive/gate_trigger.json +++ /dev/null @@ -1,27 +0,0 @@ -{ - "repo": {"owner": "stranske", "repo": "Trend_Model_Project"}, - "now": "2024-05-18T12:00:00Z", - "env": { - "OPTIONS_JSON": "{\"triggered_by_gate\": true, \"keepalive_idle_minutes\": 10}", - "DRY_RUN": "false" - }, - "pulls": [ - { - "number": 101, - "labels": ["agents:keepalive", "agent:codex"], - "comments": [ - { - "user": {"login": "triage-bot"}, - "body": "@codex plan-and-execute", - "created_at": "2024-05-18T11:58:00Z" - }, - { - "user": {"login": "chatgpt-codex-connector"}, - "body": "Working on it\n- [ ] Complete task\n- [ ] Review output", - "created_at": "2024-05-18T11:58:00Z", - "updated_at": "2024-05-18T11:58:00Z" - } - ] - } - ] -} diff --git a/tests/fixtures/keepalive/idle_threshold.json b/tests/fixtures/keepalive/idle_threshold.json deleted file mode 100644 index 8b8829f6d9..0000000000 --- a/tests/fixtures/keepalive/idle_threshold.json +++ /dev/null @@ -1,63 +0,0 @@ -{ - "repo": {"owner": "stranske", "repo": "Trend_Model_Project"}, - "now": "2024-05-18T12:00:00Z", - "env": { - "OPTIONS_JSON": "{}", - "DRY_RUN": "false" - }, - "pulls": [ - { - "number": 101, - "labels": ["agents:keepalive", "agent:codex"], - "comments": [ - { - "user": {"login": "triage-bot"}, - "body": "@codex plan-and-execute", - "created_at": "2024-05-18T08:00:00Z" - }, - { - "user": {"login": "chatgpt-codex-connector"}, - "body": "Daily update\n- [ ] Review signal output\n- [x] Stage summary", - "created_at": "2024-05-18T09:00:00Z" - } - ] - }, - { - "number": 202, - "labels": ["agents:keepalive", "agent:codex"], - "comments": [ - { - "user": {"login": "triage-bot"}, - "body": "@codex plan-and-execute", - "created_at": "2024-05-18T11:40:00Z" - }, - { - "user": {"login": "chatgpt-codex-connector"}, - "body": "Progress\n- [ ] Refresh datasets", - "created_at": "2024-05-18T11:55:00Z" - } - ] - }, - { - "number": 303, - "labels": ["agents:keepalive", "agent:codex"], - "comments": [ - { - "user": {"login": "triage-bot"}, - "body": "@codex plan-and-execute", - "created_at": "2024-05-18T09:30:00Z" - }, - { - "user": {"login": "chatgpt-codex-connector"}, - "body": "Checklist\n- [ ] Verify metrics", - "created_at": "2024-05-18T09:45:00Z" - }, - { - "user": {"login": "stranske-automation-bot"}, - "body": "\n\n\n@codex plan-and-execute\n\n**Keepalive Round 1**\n\nContinue incremental work toward acceptance criteria. Use the current checklist and update task statuses.\nPost an updated summary when this round completes.\n", - "created_at": "2024-05-18T11:50:00Z" - } - ] - } - ] -} diff --git a/tests/fixtures/keepalive/legacy_keepalive.json b/tests/fixtures/keepalive/legacy_keepalive.json deleted file mode 100644 index 7bc1cc2b40..0000000000 --- a/tests/fixtures/keepalive/legacy_keepalive.json +++ /dev/null @@ -1,33 +0,0 @@ -{ - "repo": {"owner": "stranske", "repo": "Trend_Model_Project"}, - "now": "2024-05-18T12:00:00Z", - "env": { - "OPTIONS_JSON": "{}", - "DRY_RUN": "false" - }, - "pulls": [ - { - "number": 909, - "head": {"ref": "codex/issue-909-upgrade"}, - "labels": ["agents:keepalive", "agent:codex"], - "comments": [ - { - "user": {"login": "triage-bot"}, - "body": "@codex plan-and-execute", - "created_at": "2024-05-18T08:00:00Z" - }, - { - "user": {"login": "chatgpt-codex-connector"}, - "body": "Checklist\\n- [ ] Refresh datasets\\n- [x] Draft summary", - "created_at": "2024-05-18T09:00:00Z" - }, - { - "id": 4242, - "user": {"login": "stranske-automation-bot"}, - "body": "@codex plan-and-execute\\n\\nCodex, 1/2 checklist item remains unchecked (completed 1).\\n\\nKeepalive mode: ON", - "created_at": "2024-05-18T09:10:00Z" - } - ] - } - ] -} diff --git a/tests/fixtures/keepalive/missing_dispatch_token.json b/tests/fixtures/keepalive/missing_dispatch_token.json deleted file mode 100644 index a1c1f289bc..0000000000 --- a/tests/fixtures/keepalive/missing_dispatch_token.json +++ /dev/null @@ -1,34 +0,0 @@ -{ - "repo": {"owner": "stranske", "repo": "Trend_Model_Project"}, - "now": "2024-05-18T12:00:00Z", - "env": { - "OPTIONS_JSON": "{}", - "DRY_RUN": "false", - "ACTIONS_BOT_PAT": "" - }, - "pulls": [ - { - "number": 909, - "labels": ["agents:keepalive", "agent:codex"], - "comments": [ - { - "user": {"login": "triage-bot"}, - "body": "@codex plan-and-execute", - "created_at": "2024-05-18T08:30:00Z" - }, - { - "user": {"login": "chatgpt-codex-connector"}, - "body": "Checklist\n- [ ] Verify metrics\n- [x] Stage summary", - "created_at": "2024-05-18T08:45:00Z" - }, - { - "id": 123456, - "user": {"login": "stranske-automation-bot"}, - "body": "\n\n\n@codex plan-and-execute\n\n**Keepalive Round 1**\n\nContinue incremental work toward acceptance criteria. Use the current checklist and update task statuses.\nPost an updated summary when this round completes.\n\nCodex, 1/2 checklist item remains unchecked (completed 1).", - "created_at": "2024-05-18T09:00:00Z", - "updated_at": "2024-05-18T09:00:00Z" - } - ] - } - ] -} diff --git a/tests/fixtures/keepalive/missing_label.json b/tests/fixtures/keepalive/missing_label.json deleted file mode 100644 index fbaee42ed8..0000000000 --- a/tests/fixtures/keepalive/missing_label.json +++ /dev/null @@ -1,26 +0,0 @@ -{ - "repo": {"owner": "stranske", "repo": "Trend_Model_Project"}, - "now": "2025-11-07T12:00:00Z", - "env": { - "OPTIONS_JSON": "{}", - "DRY_RUN": "false" - }, - "pulls": [ - { - "number": 612, - "labels": ["agent:codex"], - "comments": [ - { - "user": {"login": "chatgpt-codex-connector"}, - "body": "Checklist\\n- [ ] Update coverage report\\n- [x] Refresh docs", - "created_at": "2025-11-07T08:00:00Z" - }, - { - "user": {"login": "stranske"}, - "body": "@codex continuing keepalive [keepalive]\n\nKeepalive instructions remain outstanding.", - "created_at": "2025-11-07T09:00:00Z" - } - ] - } - ] -} diff --git a/tests/fixtures/keepalive/non_codex_branch.json b/tests/fixtures/keepalive/non_codex_branch.json deleted file mode 100644 index fe94e88f55..0000000000 --- a/tests/fixtures/keepalive/non_codex_branch.json +++ /dev/null @@ -1,27 +0,0 @@ -{ - "repo": {"owner": "stranske", "repo": "Trend_Model_Project"}, - "now": "2024-05-18T12:00:00Z", - "env": { - "OPTIONS_JSON": "{}", - "DRY_RUN": "false" - }, - "pulls": [ - { - "number": 111, - "head": {"ref": "feature/non-codex-update"}, - "labels": ["agents:keepalive", "agent:codex"], - "comments": [ - { - "user": {"login": "triage-bot"}, - "body": "@codex plan-and-execute", - "created_at": "2024-05-18T09:00:00Z" - }, - { - "user": {"login": "chatgpt-codex-connector"}, - "body": "Daily status\\n- [ ] Align data feed", - "created_at": "2024-05-18T09:30:00Z" - } - ] - } - ] -} diff --git a/tests/fixtures/keepalive/paged_comments.json b/tests/fixtures/keepalive/paged_comments.json deleted file mode 100644 index a622f2b66e..0000000000 --- a/tests/fixtures/keepalive/paged_comments.json +++ /dev/null @@ -1,862 +0,0 @@ -{ - "repo": { - "owner": "stranske", - "repo": "Trend_Model_Project" - }, - "now": "2024-05-18T12:00:00Z", - "env": { - "OPTIONS_JSON": "{}", - "DRY_RUN": "false" - }, - "pulls": [ - { - "number": 808, - "labels": [ - "agents:keepalive", - "agent:codex" - ], - "comments": [ - { - "user": { - "login": "user0" - }, - "body": "Placeholder comment 0", - "created_at": "2024-05-17T00:00:00Z" - }, - { - "user": { - "login": "user1" - }, - "body": "Placeholder comment 1", - "created_at": "2024-05-17T00:10:00Z" - }, - { - "user": { - "login": "user2" - }, - "body": "Placeholder comment 2", - "created_at": "2024-05-17T00:20:00Z" - }, - { - "user": { - "login": "user3" - }, - "body": "Placeholder comment 3", - "created_at": "2024-05-17T00:30:00Z" - }, - { - "user": { - "login": "user4" - }, - "body": "Placeholder comment 4", - "created_at": "2024-05-17T00:40:00Z" - }, - { - "user": { - "login": "user5" - }, - "body": "Placeholder comment 5", - "created_at": "2024-05-17T00:50:00Z" - }, - { - "user": { - "login": "user6" - }, - "body": "Placeholder comment 6", - "created_at": "2024-05-17T01:00:00Z" - }, - { - "user": { - "login": "user7" - }, - "body": "Placeholder comment 7", - "created_at": "2024-05-17T01:10:00Z" - }, - { - "user": { - "login": "user8" - }, - "body": "Placeholder comment 8", - "created_at": "2024-05-17T01:20:00Z" - }, - { - "user": { - "login": "user9" - }, - "body": "Placeholder comment 9", - "created_at": "2024-05-17T01:30:00Z" - }, - { - "user": { - "login": "user10" - }, - "body": "Placeholder comment 10", - "created_at": "2024-05-17T01:40:00Z" - }, - { - "user": { - "login": "user11" - }, - "body": "Placeholder comment 11", - "created_at": "2024-05-17T01:50:00Z" - }, - { - "user": { - "login": "user12" - }, - "body": "Placeholder comment 12", - "created_at": "2024-05-17T02:00:00Z" - }, - { - "user": { - "login": "user13" - }, - "body": "Placeholder comment 13", - "created_at": "2024-05-17T02:10:00Z" - }, - { - "user": { - "login": "user14" - }, - "body": "Placeholder comment 14", - "created_at": "2024-05-17T02:20:00Z" - }, - { - "user": { - "login": "user15" - }, - "body": "Placeholder comment 15", - "created_at": "2024-05-17T02:30:00Z" - }, - { - "user": { - "login": "user16" - }, - "body": "Placeholder comment 16", - "created_at": "2024-05-17T02:40:00Z" - }, - { - "user": { - "login": "user17" - }, - "body": "Placeholder comment 17", - "created_at": "2024-05-17T02:50:00Z" - }, - { - "user": { - "login": "user18" - }, - "body": "Placeholder comment 18", - "created_at": "2024-05-17T03:00:00Z" - }, - { - "user": { - "login": "user19" - }, - "body": "Placeholder comment 19", - "created_at": "2024-05-17T03:10:00Z" - }, - { - "user": { - "login": "user20" - }, - "body": "Placeholder comment 20", - "created_at": "2024-05-17T03:20:00Z" - }, - { - "user": { - "login": "user21" - }, - "body": "Placeholder comment 21", - "created_at": "2024-05-17T03:30:00Z" - }, - { - "user": { - "login": "user22" - }, - "body": "Placeholder comment 22", - "created_at": "2024-05-17T03:40:00Z" - }, - { - "user": { - "login": "user23" - }, - "body": "Placeholder comment 23", - "created_at": "2024-05-17T03:50:00Z" - }, - { - "user": { - "login": "user24" - }, - "body": "Placeholder comment 24", - "created_at": "2024-05-17T04:00:00Z" - }, - { - "user": { - "login": "user25" - }, - "body": "Placeholder comment 25", - "created_at": "2024-05-17T04:10:00Z" - }, - { - "user": { - "login": "user26" - }, - "body": "Placeholder comment 26", - "created_at": "2024-05-17T04:20:00Z" - }, - { - "user": { - "login": "user27" - }, - "body": "Placeholder comment 27", - "created_at": "2024-05-17T04:30:00Z" - }, - { - "user": { - "login": "user28" - }, - "body": "Placeholder comment 28", - "created_at": "2024-05-17T04:40:00Z" - }, - { - "user": { - "login": "user29" - }, - "body": "Placeholder comment 29", - "created_at": "2024-05-17T04:50:00Z" - }, - { - "user": { - "login": "user30" - }, - "body": "Placeholder comment 30", - "created_at": "2024-05-17T05:00:00Z" - }, - { - "user": { - "login": "user31" - }, - "body": "Placeholder comment 31", - "created_at": "2024-05-17T05:10:00Z" - }, - { - "user": { - "login": "user32" - }, - "body": "Placeholder comment 32", - "created_at": "2024-05-17T05:20:00Z" - }, - { - "user": { - "login": "user33" - }, - "body": "Placeholder comment 33", - "created_at": "2024-05-17T05:30:00Z" - }, - { - "user": { - "login": "user34" - }, - "body": "Placeholder comment 34", - "created_at": "2024-05-17T05:40:00Z" - }, - { - "user": { - "login": "user35" - }, - "body": "Placeholder comment 35", - "created_at": "2024-05-17T05:50:00Z" - }, - { - "user": { - "login": "user36" - }, - "body": "Placeholder comment 36", - "created_at": "2024-05-17T06:00:00Z" - }, - { - "user": { - "login": "user37" - }, - "body": "Placeholder comment 37", - "created_at": "2024-05-17T06:10:00Z" - }, - { - "user": { - "login": "user38" - }, - "body": "Placeholder comment 38", - "created_at": "2024-05-17T06:20:00Z" - }, - { - "user": { - "login": "user39" - }, - "body": "Placeholder comment 39", - "created_at": "2024-05-17T06:30:00Z" - }, - { - "user": { - "login": "user40" - }, - "body": "Placeholder comment 40", - "created_at": "2024-05-17T06:40:00Z" - }, - { - "user": { - "login": "user41" - }, - "body": "Placeholder comment 41", - "created_at": "2024-05-17T06:50:00Z" - }, - { - "user": { - "login": "user42" - }, - "body": "Placeholder comment 42", - "created_at": "2024-05-17T07:00:00Z" - }, - { - "user": { - "login": "user43" - }, - "body": "Placeholder comment 43", - "created_at": "2024-05-17T07:10:00Z" - }, - { - "user": { - "login": "user44" - }, - "body": "Placeholder comment 44", - "created_at": "2024-05-17T07:20:00Z" - }, - { - "user": { - "login": "user45" - }, - "body": "Placeholder comment 45", - "created_at": "2024-05-17T07:30:00Z" - }, - { - "user": { - "login": "user46" - }, - "body": "Placeholder comment 46", - "created_at": "2024-05-17T07:40:00Z" - }, - { - "user": { - "login": "user47" - }, - "body": "Placeholder comment 47", - "created_at": "2024-05-17T07:50:00Z" - }, - { - "user": { - "login": "user48" - }, - "body": "Placeholder comment 48", - "created_at": "2024-05-17T08:00:00Z" - }, - { - "user": { - "login": "user49" - }, - "body": "Placeholder comment 49", - "created_at": "2024-05-17T08:10:00Z" - }, - { - "user": { - "login": "user50" - }, - "body": "Placeholder comment 50", - "created_at": "2024-05-17T08:20:00Z" - }, - { - "user": { - "login": "user51" - }, - "body": "Placeholder comment 51", - "created_at": "2024-05-17T08:30:00Z" - }, - { - "user": { - "login": "user52" - }, - "body": "Placeholder comment 52", - "created_at": "2024-05-17T08:40:00Z" - }, - { - "user": { - "login": "user53" - }, - "body": "Placeholder comment 53", - "created_at": "2024-05-17T08:50:00Z" - }, - { - "user": { - "login": "user54" - }, - "body": "Placeholder comment 54", - "created_at": "2024-05-17T09:00:00Z" - }, - { - "user": { - "login": "user55" - }, - "body": "Placeholder comment 55", - "created_at": "2024-05-17T09:10:00Z" - }, - { - "user": { - "login": "user56" - }, - "body": "Placeholder comment 56", - "created_at": "2024-05-17T09:20:00Z" - }, - { - "user": { - "login": "user57" - }, - "body": "Placeholder comment 57", - "created_at": "2024-05-17T09:30:00Z" - }, - { - "user": { - "login": "user58" - }, - "body": "Placeholder comment 58", - "created_at": "2024-05-17T09:40:00Z" - }, - { - "user": { - "login": "user59" - }, - "body": "Placeholder comment 59", - "created_at": "2024-05-17T09:50:00Z" - }, - { - "user": { - "login": "user60" - }, - "body": "Placeholder comment 60", - "created_at": "2024-05-17T10:00:00Z" - }, - { - "user": { - "login": "user61" - }, - "body": "Placeholder comment 61", - "created_at": "2024-05-17T10:10:00Z" - }, - { - "user": { - "login": "user62" - }, - "body": "Placeholder comment 62", - "created_at": "2024-05-17T10:20:00Z" - }, - { - "user": { - "login": "user63" - }, - "body": "Placeholder comment 63", - "created_at": "2024-05-17T10:30:00Z" - }, - { - "user": { - "login": "user64" - }, - "body": "Placeholder comment 64", - "created_at": "2024-05-17T10:40:00Z" - }, - { - "user": { - "login": "user65" - }, - "body": "Placeholder comment 65", - "created_at": "2024-05-17T10:50:00Z" - }, - { - "user": { - "login": "user66" - }, - "body": "Placeholder comment 66", - "created_at": "2024-05-17T11:00:00Z" - }, - { - "user": { - "login": "user67" - }, - "body": "Placeholder comment 67", - "created_at": "2024-05-17T11:10:00Z" - }, - { - "user": { - "login": "user68" - }, - "body": "Placeholder comment 68", - "created_at": "2024-05-17T11:20:00Z" - }, - { - "user": { - "login": "user69" - }, - "body": "Placeholder comment 69", - "created_at": "2024-05-17T11:30:00Z" - }, - { - "user": { - "login": "user70" - }, - "body": "Placeholder comment 70", - "created_at": "2024-05-17T11:40:00Z" - }, - { - "user": { - "login": "user71" - }, - "body": "Placeholder comment 71", - "created_at": "2024-05-17T11:50:00Z" - }, - { - "user": { - "login": "user72" - }, - "body": "Placeholder comment 72", - "created_at": "2024-05-17T12:00:00Z" - }, - { - "user": { - "login": "user73" - }, - "body": "Placeholder comment 73", - "created_at": "2024-05-17T12:10:00Z" - }, - { - "user": { - "login": "user74" - }, - "body": "Placeholder comment 74", - "created_at": "2024-05-17T12:20:00Z" - }, - { - "user": { - "login": "user75" - }, - "body": "Placeholder comment 75", - "created_at": "2024-05-17T12:30:00Z" - }, - { - "user": { - "login": "user76" - }, - "body": "Placeholder comment 76", - "created_at": "2024-05-17T12:40:00Z" - }, - { - "user": { - "login": "user77" - }, - "body": "Placeholder comment 77", - "created_at": "2024-05-17T12:50:00Z" - }, - { - "user": { - "login": "user78" - }, - "body": "Placeholder comment 78", - "created_at": "2024-05-17T13:00:00Z" - }, - { - "user": { - "login": "user79" - }, - "body": "Placeholder comment 79", - "created_at": "2024-05-17T13:10:00Z" - }, - { - "user": { - "login": "user80" - }, - "body": "Placeholder comment 80", - "created_at": "2024-05-17T13:20:00Z" - }, - { - "user": { - "login": "user81" - }, - "body": "Placeholder comment 81", - "created_at": "2024-05-17T13:30:00Z" - }, - { - "user": { - "login": "user82" - }, - "body": "Placeholder comment 82", - "created_at": "2024-05-17T13:40:00Z" - }, - { - "user": { - "login": "user83" - }, - "body": "Placeholder comment 83", - "created_at": "2024-05-17T13:50:00Z" - }, - { - "user": { - "login": "user84" - }, - "body": "Placeholder comment 84", - "created_at": "2024-05-17T14:00:00Z" - }, - { - "user": { - "login": "user85" - }, - "body": "Placeholder comment 85", - "created_at": "2024-05-17T14:10:00Z" - }, - { - "user": { - "login": "user86" - }, - "body": "Placeholder comment 86", - "created_at": "2024-05-17T14:20:00Z" - }, - { - "user": { - "login": "user87" - }, - "body": "Placeholder comment 87", - "created_at": "2024-05-17T14:30:00Z" - }, - { - "user": { - "login": "user88" - }, - "body": "Placeholder comment 88", - "created_at": "2024-05-17T14:40:00Z" - }, - { - "user": { - "login": "user89" - }, - "body": "Placeholder comment 89", - "created_at": "2024-05-17T14:50:00Z" - }, - { - "user": { - "login": "user90" - }, - "body": "Placeholder comment 90", - "created_at": "2024-05-17T15:00:00Z" - }, - { - "user": { - "login": "user91" - }, - "body": "Placeholder comment 91", - "created_at": "2024-05-17T15:10:00Z" - }, - { - "user": { - "login": "user92" - }, - "body": "Placeholder comment 92", - "created_at": "2024-05-17T15:20:00Z" - }, - { - "user": { - "login": "user93" - }, - "body": "Placeholder comment 93", - "created_at": "2024-05-17T15:30:00Z" - }, - { - "user": { - "login": "user94" - }, - "body": "Placeholder comment 94", - "created_at": "2024-05-17T15:40:00Z" - }, - { - "user": { - "login": "user95" - }, - "body": "Placeholder comment 95", - "created_at": "2024-05-17T15:50:00Z" - }, - { - "user": { - "login": "user96" - }, - "body": "Placeholder comment 96", - "created_at": "2024-05-17T16:00:00Z" - }, - { - "user": { - "login": "user97" - }, - "body": "Placeholder comment 97", - "created_at": "2024-05-17T16:10:00Z" - }, - { - "user": { - "login": "user98" - }, - "body": "Placeholder comment 98", - "created_at": "2024-05-17T16:20:00Z" - }, - { - "user": { - "login": "user99" - }, - "body": "Placeholder comment 99", - "created_at": "2024-05-17T16:30:00Z" - }, - { - "user": { - "login": "user100" - }, - "body": "Placeholder comment 100", - "created_at": "2024-05-17T16:40:00Z" - }, - { - "user": { - "login": "user101" - }, - "body": "Placeholder comment 101", - "created_at": "2024-05-17T16:50:00Z" - }, - { - "user": { - "login": "user102" - }, - "body": "Placeholder comment 102", - "created_at": "2024-05-17T17:00:00Z" - }, - { - "user": { - "login": "user103" - }, - "body": "Placeholder comment 103", - "created_at": "2024-05-17T17:10:00Z" - }, - { - "user": { - "login": "user104" - }, - "body": "Placeholder comment 104", - "created_at": "2024-05-17T17:20:00Z" - }, - { - "user": { - "login": "user105" - }, - "body": "Placeholder comment 105", - "created_at": "2024-05-17T17:30:00Z" - }, - { - "user": { - "login": "user106" - }, - "body": "Placeholder comment 106", - "created_at": "2024-05-17T17:40:00Z" - }, - { - "user": { - "login": "user107" - }, - "body": "Placeholder comment 107", - "created_at": "2024-05-17T17:50:00Z" - }, - { - "user": { - "login": "user108" - }, - "body": "Placeholder comment 108", - "created_at": "2024-05-17T18:00:00Z" - }, - { - "user": { - "login": "user109" - }, - "body": "Placeholder comment 109", - "created_at": "2024-05-17T18:10:00Z" - }, - { - "user": { - "login": "triage-bot" - }, - "body": "@codex plan-and-execute", - "created_at": "2024-05-18T08:00:00Z" - }, - { - "user": { - "login": "user111" - }, - "body": "Placeholder comment 111", - "created_at": "2024-05-17T18:30:00Z" - }, - { - "user": { - "login": "user112" - }, - "body": "Placeholder comment 112", - "created_at": "2024-05-17T18:40:00Z" - }, - { - "user": { - "login": "user113" - }, - "body": "Placeholder comment 113", - "created_at": "2024-05-17T18:50:00Z" - }, - { - "user": { - "login": "user114" - }, - "body": "Placeholder comment 114", - "created_at": "2024-05-17T19:00:00Z" - }, - { - "user": { - "login": "user115" - }, - "body": "Placeholder comment 115", - "created_at": "2024-05-17T19:10:00Z" - }, - { - "user": { - "login": "user116" - }, - "body": "Placeholder comment 116", - "created_at": "2024-05-17T19:20:00Z" - }, - { - "user": { - "login": "user117" - }, - "body": "Placeholder comment 117", - "created_at": "2024-05-17T19:30:00Z" - }, - { - "user": { - "login": "user118" - }, - "body": "Placeholder comment 118", - "created_at": "2024-05-17T19:40:00Z" - }, - { - "user": { - "login": "chatgpt-codex-connector" - }, - "body": "Daily update\n- [ ] Review signal output\n- [x] Stage summary", - "created_at": "2024-05-18T08:30:00Z" - } - ] - } - ] -} \ No newline at end of file diff --git a/tests/fixtures/keepalive/paused.json b/tests/fixtures/keepalive/paused.json deleted file mode 100644 index cc23b6b175..0000000000 --- a/tests/fixtures/keepalive/paused.json +++ /dev/null @@ -1,42 +0,0 @@ -{ - "repo": {"owner": "stranske", "repo": "Trend_Model_Project"}, - "now": "2024-05-18T12:00:00Z", - "env": { - "OPTIONS_JSON": "{}", - "DRY_RUN": "false" - }, - "pulls": [ - { - "number": 404, - "labels": ["agents:keepalive", "agent:codex", "agents:paused"], - "comments": [ - { - "user": {"login": "triage-bot"}, - "body": "@codex plan-and-execute", - "created_at": "2024-05-18T06:00:00Z" - }, - { - "user": {"login": "chatgpt-codex-connector"}, - "body": "Checklist\n- [ ] Refresh datasets\n- [x] Stage summary", - "created_at": "2024-05-18T07:00:00Z" - } - ] - }, - { - "number": 505, - "labels": ["agents:keepalive", "agent:codex"], - "comments": [ - { - "user": {"login": "triage-bot"}, - "body": "@codex plan-and-execute", - "created_at": "2024-05-18T08:00:00Z" - }, - { - "user": {"login": "chatgpt-codex-connector"}, - "body": "Daily update\n- [ ] Review signal output", - "created_at": "2024-05-18T09:00:00Z" - } - ] - } - ] -} diff --git a/tests/fixtures/keepalive/refresh.json b/tests/fixtures/keepalive/refresh.json deleted file mode 100644 index c9feb98f87..0000000000 --- a/tests/fixtures/keepalive/refresh.json +++ /dev/null @@ -1,33 +0,0 @@ -{ - "repo": {"owner": "stranske", "repo": "Trend_Model_Project"}, - "now": "2024-05-18T12:00:00Z", - "env": { - "OPTIONS_JSON": "{}", - "DRY_RUN": "false" - }, - "pulls": [ - { - "number": 909, - "labels": ["agents:keepalive", "agent:codex"], - "comments": [ - { - "user": {"login": "triage-bot"}, - "body": "@codex plan-and-execute", - "created_at": "2024-05-18T08:30:00Z" - }, - { - "user": {"login": "chatgpt-codex-connector"}, - "body": "Checklist\n- [ ] Verify metrics\n- [x] Stage summary", - "created_at": "2024-05-18T08:45:00Z" - }, - { - "id": 123456, - "user": {"login": "stranske-automation-bot"}, - "body": "\n\n\n@codex plan-and-execute\n\n**Keepalive Round 1**\n\nContinue incremental work toward acceptance criteria. Use the current checklist and update task statuses.\nPost an updated summary when this round completes.\n\nCodex, 1/2 checklist item remains unchecked (completed 1).", - "created_at": "2024-05-18T09:00:00Z", - "updated_at": "2024-05-18T09:00:00Z" - } - ] - } - ] -} diff --git a/tests/fixtures/keepalive/skip_opt_out.json b/tests/fixtures/keepalive/skip_opt_out.json deleted file mode 100644 index d70c4d9387..0000000000 --- a/tests/fixtures/keepalive/skip_opt_out.json +++ /dev/null @@ -1,20 +0,0 @@ -{ - "repo": {"owner": "stranske", "repo": "Trend_Model_Project"}, - "now": "2024-05-18T12:00:00Z", - "env": { - "OPTIONS_JSON": "{\"enable_keepalive\": false}" - }, - "pulls": [ - { - "number": 101, - "labels": ["agent:codex"], - "comments": [ - { - "user": {"login": "chatgpt-codex-connector"}, - "body": "- [ ] Follow up", - "created_at": "2024-05-18T10:00:00Z" - } - ] - } - ] -} diff --git a/tests/fixtures/keepalive/unauthorised_author.json b/tests/fixtures/keepalive/unauthorised_author.json deleted file mode 100644 index faf9510558..0000000000 --- a/tests/fixtures/keepalive/unauthorised_author.json +++ /dev/null @@ -1,29 +0,0 @@ -{ - "repo": {"owner": "stranske", "repo": "Trend_Model_Project"}, - "now": "2024-05-18T12:00:00Z", - "env": { - "OPTIONS_JSON": "{}", - "DRY_RUN": "false" - }, - "identity": { - "keepalive_author": "helper-bot" - }, - "pulls": [ - { - "number": 313, - "labels": ["agents:keepalive", "agent:codex"], - "comments": [ - { - "user": {"login": "triage-bot"}, - "body": "@codex plan-and-execute", - "created_at": "2024-05-18T08:00:00Z" - }, - { - "user": {"login": "chatgpt-codex-connector"}, - "body": "Daily update\n- [ ] Review signal output\n- [x] Stage summary", - "created_at": "2024-05-18T09:00:00Z" - } - ] - } - ] -} diff --git a/tests/fixtures/keepalive_post_work/create_pr.json b/tests/fixtures/keepalive_post_work/create_pr.json deleted file mode 100644 index eb851d42ea..0000000000 --- a/tests/fixtures/keepalive_post_work/create_pr.json +++ /dev/null @@ -1,28 +0,0 @@ -{ - "prNumber": 403, - "issueNumber": 403, - "headSequence": ["sha0", "sha0", "sha0", "sha0", "sha1", "sha1", "sha1"], - "labelsSequence": [["agents:keepalive", "agent:codex"]], - "env": { - "TRACE": "trace-create-pr", - "ROUND": "5", - "HEAD_BRANCH": "codex/issue-403", - "BASE_BRANCH": "main", - "PREVIOUS_HEAD": "sha0", - "AGENT_STATE": "done", - "TTL_SHORT_MS": "0", - "POLL_SHORT_MS": "0", - "TTL_LONG_MS": "50", - "POLL_LONG_MS": "0" - }, - "updateBranch": { - "error": "Update branch blocked" - }, - "workflowRuns": [ - { - "id": 987654, - "html_url": "https://example.test/run/987654", - "created_at": "2025-01-01T00:00:00Z" - } - ] -} diff --git a/tests/fixtures/keepalive_post_work/escalation.json b/tests/fixtures/keepalive_post_work/escalation.json deleted file mode 100644 index 263524e29e..0000000000 --- a/tests/fixtures/keepalive_post_work/escalation.json +++ /dev/null @@ -1,22 +0,0 @@ -{ - "prNumber": 404, - "issueNumber": 404, - "headSequence": ["sha0", "sha0", "sha0", "sha0", "sha0", "sha0"], - "labelsSequence": [["agents:keepalive", "agent:codex", "agents:debug"]], - "env": { - "TRACE": "trace-escalate", - "ROUND": "4", - "HEAD_BRANCH": "codex/issue-404", - "BASE_BRANCH": "main", - "PREVIOUS_HEAD": "sha0", - "AGENT_STATE": "done", - "TTL_SHORT_MS": "0", - "POLL_SHORT_MS": "0", - "TTL_LONG_MS": "0", - "POLL_LONG_MS": "0" - }, - "updateBranch": { - "error": "Update branch blocked" - }, - "workflowRuns": [] -} diff --git a/tests/fixtures/keepalive_post_work/fork_missing_head_repo.json b/tests/fixtures/keepalive_post_work/fork_missing_head_repo.json deleted file mode 100644 index 6c473b62f8..0000000000 --- a/tests/fixtures/keepalive_post_work/fork_missing_head_repo.json +++ /dev/null @@ -1,18 +0,0 @@ -{ - "prNumber": 411, - "issueNumber": 411, - "headSequence": ["sha0", "sha0"], - "env": { - "TRACE": "trace-fork-missing", - "ROUND": "3", - "HEAD_BRANCH": "contrib/feature-411", - "BASE_BRANCH": "main", - "PREVIOUS_HEAD": "sha0", - "AGENT_STATE": "done", - "TTL_SHORT_MS": "0", - "POLL_SHORT_MS": "0" - }, - "headRepo": null, - "headRepoFork": true, - "baseRepo": "stranske/Trend_Model_Project" -} diff --git a/tests/fixtures/keepalive_post_work/fork_sync.json b/tests/fixtures/keepalive_post_work/fork_sync.json deleted file mode 100644 index 9b22a5d391..0000000000 --- a/tests/fixtures/keepalive_post_work/fork_sync.json +++ /dev/null @@ -1,32 +0,0 @@ -{ - "prNumber": 410, - "issueNumber": 410, - "headSequence": ["sha0", "sha0", "sha0", "sha0", "sha1"], - "labelsSequence": [["agents:keepalive", "agent:codex"]], - "env": { - "TRACE": "trace-fork-sync", - "ROUND": "2", - "HEAD_BRANCH": "contrib/feature-410", - "BASE_BRANCH": "main", - "PREVIOUS_HEAD": "sha0", - "HEAD_REPO": "fork-owner/Trend_Model_Project", - "AGENT_STATE": "done", - "TTL_SHORT_MS": "0", - "POLL_SHORT_MS": "0", - "TTL_LONG_MS": "5", - "POLL_LONG_MS": "0" - }, - "headRepo": "fork-owner/Trend_Model_Project", - "headRepoFork": true, - "baseRepo": "stranske/Trend_Model_Project", - "updateBranch": { - "error": "Update branch blocked" - }, - "workflowRuns": [ - { - "id": 24680, - "html_url": "https://example.test/run/24680", - "created_at": "2030-01-01T00:00:00Z" - } - ] -} diff --git a/tests/fixtures/keepalive_post_work/head_change.json b/tests/fixtures/keepalive_post_work/head_change.json deleted file mode 100644 index cdb7d55274..0000000000 --- a/tests/fixtures/keepalive_post_work/head_change.json +++ /dev/null @@ -1,18 +0,0 @@ -{ - "prNumber": 401, - "issueNumber": 401, - "headSequence": ["sha0", "sha1"], - "labelsSequence": [["agents:keepalive", "agent:codex"]], - "env": { - "TRACE": "trace-head-change", - "ROUND": "2", - "HEAD_BRANCH": "codex/issue-401", - "BASE_BRANCH": "main", - "PREVIOUS_HEAD": "sha0", - "AGENT_STATE": "done", - "TTL_SHORT_MS": "0", - "POLL_SHORT_MS": "0", - "TTL_LONG_MS": "0", - "POLL_LONG_MS": "0" - } -} diff --git a/tests/fixtures/keepalive_post_work/update_branch.json b/tests/fixtures/keepalive_post_work/update_branch.json deleted file mode 100644 index a92e4bfdc3..0000000000 --- a/tests/fixtures/keepalive_post_work/update_branch.json +++ /dev/null @@ -1,21 +0,0 @@ -{ - "prNumber": 402, - "issueNumber": 402, - "headSequence": ["sha0", "sha0", "sha0", "sha1", "sha1"], - "labelsSequence": [["agents:keepalive", "agent:codex", "agents:sync-required"]], - "env": { - "TRACE": "trace-update-branch", - "ROUND": "3", - "HEAD_BRANCH": "codex/issue-402", - "BASE_BRANCH": "main", - "PREVIOUS_HEAD": "sha0", - "AGENT_STATE": "done", - "TTL_SHORT_MS": "0", - "POLL_SHORT_MS": "0", - "TTL_LONG_MS": "5", - "POLL_LONG_MS": "0" - }, - "updateBranch": { - "status": 202 - } -} diff --git a/tests/fixtures/orchestrator/options_passthrough.json b/tests/fixtures/orchestrator/options_passthrough.json deleted file mode 100644 index 8254cd9edb..0000000000 --- a/tests/fixtures/orchestrator/options_passthrough.json +++ /dev/null @@ -1,14 +0,0 @@ -{ - "env": { - "PARAMS_JSON": "{\"enable_keepalive\": true}", - "WORKFLOW_OPTIONS_JSON": "{\"keepalive_trace\":\"trace-from-options\",\"round\":\"7\",\"pr\":4001}", - "WORKFLOW_KEEPALIVE_ENABLED": "true" - }, - "context": { - "eventName": "workflow_dispatch", - "repo": { - "owner": "stranske", - "repo": "Trend_Model_Project" - } - } -} diff --git a/tests/workflows/__init__.py b/tests/workflows/__init__.py new file mode 100644 index 0000000000..c8746ee24a --- /dev/null +++ b/tests/workflows/__init__.py @@ -0,0 +1 @@ +"""Workflow and CI automation tests.""" diff --git a/tests/fixtures/agents_pr_meta/harness.js b/tests/workflows/fixtures/agents_pr_meta/harness.js similarity index 98% rename from tests/fixtures/agents_pr_meta/harness.js rename to tests/workflows/fixtures/agents_pr_meta/harness.js index 7dad22627c..94c9bbe66a 100644 --- a/tests/fixtures/agents_pr_meta/harness.js +++ b/tests/workflows/fixtures/agents_pr_meta/harness.js @@ -2,7 +2,7 @@ 'use strict'; const fs = require('fs'); -const { detectKeepalive } = require('../../../.github/scripts/agents_pr_meta_keepalive.js'); +const { detectKeepalive } = require('../../../../.github/scripts/agents_pr_meta_keepalive.js'); async function main() { const [, , scenarioPath] = process.argv; diff --git a/tests/fixtures/keepalive/guard_analysis.js b/tests/workflows/fixtures/keepalive/guard_analysis.js similarity index 89% rename from tests/fixtures/keepalive/guard_analysis.js rename to tests/workflows/fixtures/keepalive/guard_analysis.js index a590341670..60b9e61fb3 100644 --- a/tests/fixtures/keepalive/guard_analysis.js +++ b/tests/workflows/fixtures/keepalive/guard_analysis.js @@ -4,7 +4,7 @@ const fs = require('fs'); const path = require('path'); -const { analyseSkipComments } = require('../../../.github/scripts/keepalive_guard_utils.js'); +const { analyseSkipComments } = require('../../../../.github/scripts/keepalive_guard_utils.js'); function main() { const scenarioPath = process.argv[2]; diff --git a/tests/fixtures/keepalive/harness.js b/tests/workflows/fixtures/keepalive/harness.js similarity index 99% rename from tests/fixtures/keepalive/harness.js rename to tests/workflows/fixtures/keepalive/harness.js index 63066f5b30..f0f141f3f9 100644 --- a/tests/fixtures/keepalive/harness.js +++ b/tests/workflows/fixtures/keepalive/harness.js @@ -63,7 +63,7 @@ class SummaryRecorder { } function loadKeepaliveRunner() { - const targetPath = path.resolve(__dirname, '../../../scripts/keepalive-runner.js'); + const targetPath = path.resolve(__dirname, '../../../../scripts/keepalive-runner.js'); const code = fs.readFileSync(targetPath, 'utf8'); const sandbox = { module: { exports: {} }, diff --git a/tests/fixtures/keepalive_post_work/harness.js b/tests/workflows/fixtures/keepalive_post_work/harness.js similarity index 99% rename from tests/fixtures/keepalive_post_work/harness.js rename to tests/workflows/fixtures/keepalive_post_work/harness.js index ca0e0d8137..0cf6c021dd 100644 --- a/tests/fixtures/keepalive_post_work/harness.js +++ b/tests/workflows/fixtures/keepalive_post_work/harness.js @@ -3,7 +3,7 @@ const fs = require('fs'); const path = require('path'); -const { runKeepalivePostWork } = require('../../../.github/scripts/keepalive_post_work.js'); +const { runKeepalivePostWork } = require('../../../../.github/scripts/keepalive_post_work.js'); function createSummary() { const entries = []; diff --git a/tests/fixtures/orchestrator/resolve_harness.js b/tests/workflows/fixtures/orchestrator/resolve_harness.js similarity index 94% rename from tests/fixtures/orchestrator/resolve_harness.js rename to tests/workflows/fixtures/orchestrator/resolve_harness.js index 8e405f2bc7..b545671aae 100755 --- a/tests/fixtures/orchestrator/resolve_harness.js +++ b/tests/workflows/fixtures/orchestrator/resolve_harness.js @@ -4,7 +4,7 @@ const fs = require('fs'); const path = require('path'); -const { resolveOrchestratorParams } = require('../../../.github/scripts/agents_orchestrator_resolve.js'); +const { resolveOrchestratorParams } = require('../../../../.github/scripts/agents_orchestrator_resolve.js'); async function main() { const scenarioPath = process.argv[2]; diff --git a/tests/github_scripts/__init__.py b/tests/workflows/github_scripts/__init__.py similarity index 100% rename from tests/github_scripts/__init__.py rename to tests/workflows/github_scripts/__init__.py diff --git a/tests/github_scripts/test_decode_raw_input.py b/tests/workflows/github_scripts/test_decode_raw_input.py similarity index 99% rename from tests/github_scripts/test_decode_raw_input.py rename to tests/workflows/github_scripts/test_decode_raw_input.py index cb172b2faa..dda7115d55 100644 --- a/tests/github_scripts/test_decode_raw_input.py +++ b/tests/workflows/github_scripts/test_decode_raw_input.py @@ -9,7 +9,7 @@ from pathlib import Path from types import SimpleNamespace -REPO_ROOT = Path(__file__).resolve().parents[2] +REPO_ROOT = Path(__file__).resolve().parents[3] SCRIPT_DIR = REPO_ROOT / ".github" / "scripts" if str(SCRIPT_DIR) not in sys.path: sys.path.insert(0, str(SCRIPT_DIR)) diff --git a/tests/github_scripts/test_fallback_split.py b/tests/workflows/github_scripts/test_fallback_split.py similarity index 98% rename from tests/github_scripts/test_fallback_split.py rename to tests/workflows/github_scripts/test_fallback_split.py index 38e0e8e731..afc33fe1ad 100644 --- a/tests/github_scripts/test_fallback_split.py +++ b/tests/workflows/github_scripts/test_fallback_split.py @@ -9,7 +9,7 @@ from pathlib import Path from types import SimpleNamespace -REPO_ROOT = Path(__file__).resolve().parents[2] +REPO_ROOT = Path(__file__).resolve().parents[3] SCRIPT_DIR = REPO_ROOT / ".github" / "scripts" if str(SCRIPT_DIR) not in sys.path: sys.path.insert(0, str(SCRIPT_DIR)) diff --git a/tests/github_scripts/test_gate_summary.py b/tests/workflows/github_scripts/test_gate_summary.py similarity index 99% rename from tests/github_scripts/test_gate_summary.py rename to tests/workflows/github_scripts/test_gate_summary.py index 9adf11f4db..366b8bba3c 100644 --- a/tests/github_scripts/test_gate_summary.py +++ b/tests/workflows/github_scripts/test_gate_summary.py @@ -7,7 +7,7 @@ import pytest # Add script directory to path before importing gate_summary -SCRIPT_DIR = Path(__file__).resolve().parents[2] / ".github" / "scripts" +SCRIPT_DIR = Path(__file__).resolve().parents[3] / ".github" / "scripts" if str(SCRIPT_DIR) not in sys.path: sys.path.insert(0, str(SCRIPT_DIR)) diff --git a/tests/github_scripts/test_health_summarize.py b/tests/workflows/github_scripts/test_health_summarize.py similarity index 99% rename from tests/github_scripts/test_health_summarize.py rename to tests/workflows/github_scripts/test_health_summarize.py index a39023994a..8f7672aa29 100644 --- a/tests/github_scripts/test_health_summarize.py +++ b/tests/workflows/github_scripts/test_health_summarize.py @@ -7,7 +7,7 @@ import pytest -SCRIPT_DIR = Path(__file__).resolve().parents[2] / ".github" / "scripts" +SCRIPT_DIR = Path(__file__).resolve().parents[3] / ".github" / "scripts" if str(SCRIPT_DIR) not in sys.path: sys.path.insert(0, str(SCRIPT_DIR)) diff --git a/tests/github_scripts/test_parse_chatgpt_topics.py b/tests/workflows/github_scripts/test_parse_chatgpt_topics.py similarity index 99% rename from tests/github_scripts/test_parse_chatgpt_topics.py rename to tests/workflows/github_scripts/test_parse_chatgpt_topics.py index cd83fcc37c..80b8e1390c 100644 --- a/tests/github_scripts/test_parse_chatgpt_topics.py +++ b/tests/workflows/github_scripts/test_parse_chatgpt_topics.py @@ -11,7 +11,7 @@ import pytest -REPO_ROOT = Path(__file__).resolve().parents[2] +REPO_ROOT = Path(__file__).resolve().parents[3] SCRIPT_DIR = REPO_ROOT / ".github" / "scripts" SCRIPT_PATH = SCRIPT_DIR / "parse_chatgpt_topics.py" diff --git a/tests/github_scripts/test_restore_branch_snapshots.py b/tests/workflows/github_scripts/test_restore_branch_snapshots.py similarity index 99% rename from tests/github_scripts/test_restore_branch_snapshots.py rename to tests/workflows/github_scripts/test_restore_branch_snapshots.py index 5648a9fd39..1d38f15d8e 100644 --- a/tests/github_scripts/test_restore_branch_snapshots.py +++ b/tests/workflows/github_scripts/test_restore_branch_snapshots.py @@ -9,7 +9,7 @@ import pytest # Add script directory to path before importing restore_branch_snapshots -SCRIPT_DIR = Path(__file__).resolve().parents[2] / ".github" / "scripts" +SCRIPT_DIR = Path(__file__).resolve().parents[3] / ".github" / "scripts" if str(SCRIPT_DIR) not in sys.path: sys.path.insert(0, str(SCRIPT_DIR)) diff --git a/tests/test_agents_guard.py b/tests/workflows/test_agents_guard.py similarity index 99% rename from tests/test_agents_guard.py rename to tests/workflows/test_agents_guard.py index 642c5ab52f..0c94ce18e2 100644 --- a/tests/test_agents_guard.py +++ b/tests/workflows/test_agents_guard.py @@ -6,7 +6,7 @@ import pytest -REPO_ROOT = Path(__file__).resolve().parents[1] +REPO_ROOT = Path(__file__).resolve().parents[2] # Check if Node.js is available NODE_AVAILABLE = shutil.which("node") is not None diff --git a/tests/test_agents_orchestrator_resolve.py b/tests/workflows/test_agents_orchestrator_resolve.py similarity index 100% rename from tests/test_agents_orchestrator_resolve.py rename to tests/workflows/test_agents_orchestrator_resolve.py diff --git a/tests/test_agents_pr_meta_keepalive.py b/tests/workflows/test_agents_pr_meta_keepalive.py similarity index 100% rename from tests/test_agents_pr_meta_keepalive.py rename to tests/workflows/test_agents_pr_meta_keepalive.py diff --git a/tests/test_autofix_full_pipeline.py b/tests/workflows/test_autofix_full_pipeline.py similarity index 100% rename from tests/test_autofix_full_pipeline.py rename to tests/workflows/test_autofix_full_pipeline.py diff --git a/tests/test_autofix_pipeline.py b/tests/workflows/test_autofix_pipeline.py similarity index 100% rename from tests/test_autofix_pipeline.py rename to tests/workflows/test_autofix_pipeline.py diff --git a/tests/test_autofix_pipeline_diverse.py b/tests/workflows/test_autofix_pipeline_diverse.py similarity index 100% rename from tests/test_autofix_pipeline_diverse.py rename to tests/workflows/test_autofix_pipeline_diverse.py diff --git a/tests/test_autofix_pipeline_live_docs.py b/tests/workflows/test_autofix_pipeline_live_docs.py similarity index 98% rename from tests/test_autofix_pipeline_live_docs.py rename to tests/workflows/test_autofix_pipeline_live_docs.py index 3e23aa51bc..2e2cd10912 100644 --- a/tests/test_autofix_pipeline_live_docs.py +++ b/tests/workflows/test_autofix_pipeline_live_docs.py @@ -49,7 +49,7 @@ def test_autofix_pipeline_repairs_live_documents( src_dir.mkdir() tests_dir.mkdir() - real_root = Path(__file__).resolve().parents[1] + real_root = Path(__file__).resolve().parents[2] trend_analysis_src = real_root / "src" / "trend_analysis" shutil.copytree(trend_analysis_src, src_dir / "trend_analysis") @@ -58,7 +58,9 @@ def test_autofix_pipeline_repairs_live_documents( if yaml_stub_src.exists(): shutil.copytree(yaml_stub_src, src_dir / "yaml") - expectation_module_src = real_root / "tests" / "test_autofix_repo_regressions.py" + expectation_module_src = ( + real_root / "tests" / "workflows" / "test_autofix_repo_regressions.py" + ) expectation_module_target = tests_dir / "test_autofix_repo_regressions.py" shutil.copy2(expectation_module_src, expectation_module_target) diff --git a/tests/test_autofix_pipeline_tools.py b/tests/workflows/test_autofix_pipeline_tools.py similarity index 100% rename from tests/test_autofix_pipeline_tools.py rename to tests/workflows/test_autofix_pipeline_tools.py diff --git a/tests/test_autofix_pr_comment.py b/tests/workflows/test_autofix_pr_comment.py similarity index 100% rename from tests/test_autofix_pr_comment.py rename to tests/workflows/test_autofix_pr_comment.py diff --git a/tests/test_autofix_probe_module.py b/tests/workflows/test_autofix_probe_module.py similarity index 100% rename from tests/test_autofix_probe_module.py rename to tests/workflows/test_autofix_probe_module.py diff --git a/tests/test_autofix_repo_regressions.py b/tests/workflows/test_autofix_repo_regressions.py similarity index 100% rename from tests/test_autofix_repo_regressions.py rename to tests/workflows/test_autofix_repo_regressions.py diff --git a/tests/test_autofix_samples.py b/tests/workflows/test_autofix_samples.py similarity index 100% rename from tests/test_autofix_samples.py rename to tests/workflows/test_autofix_samples.py diff --git a/tests/test_autofix_trigger_scenario2.py b/tests/workflows/test_autofix_trigger_scenario2.py similarity index 100% rename from tests/test_autofix_trigger_scenario2.py rename to tests/workflows/test_autofix_trigger_scenario2.py diff --git a/tests/test_chatgpt_topics_parser.py b/tests/workflows/test_chatgpt_topics_parser.py similarity index 99% rename from tests/test_chatgpt_topics_parser.py rename to tests/workflows/test_chatgpt_topics_parser.py index 7c000deac9..eaf43e24d9 100644 --- a/tests/test_chatgpt_topics_parser.py +++ b/tests/workflows/test_chatgpt_topics_parser.py @@ -10,7 +10,7 @@ import pytest -REPO_ROOT = pathlib.Path(__file__).resolve().parents[1] +REPO_ROOT = pathlib.Path(__file__).resolve().parents[2] SCRIPT = REPO_ROOT / ".github/scripts/parse_chatgpt_topics.py" TOPICS_PATH = pathlib.Path("topics.json") diff --git a/tests/test_ci_cosmetic_repair.py b/tests/workflows/test_ci_cosmetic_repair.py similarity index 100% rename from tests/test_ci_cosmetic_repair.py rename to tests/workflows/test_ci_cosmetic_repair.py diff --git a/tests/test_ci_coverage_delta.py b/tests/workflows/test_ci_coverage_delta.py similarity index 100% rename from tests/test_ci_coverage_delta.py rename to tests/workflows/test_ci_coverage_delta.py diff --git a/tests/test_ci_history.py b/tests/workflows/test_ci_history.py similarity index 100% rename from tests/test_ci_history.py rename to tests/workflows/test_ci_history.py diff --git a/tests/test_ci_metrics.py b/tests/workflows/test_ci_metrics.py similarity index 100% rename from tests/test_ci_metrics.py rename to tests/workflows/test_ci_metrics.py diff --git a/tests/test_ci_probe_faults.py b/tests/workflows/test_ci_probe_faults.py similarity index 100% rename from tests/test_ci_probe_faults.py rename to tests/workflows/test_ci_probe_faults.py diff --git a/tests/test_codex_belt_pipeline.py b/tests/workflows/test_codex_belt_pipeline.py similarity index 100% rename from tests/test_codex_belt_pipeline.py rename to tests/workflows/test_codex_belt_pipeline.py diff --git a/tests/test_disable_legacy_workflows.py b/tests/workflows/test_disable_legacy_workflows.py similarity index 98% rename from tests/test_disable_legacy_workflows.py rename to tests/workflows/test_disable_legacy_workflows.py index 3237802689..0931f231a6 100644 --- a/tests/test_disable_legacy_workflows.py +++ b/tests/workflows/test_disable_legacy_workflows.py @@ -4,7 +4,7 @@ import pytest -from tests.test_workflow_naming import EXPECTED_NAMES +from tests.workflows.test_workflow_naming import EXPECTED_NAMES from tools.disable_legacy_workflows import ( CANONICAL_WORKFLOW_FILES, CANONICAL_WORKFLOW_NAMES, diff --git a/tests/test_issue_bridge_triggers.py b/tests/workflows/test_issue_bridge_triggers.py similarity index 99% rename from tests/test_issue_bridge_triggers.py rename to tests/workflows/test_issue_bridge_triggers.py index 904a3dd224..430c52afee 100644 --- a/tests/test_issue_bridge_triggers.py +++ b/tests/workflows/test_issue_bridge_triggers.py @@ -21,7 +21,7 @@ class TestIssueBridgeTriggers(unittest.TestCase): @classmethod def setUpClass(cls) -> None: - cls.project_root = Path(__file__).resolve().parents[1] + cls.project_root = Path(__file__).resolve().parents[2] cls.workflows_dir = cls.project_root / ".github" / "workflows" cls.intake_workflow = cls.workflows_dir / "agents-63-issue-intake.yml" diff --git a/tests/test_keepalive_guard_utils.py b/tests/workflows/test_keepalive_guard_utils.py similarity index 95% rename from tests/test_keepalive_guard_utils.py rename to tests/workflows/test_keepalive_guard_utils.py index 1a5da35997..5c9c2de89e 100644 --- a/tests/test_keepalive_guard_utils.py +++ b/tests/workflows/test_keepalive_guard_utils.py @@ -6,7 +6,9 @@ import pytest -GUARD_ANALYSIS = Path("tests/fixtures/keepalive/guard_analysis.js") +GUARD_ANALYSIS = ( + Path(__file__).resolve().parent / "fixtures" / "keepalive" / "guard_analysis.js" +) def _require_node() -> None: diff --git a/tests/test_keepalive_post_work.py b/tests/workflows/test_keepalive_post_work.py similarity index 100% rename from tests/test_keepalive_post_work.py rename to tests/workflows/test_keepalive_post_work.py diff --git a/tests/test_keepalive_workflow.py b/tests/workflows/test_keepalive_workflow.py similarity index 100% rename from tests/test_keepalive_workflow.py rename to tests/workflows/test_keepalive_workflow.py diff --git a/tests/test_reusable_ci_workflow.py b/tests/workflows/test_reusable_ci_workflow.py similarity index 100% rename from tests/test_reusable_ci_workflow.py rename to tests/workflows/test_reusable_ci_workflow.py diff --git a/tests/test_workflow_agents_consolidation.py b/tests/workflows/test_workflow_agents_consolidation.py similarity index 100% rename from tests/test_workflow_agents_consolidation.py rename to tests/workflows/test_workflow_agents_consolidation.py diff --git a/tests/test_workflow_archival_issue2823.py b/tests/workflows/test_workflow_archival_issue2823.py similarity index 100% rename from tests/test_workflow_archival_issue2823.py rename to tests/workflows/test_workflow_archival_issue2823.py diff --git a/tests/test_workflow_autofix_guard.py b/tests/workflows/test_workflow_autofix_guard.py similarity index 100% rename from tests/test_workflow_autofix_guard.py rename to tests/workflows/test_workflow_autofix_guard.py diff --git a/tests/test_workflow_multi_failure.py b/tests/workflows/test_workflow_multi_failure.py similarity index 100% rename from tests/test_workflow_multi_failure.py rename to tests/workflows/test_workflow_multi_failure.py diff --git a/tests/test_workflow_multi_failure_demo.py b/tests/workflows/test_workflow_multi_failure_demo.py similarity index 100% rename from tests/test_workflow_multi_failure_demo.py rename to tests/workflows/test_workflow_multi_failure_demo.py diff --git a/tests/test_workflow_naming.py b/tests/workflows/test_workflow_naming.py similarity index 100% rename from tests/test_workflow_naming.py rename to tests/workflows/test_workflow_naming.py diff --git a/tests/test_workflow_selftest_consolidation.py b/tests/workflows/test_workflow_selftest_consolidation.py similarity index 100% rename from tests/test_workflow_selftest_consolidation.py rename to tests/workflows/test_workflow_selftest_consolidation.py From a3c0a805fda9ca9862ab8909a06af23026d7de7d Mon Sep 17 00:00:00 2001 From: stranske Date: Sun, 30 Nov 2025 05:46:17 +0000 Subject: [PATCH 27/40] test: fix 3 failing tests with outdated expectations 1. test_run_page_imports_successfully: Check for 'main' function instead of removed 'run_analysis_with_progress' function 2. test_ensure_glob_matches_raises_when_no_files: Use unique directory pattern to avoid matching files in project's data/ folder 3. test_list_agent_bootstraps_includes_current_issue_file: Check for codex-3572.md instead of archived codex-3878.md All 3707 tests now pass. --- tests/test_streamlit_smoke_ci.py | 2 +- tests/test_trend_analysis_config_model.py | 7 ++++++- tests/tools/test_agents_index.py | 5 +++-- 3 files changed, 10 insertions(+), 4 deletions(-) diff --git a/tests/test_streamlit_smoke_ci.py b/tests/test_streamlit_smoke_ci.py index a3b485ed69..2f3fa91aa0 100644 --- a/tests/test_streamlit_smoke_ci.py +++ b/tests/test_streamlit_smoke_ci.py @@ -348,7 +348,7 @@ def test_run_page_imports_successfully(): # Check that key functions exist assert hasattr(run_page, "format_error_message") - assert hasattr(run_page, "run_analysis_with_progress") + assert hasattr(run_page, "main") print("✅ Run page imports successfully") diff --git a/tests/test_trend_analysis_config_model.py b/tests/test_trend_analysis_config_model.py index 2c840baca2..7e304a160d 100644 --- a/tests/test_trend_analysis_config_model.py +++ b/tests/test_trend_analysis_config_model.py @@ -89,8 +89,13 @@ def test_ensure_glob_matches_requires_csv_extension(tmp_path: Path) -> None: def test_ensure_glob_matches_raises_when_no_files(tmp_path: Path) -> None: + # Use a unique pattern that won't match any files anywhere + nonexistent_dir = tmp_path / "unique_nonexistent_dir_xyz123" + nonexistent_dir.mkdir() with pytest.raises(ValueError, match="did not match any CSV files"): - config_model._ensure_glob_matches("data/*.csv", base_dir=tmp_path) + config_model._ensure_glob_matches( + "unique_nonexistent_dir_xyz123/*.csv", base_dir=tmp_path + ) def _basic_data_settings_dict(tmp_path: Path) -> dict[str, object]: diff --git a/tests/tools/test_agents_index.py b/tests/tools/test_agents_index.py index 68126d8307..8998b39812 100644 --- a/tests/tools/test_agents_index.py +++ b/tests/tools/test_agents_index.py @@ -18,5 +18,6 @@ def test_list_agent_bootstraps_includes_current_issue_file(): bootstraps = list_agent_bootstraps(agents_dir) - assert any(entry.issue == 3878 for entry in bootstraps) - assert any(entry.path.name == "codex-3878.md" for entry in bootstraps) + # Check for any active codex file (3878 was archived, 3572 is current) + assert any(entry.issue == 3572 for entry in bootstraps) + assert any(entry.path.name == "codex-3572.md" for entry in bootstraps) From a11f20a38f352da0a276db9b8767ebd7cca4e6e5 Mon Sep 17 00:00:00 2001 From: stranske Date: Sun, 30 Nov 2025 06:00:18 +0000 Subject: [PATCH 28/40] test: fix pandas FutureWarning by using 'ME' instead of 'M' frequency - Update date_range() calls to use freq='ME' (month end) instead of deprecated freq='M' in 27 test files - Fix test_mypy_failure to not return a value (removes pytest warning) - Increase script timeout in test_script_error_handling.py for CI stability Warnings reduced from 151 to 54 (remaining are numpy RuntimeWarnings in production code and expected module import behavior). --- tests/app/test_data_page.py | 2 +- tests/app/test_results_page.py | 2 +- tests/backtesting/test_harness.py | 2 +- tests/test_analysis_results_module.py | 2 +- tests/test_io_validators_extra.py | 8 ++-- tests/test_metrics_rolling_cache_disabled.py | 2 +- tests/test_multi_period_engine_additional.py | 2 +- ...t_multi_period_engine_branch_completion.py | 2 +- tests/test_optional_notebook_deps.py | 2 +- tests/test_pipeline_branch_coverage.py | 6 +-- tests/test_pipeline_helpers.py | 4 +- tests/test_pipeline_helpers_additional.py | 48 +++++++++---------- tests/test_regimes.py | 4 +- tests/test_regimes_additional.py | 24 +++++----- tests/test_risk_additional.py | 4 +- tests/test_run_analysis_additional.py | 12 ++--- tests/test_script_error_handling.py | 4 +- tests/test_signals_engine.py | 2 +- tests/test_signals_validation.py | 2 +- tests/test_time_utils.py | 2 +- tests/test_trend_reporting_unified_helpers.py | 2 +- tests/test_trend_signals_validation.py | 2 +- tests/test_universe_membership.py | 4 +- tests/test_util_frequency_additional.py | 2 +- tests/test_util_frequency_targeted.py | 2 +- tests/test_validators_branch_coverage.py | 6 +-- .../test_backtesting_harness.py | 10 ++-- .../unit/util/test_frequency_comprehensive.py | 2 +- .../test_workflow_multi_failure_demo.py | 7 +-- 29 files changed, 87 insertions(+), 86 deletions(-) diff --git a/tests/app/test_data_page.py b/tests/app/test_data_page.py index b35ce2c489..fa4d11f184 100644 --- a/tests/app/test_data_page.py +++ b/tests/app/test_data_page.py @@ -174,7 +174,7 @@ def test_data_page_autoloads_sample(monkeypatch: pytest.MonkeyPatch, data_page) df = pd.DataFrame( {"FundA": [0.01, 0.02, -0.01], "SPX Index": [0.03, -0.02, 0.01]}, - index=pd.date_range("2024-01-31", periods=3, freq="M"), + index=pd.date_range("2024-01-31", periods=3, freq="ME"), ) meta = {"validation": {"issues": [], "warnings": []}, "frequency_label": "monthly"} diff --git a/tests/app/test_results_page.py b/tests/app/test_results_page.py index 8d77fce8e8..797e4758e3 100644 --- a/tests/app/test_results_page.py +++ b/tests/app/test_results_page.py @@ -131,7 +131,7 @@ def _sample_returns() -> pd.DataFrame: "FundA": [0.01, -0.005, 0.012], "FundB": [0.008, 0.007, -0.002], } - index = pd.date_range("2023-01-31", periods=3, freq="M") + index = pd.date_range("2023-01-31", periods=3, freq="ME") return pd.DataFrame(data, index=index) diff --git a/tests/backtesting/test_harness.py b/tests/backtesting/test_harness.py index ef33102340..e7008756f5 100644 --- a/tests/backtesting/test_harness.py +++ b/tests/backtesting/test_harness.py @@ -624,7 +624,7 @@ def test_infer_periods_per_year_handles_various_spacings( ) -> None: daily = pd.date_range("2020-01-01", periods=10, freq="B") weekly = pd.date_range("2020-01-01", periods=10, freq="W") - monthly = pd.date_range("2020-01-01", periods=10, freq="M") + monthly = pd.date_range("2020-01-01", periods=10, freq="ME") quarterly = pd.date_range("2020-01-01", periods=5, freq="Q") sparse = pd.DatetimeIndex([pd.Timestamp("2020-01-01")]) descending = pd.DatetimeIndex( diff --git a/tests/test_analysis_results_module.py b/tests/test_analysis_results_module.py index a769f9313e..0ecad7ab2f 100644 --- a/tests/test_analysis_results_module.py +++ b/tests/test_analysis_results_module.py @@ -53,7 +53,7 @@ def test_build_metadata_includes_core_fields(monkeypatch) -> None: def test_results_from_payload_coerces_series() -> None: portfolio = pd.Series( - [0.01, 0.02], index=pd.date_range("2020-01-31", periods=2, freq="M") + [0.01, 0.02], index=pd.date_range("2020-01-31", periods=2, freq="ME") ) payload = { "portfolio_equal_weight_combined": portfolio, diff --git a/tests/test_io_validators_extra.py b/tests/test_io_validators_extra.py index 04363739b4..cab507fe90 100644 --- a/tests/test_io_validators_extra.py +++ b/tests/test_io_validators_extra.py @@ -288,7 +288,7 @@ def test_load_and_validate_upload_returns_metadata( metadata = _metadata_with_warnings() frame = pd.DataFrame( { - "Date": pd.date_range("2024-01-31", periods=metadata.rows, freq="M"), + "Date": pd.date_range("2024-01-31", periods=metadata.rows, freq="ME"), "FundA": 0.01, } ) @@ -382,7 +382,7 @@ def test_validation_result_report_omits_optional_metadata() -> None: def test_detect_frequency_handles_irregular(monkeypatch: pytest.MonkeyPatch) -> None: - index = pd.date_range("2024-01-01", periods=3, freq="M") + index = pd.date_range("2024-01-01", periods=3, freq="ME") df = pd.DataFrame(index=index) def raise_error(_index: pd.Index) -> dict[str, str]: @@ -393,7 +393,7 @@ def raise_error(_index: pd.Index) -> dict[str, str]: def test_detect_frequency_returns_code(monkeypatch: pytest.MonkeyPatch) -> None: - index = pd.date_range("2024-01-01", periods=3, freq="M") + index = pd.date_range("2024-01-01", periods=3, freq="ME") df = pd.DataFrame(index=index) monkeypatch.setattr( "trend_analysis.io.validators.classify_frequency", @@ -408,7 +408,7 @@ def test_detect_frequency_handles_non_datetime_index() -> None: def test_detect_frequency_returns_label(monkeypatch: pytest.MonkeyPatch) -> None: - index = pd.date_range("2024-01-01", periods=3, freq="M") + index = pd.date_range("2024-01-01", periods=3, freq="ME") df = pd.DataFrame(index=index) def classify(idx: pd.Index) -> dict[str, Any]: diff --git a/tests/test_metrics_rolling_cache_disabled.py b/tests/test_metrics_rolling_cache_disabled.py index e8bd434322..f8f6e7957c 100644 --- a/tests/test_metrics_rolling_cache_disabled.py +++ b/tests/test_metrics_rolling_cache_disabled.py @@ -10,7 +10,7 @@ def test_rolling_information_ratio_without_cache(): original = cache.is_enabled() cache.set_enabled(False) try: - index = pd.date_range("2024-01-01", periods=5, freq="M") + index = pd.date_range("2024-01-01", periods=5, freq="ME") returns = pd.Series([0.01, 0.02, -0.01, 0.015, 0.005], index=index) result = rolling_information_ratio(returns, benchmark=0.0, window=3) diff --git a/tests/test_multi_period_engine_additional.py b/tests/test_multi_period_engine_additional.py index 5c3fa468f6..b97b870316 100644 --- a/tests/test_multi_period_engine_additional.py +++ b/tests/test_multi_period_engine_additional.py @@ -1129,7 +1129,7 @@ def fake_run_analysis( df = pd.DataFrame( { - "Date": pd.date_range("2020-01-31", periods=6, freq="M"), + "Date": pd.date_range("2020-01-31", periods=6, freq="ME"), "Alpha Fund": np.linspace(0.01, 0.02, num=6), "Beta Fund": np.linspace(0.02, 0.03, num=6), "Gamma Fund": np.linspace(0.015, 0.025, num=6), diff --git a/tests/test_multi_period_engine_branch_completion.py b/tests/test_multi_period_engine_branch_completion.py index b68a794335..e6574f1e50 100644 --- a/tests/test_multi_period_engine_branch_completion.py +++ b/tests/test_multi_period_engine_branch_completion.py @@ -178,7 +178,7 @@ def test_run_missing_policy_rejects_empty_cleaned_frame() -> None: """If the missing-data policy yields no assets the engine must error.""" cfg = _base_config() - dates = pd.date_range("2020-01-31", periods=3, freq="M") + dates = pd.date_range("2020-01-31", periods=3, freq="ME") df = pd.DataFrame({"Date": dates, "Alpha": [float("nan")] * 3}) with pytest.raises(ValueError, match="Missing-data policy removed all assets"): diff --git a/tests/test_optional_notebook_deps.py b/tests/test_optional_notebook_deps.py index 010c19b11f..971e9be80a 100644 --- a/tests/test_optional_notebook_deps.py +++ b/tests/test_optional_notebook_deps.py @@ -51,7 +51,7 @@ def _reload(monkeypatch: pytest.MonkeyPatch, module_name: str): def _sample_df() -> pd.DataFrame: - dates = pd.date_range("2024-01-31", periods=6, freq="M") + dates = pd.date_range("2024-01-31", periods=6, freq="ME") return pd.DataFrame( { "Date": dates, diff --git a/tests/test_pipeline_branch_coverage.py b/tests/test_pipeline_branch_coverage.py index ba4232b51e..68869682c9 100644 --- a/tests/test_pipeline_branch_coverage.py +++ b/tests/test_pipeline_branch_coverage.py @@ -15,7 +15,7 @@ def _sample_frame() -> pd.DataFrame: - dates = pd.date_range("2024-01-31", periods=6, freq="M") + dates = pd.date_range("2024-01-31", periods=6, freq="ME") data = { "Date": dates, "Fund_A": [0.01, 0.02, 0.015, 0.017, np.nan, 0.011], @@ -30,7 +30,7 @@ def _sample_frame() -> pd.DataFrame: def _stub_diagnostics(columns: Iterator[str]) -> RiskDiagnostics: cols = list(columns) - index = pd.date_range("2024-01-31", periods=6, freq="M") + index = pd.date_range("2024-01-31", periods=6, freq="ME") asset_vol = pd.DataFrame(0.1, index=index, columns=cols) portfolio = pd.Series(0.1, index=index, name="portfolio") turnover = pd.Series([], dtype=float, name="turnover") @@ -53,7 +53,7 @@ def test_preprocessing_summary_monthly_branch() -> None: def test_resolve_sample_split_returns_existing_keys() -> None: - df = pd.DataFrame({"Date": pd.date_range("2024-01-31", periods=2, freq="M")}) + df = pd.DataFrame({"Date": pd.date_range("2024-01-31", periods=2, freq="ME")}) split_cfg = { "in_start": "2024-01", "in_end": "2024-02", diff --git a/tests/test_pipeline_helpers.py b/tests/test_pipeline_helpers.py index d867c46080..24908001e4 100644 --- a/tests/test_pipeline_helpers.py +++ b/tests/test_pipeline_helpers.py @@ -75,7 +75,7 @@ def test_derive_split_from_periods_handles_ratio_and_date() -> None: def test_resolve_sample_split_validates_dataframe() -> None: df = pd.DataFrame( { - "Date": pd.date_range("2020-01-31", periods=4, freq="M"), + "Date": pd.date_range("2020-01-31", periods=4, freq="ME"), "Fund": [0.1, 0.2, 0.3, 0.4], } ) @@ -90,7 +90,7 @@ def test_resolve_sample_split_validates_dataframe() -> None: def test_prepare_input_data_applies_missing_policy() -> None: df = pd.DataFrame( { - "Date": pd.date_range("2020-01-31", periods=3, freq="M"), + "Date": pd.date_range("2020-01-31", periods=3, freq="ME"), "FundA": [0.1, None, 0.2], "FundB": [0.05, 0.06, 0.07], } diff --git a/tests/test_pipeline_helpers_additional.py b/tests/test_pipeline_helpers_additional.py index b49a5d6431..498afdc5a4 100644 --- a/tests/test_pipeline_helpers_additional.py +++ b/tests/test_pipeline_helpers_additional.py @@ -62,7 +62,7 @@ def get(self, key: str, default: Any = None): def fixture_monthly_frame() -> pd.DataFrame: return pd.DataFrame( { - "Date": pd.date_range("2020-01-31", periods=4, freq="M"), + "Date": pd.date_range("2020-01-31", periods=4, freq="ME"), "A": [0.01, 0.02, 0.03, 0.04], "B": [0.0, 0.01, -0.02, 0.03], } @@ -450,7 +450,7 @@ def test_prepare_input_data_requires_date_column(monthly_frame: pd.DataFrame) -> def test_prepare_input_data_handles_empty_results( monkeypatch: pytest.MonkeyPatch, ) -> None: - df = pd.DataFrame({"Date": pd.date_range("2020-01-31", periods=2, freq="M")}) + df = pd.DataFrame({"Date": pd.date_range("2020-01-31", periods=2, freq="ME")}) summary = FrequencySummary( code="M", label="Monthly", resampled=False, target="M", target_label="Monthly" ) @@ -548,7 +548,7 @@ def prepare_no_values(*args, **kwargs): def test_run_analysis_rank_selection_with_fallbacks( monkeypatch: pytest.MonkeyPatch, ) -> None: - dates = pd.date_range("2020-01-31", periods=4, freq="M") + dates = pd.date_range("2020-01-31", periods=4, freq="ME") prepared = pd.DataFrame( { "Date": dates, @@ -658,7 +658,7 @@ def fake_regime_payload(**kwargs): def test_run_analysis_zero_weight_custom(monkeypatch: pytest.MonkeyPatch) -> None: - dates = pd.date_range("2020-01-31", periods=3, freq="M") + dates = pd.date_range("2020-01-31", periods=3, freq="ME") prepared = pd.DataFrame( { "Date": dates, @@ -748,7 +748,7 @@ def test_compute_signal_error_paths(monthly_frame: pd.DataFrame) -> None: def test_run_uses_nan_policy_fallback(monkeypatch: pytest.MonkeyPatch) -> None: df = pd.DataFrame( { - "Date": pd.date_range("2020-01-31", periods=4, freq="M"), + "Date": pd.date_range("2020-01-31", periods=4, freq="ME"), "FundA": [0.01, 0.02, 0.0, 0.03], "FundB": [0.0, -0.01, 0.02, 0.01], } @@ -811,7 +811,7 @@ def fake_run_analysis(*args, **kwargs): def test_run_full_passes_through_results(monkeypatch: pytest.MonkeyPatch) -> None: df = pd.DataFrame( { - "Date": pd.date_range("2020-01-31", periods=4, freq="M"), + "Date": pd.date_range("2020-01-31", periods=4, freq="ME"), "FundA": [0.01, 0.02, 0.0, 0.03], "FundB": [0.0, -0.01, 0.02, 0.01], } @@ -870,7 +870,7 @@ def fake_run_analysis(*args, **kwargs): def test_single_period_run_basic_metrics() -> None: df = pd.DataFrame( { - "Date": pd.date_range("2020-01-31", periods=4, freq="M"), + "Date": pd.date_range("2020-01-31", periods=4, freq="ME"), "FundA": [0.01, 0.02, -0.01, 0.03], "FundB": [0.0, 0.01, 0.02, -0.01], } @@ -901,7 +901,7 @@ def test_single_period_run_coerces_string_dates() -> None: def test_single_period_run_rejects_empty_metrics() -> None: df = pd.DataFrame( { - "Date": pd.date_range("2020-01-31", periods=2, freq="M"), + "Date": pd.date_range("2020-01-31", periods=2, freq="ME"), "FundA": [0.01, 0.02], } ) @@ -916,7 +916,7 @@ class EmptyConfig(SimpleNamespace): def test_single_period_run_rejects_empty_window() -> None: df = pd.DataFrame( { - "Date": pd.date_range("2020-01-31", periods=2, freq="M"), + "Date": pd.date_range("2020-01-31", periods=2, freq="ME"), "FundA": [0.01, 0.02], } ) @@ -928,7 +928,7 @@ def test_single_period_run_rejects_empty_window() -> None: def test_single_period_run_rejects_all_nan_window() -> None: df = pd.DataFrame( { - "Date": pd.date_range("2020-01-31", periods=3, freq="M"), + "Date": pd.date_range("2020-01-31", periods=3, freq="ME"), "FundA": [np.nan, np.nan, np.nan], "FundB": [np.nan, np.nan, np.nan], } @@ -946,7 +946,7 @@ def freq(self): # type: ignore[override] data = pd.DataFrame( {"returns": [0.1, -0.2, 0.05, 0.03]}, - index=RaisingIndex(pd.date_range("2020-01-31", periods=4, freq="M")), + index=RaisingIndex(pd.date_range("2020-01-31", periods=4, freq="ME")), ) class DummyCache: @@ -972,7 +972,7 @@ def get_or_compute(self, *args): def test_compute_signal_without_cache(monkeypatch: pytest.MonkeyPatch) -> None: frame = pd.DataFrame( {"returns": [0.1, -0.2, 0.05]}, - index=pd.date_range("2020-01-31", periods=3, freq="M"), + index=pd.date_range("2020-01-31", periods=3, freq="ME"), ) class DummyCache: @@ -989,7 +989,7 @@ def is_enabled(self) -> bool: def test_position_from_signal_behaviour() -> None: signal = pd.Series( [np.nan, 0.2, 0.0, -0.5, np.nan], - index=pd.date_range("2020-01-31", periods=5, freq="M"), + index=pd.date_range("2020-01-31", periods=5, freq="ME"), name="signal", ) positions = pipeline.position_from_signal( @@ -1013,7 +1013,7 @@ def test_module_getattr_stats_alias() -> None: def test_run_analysis_random_selection(monkeypatch: pytest.MonkeyPatch) -> None: - dates = pd.date_range("2020-01-31", periods=5, freq="M") + dates = pd.date_range("2020-01-31", periods=5, freq="ME") prepared = pd.DataFrame( { "Date": dates, @@ -1189,7 +1189,7 @@ def columns(self): # type: ignore[override] base = ShrinkingColumnsFrame( { - "Date": pd.date_range("2020-01-31", periods=3, freq="M"), + "Date": pd.date_range("2020-01-31", periods=3, freq="ME"), "FundA": [0.0, 0.1, -0.1], } ) @@ -1226,7 +1226,7 @@ def columns(self): # type: ignore[override] def test_run_analysis_weight_engine_success(monkeypatch: pytest.MonkeyPatch) -> None: - dates = pd.date_range("2020-01-31", periods=4, freq="M") + dates = pd.date_range("2020-01-31", periods=4, freq="ME") prepared = pd.DataFrame( { "Date": dates, @@ -1345,7 +1345,7 @@ def set_index(self, keys, drop: bool = True, inplace: bool = False, verify_integ return result.iloc[0:0].copy() return SignalFrame(result) - dates = pd.date_range("2020-01-31", periods=2, freq="M") + dates = pd.date_range("2020-01-31", periods=2, freq="ME") frame = SignalFrame({"Date": dates, "FundA": [0.01, 0.02], "RF": [0.0, 0.0]}) freq_summary = FrequencySummary("M", "Monthly", False, "M", "Monthly") missing_result = MissingPolicyResult( @@ -1426,7 +1426,7 @@ def fake_weights(base, returns, **kwargs): def test_run_analysis_warmup_zeroes_initial_rows( monkeypatch: pytest.MonkeyPatch, ) -> None: - dates = pd.date_range("2020-01-31", periods=5, freq="M") + dates = pd.date_range("2020-01-31", periods=5, freq="ME") prepared = pd.DataFrame( { "Date": dates, @@ -1511,7 +1511,7 @@ def fake_weights(base, returns, **kwargs): def test_run_analysis_adds_valid_indices_and_skips_missing_benchmarks( monkeypatch: pytest.MonkeyPatch, ) -> None: - dates = pd.date_range("2020-01-31", periods=4, freq="M") + dates = pd.date_range("2020-01-31", periods=4, freq="ME") prepared = pd.DataFrame( { "Date": dates, @@ -1596,7 +1596,7 @@ def fake_weights(base, returns, **kwargs): def test_run_analysis_handles_benchmark_overrides( monkeypatch: pytest.MonkeyPatch, ) -> None: - dates = pd.date_range("2020-01-31", periods=3, freq="M") + dates = pd.date_range("2020-01-31", periods=3, freq="ME") prepared = pd.DataFrame( { "Date": dates, @@ -1683,7 +1683,7 @@ def test_run_missing_policy_and_limit_fallbacks( ) -> None: df = pd.DataFrame( { - "Date": pd.date_range("2020-01-31", periods=4, freq="M"), + "Date": pd.date_range("2020-01-31", periods=4, freq="ME"), "FundA": [0.01, 0.02, 0.0, 0.03], "FundB": [0.0, -0.01, 0.02, 0.01], } @@ -1737,7 +1737,7 @@ def fake_run_analysis(*args, **kwargs): def test_run_respects_explicit_missing_policy(monkeypatch: pytest.MonkeyPatch) -> None: df = pd.DataFrame( { - "Date": pd.date_range("2020-01-31", periods=3, freq="M"), + "Date": pd.date_range("2020-01-31", periods=3, freq="ME"), "FundA": [0.01, 0.02, 0.03], } ) @@ -1795,7 +1795,7 @@ def test_run_full_requires_csv_path() -> None: def test_run_full_uses_nan_policy_defaults(monkeypatch: pytest.MonkeyPatch) -> None: df = pd.DataFrame( { - "Date": pd.date_range("2020-01-31", periods=4, freq="M"), + "Date": pd.date_range("2020-01-31", periods=4, freq="ME"), "FundA": [0.01, 0.02, 0.0, 0.03], "FundB": [0.0, -0.01, 0.02, 0.01], } @@ -1845,7 +1845,7 @@ def fake_run_analysis(*args, **kwargs): def test_run_full_respects_explicit_policy(monkeypatch: pytest.MonkeyPatch) -> None: df = pd.DataFrame( { - "Date": pd.date_range("2020-01-31", periods=3, freq="M"), + "Date": pd.date_range("2020-01-31", periods=3, freq="ME"), "FundA": [0.01, 0.02, 0.03], } ) diff --git a/tests/test_regimes.py b/tests/test_regimes.py index efacc9c4fc..d047ab1e8a 100644 --- a/tests/test_regimes.py +++ b/tests/test_regimes.py @@ -285,7 +285,7 @@ def get_or_compute(self, *args): def test_compute_regimes_disabled_returns_empty() -> None: series = pd.Series( - [0.01, 0.02], index=pd.date_range("2023-01-31", periods=2, freq="M") + [0.01, 0.02], index=pd.date_range("2023-01-31", periods=2, freq="ME") ) settings = RegimeSettings(enabled=False) result = compute_regimes(series, settings, freq="M") @@ -294,7 +294,7 @@ def test_compute_regimes_disabled_returns_empty() -> None: def test_rolling_volatility_signal_validates_window() -> None: series = pd.Series( - [0.01, 0.02], index=pd.date_range("2023-01-31", periods=2, freq="M") + [0.01, 0.02], index=pd.date_range("2023-01-31", periods=2, freq="ME") ) with pytest.raises(ValueError, match="window must be positive"): _rolling_volatility_signal( diff --git a/tests/test_regimes_additional.py b/tests/test_regimes_additional.py index 02dce4f288..68f995b691 100644 --- a/tests/test_regimes_additional.py +++ b/tests/test_regimes_additional.py @@ -131,7 +131,7 @@ def test_default_periods_per_year_mappings() -> None: def test_compute_regime_series_uses_cache(monkeypatch: pytest.MonkeyPatch) -> None: - dates = pd.date_range("2024-01-31", periods=6, freq="M") + dates = pd.date_range("2024-01-31", periods=6, freq="ME") proxy = pd.Series([0.01, 0.02, -0.01, 0.015, 0.03, 0.025], index=dates) settings = RegimeSettings( enabled=True, @@ -175,7 +175,7 @@ def get_or_compute( def test_compute_regime_series_without_cache_returns_labels() -> None: - dates = pd.date_range("2024-01-31", periods=6, freq="M") + dates = pd.date_range("2024-01-31", periods=6, freq="ME") proxy = pd.Series([0.01, 0.02, -0.01, 0.03, 0.025, -0.02], index=dates) settings = RegimeSettings( enabled=True, @@ -197,7 +197,7 @@ def test_compute_regime_series_handles_empty_input() -> None: empty_series, settings, freq="M", periods_per_year=12 ).empty nan_series = pd.Series( - [np.nan, np.nan], index=pd.date_range("2024-01-31", periods=2, freq="M") + [np.nan, np.nan], index=pd.date_range("2024-01-31", periods=2, freq="ME") ) assert _compute_regime_series( nan_series, settings, freq="M", periods_per_year=12 @@ -207,7 +207,7 @@ def test_compute_regime_series_handles_empty_input() -> None: def test_compute_regimes_disabled_returns_empty() -> None: settings = RegimeSettings(enabled=False) proxy = pd.Series( - [0.01, 0.02], index=pd.date_range("2024-01-31", periods=2, freq="M") + [0.01, 0.02], index=pd.date_range("2024-01-31", periods=2, freq="ME") ) result = compute_regimes(proxy, settings, freq="M", periods_per_year=12) assert result.empty @@ -258,7 +258,7 @@ def test_aggregate_performance_by_regime_edge_cases() -> None: table, notes = aggregate_performance_by_regime( returns_map={ "Fund": pd.Series( - [0.01, 0.02], index=pd.date_range("2024-01-31", periods=2, freq="M") + [0.01, 0.02], index=pd.date_range("2024-01-31", periods=2, freq="ME") ) }, risk_free=0.0, @@ -271,7 +271,7 @@ def test_aggregate_performance_by_regime_edge_cases() -> None: regimes = pd.Series( ["Risk-On", "Risk-Off"], - index=pd.date_range("2024-01-31", periods=2, freq="M"), + index=pd.date_range("2024-01-31", periods=2, freq="ME"), dtype="string", ) series = pd.Series([0.01, -0.02], index=regimes.index) @@ -290,7 +290,7 @@ def test_aggregate_performance_by_regime_edge_cases() -> None: def test_build_regime_payload_handling(monkeypatch: pytest.MonkeyPatch) -> None: - dates = pd.date_range("2024-01-31", periods=3, freq="M") + dates = pd.date_range("2024-01-31", periods=3, freq="ME") data = pd.DataFrame( {"Date": dates, "Proxy": [0.01, 0.02, -0.01], "Fund": [0.02, 0.01, 0.03]} ) @@ -378,7 +378,7 @@ def test_build_regime_payload_handling(monkeypatch: pytest.MonkeyPatch) -> None: def test_build_regime_payload_handles_missing_labels( monkeypatch: pytest.MonkeyPatch, ) -> None: - dates = pd.date_range("2024-01-31", periods=2, freq="M") + dates = pd.date_range("2024-01-31", periods=2, freq="ME") data = pd.DataFrame({"Date": dates, "Proxy": [0.01, 0.02], "Fund": [0.02, 0.01]}) returns_map = {"Fund": data.set_index("Date")["Fund"]} @@ -412,7 +412,7 @@ def test_build_regime_payload_handles_missing_labels( def test_build_regime_payload_generates_summary( monkeypatch: pytest.MonkeyPatch, ) -> None: - dates = pd.date_range("2024-01-31", periods=6, freq="M") + dates = pd.date_range("2024-01-31", periods=6, freq="ME") data = pd.DataFrame( { "Date": dates, @@ -459,7 +459,7 @@ def test_build_regime_payload_generates_summary( def test_compute_regime_series_volatility_tag_includes_periods( monkeypatch: pytest.MonkeyPatch, ) -> None: - dates = pd.date_range("2024-01-31", periods=10, freq="M") + dates = pd.date_range("2024-01-31", periods=10, freq="ME") proxy = pd.Series(np.linspace(0.01, 0.05, len(dates)), index=dates) settings = RegimeSettings( enabled=True, @@ -507,7 +507,7 @@ def get_or_compute( def test_compute_regime_series_volatility_tag_skips_when_no_periods( monkeypatch: pytest.MonkeyPatch, ) -> None: - dates = pd.date_range("2024-01-31", periods=8, freq="M") + dates = pd.date_range("2024-01-31", periods=8, freq="ME") proxy = pd.Series(np.linspace(0.01, 0.04, len(dates)), index=dates) settings = RegimeSettings( enabled=True, @@ -559,7 +559,7 @@ def get_or_compute( def test_build_regime_payload_uses_notes_when_no_user_columns( monkeypatch: pytest.MonkeyPatch, ) -> None: - dates = pd.date_range("2024-01-31", periods=6, freq="M") + dates = pd.date_range("2024-01-31", periods=6, freq="ME") data = pd.DataFrame({"Date": dates, "Proxy": np.linspace(100, 120, len(dates))}) regimes = pd.Series(["Risk-On"] * len(dates), index=dates, dtype="string") diff --git a/tests/test_risk_additional.py b/tests/test_risk_additional.py index 26a3133222..eabf0a987f 100644 --- a/tests/test_risk_additional.py +++ b/tests/test_risk_additional.py @@ -15,7 +15,7 @@ def _restore_optimizer(monkeypatch): def test_realised_volatility_supports_simple_and_ewma(): returns = pd.DataFrame( {"asset": [0.01, 0.03, 0.02, 0.05, 0.04]}, - index=pd.date_range("2024-01-01", periods=5, freq="M"), + index=pd.date_range("2024-01-01", periods=5, freq="ME"), ) simple = risk.realised_volatility(returns, risk.RiskWindow(length=2)) assert simple.index.equals(returns.index) @@ -50,7 +50,7 @@ def test_compute_constrained_weights_applies_controls(monkeypatch): "A": [0.01, 0.02, 0.015, 0.018, 0.022], "B": [0.0, 0.0, 0.0, 0.0, 0.0], }, - index=pd.date_range("2024-01-31", periods=5, freq="M"), + index=pd.date_range("2024-01-31", periods=5, freq="ME"), ) base_weights = {"A": 0.6, "B": 0.4} payload_capture: dict[str, object] = {} diff --git a/tests/test_run_analysis_additional.py b/tests/test_run_analysis_additional.py index 85a0560f3f..c6b63f2edd 100644 --- a/tests/test_run_analysis_additional.py +++ b/tests/test_run_analysis_additional.py @@ -13,14 +13,14 @@ class DummyResult: def __init__(self) -> None: - dates = pd.date_range("2024-01-31", periods=2, freq="M") + dates = pd.date_range("2024-01-31", periods=2, freq="ME") self.metrics = pd.DataFrame({"metric": [1.0, 2.0]}, index=dates) self.details = {"summary": "ok"} class DetailedResult: def __init__(self) -> None: - index = pd.date_range("2024-01-31", periods=3, freq="M") + index = pd.date_range("2024-01-31", periods=3, freq="ME") self.metrics = pd.DataFrame({"metric": [1.0, 2.0, 3.0]}, index=index) self.details = { "performance_by_regime": pd.DataFrame( @@ -74,7 +74,7 @@ def fake_load_csv( } return pd.DataFrame( { - "Date": pd.date_range("2024-01-31", periods=2, freq="M"), + "Date": pd.date_range("2024-01-31", periods=2, freq="ME"), "Fund": [0.01, 0.02], } ) @@ -120,7 +120,7 @@ def fake_load_csv( captured["nan_limit"] = nan_limit return pd.DataFrame( { - "Date": pd.date_range("2024-01-31", periods=2, freq="M"), + "Date": pd.date_range("2024-01-31", periods=2, freq="ME"), "Fund": [0.01, 0.02], } ) @@ -170,7 +170,7 @@ def fake_load_csv( } return pd.DataFrame( { - "Date": pd.date_range("2024-01-31", periods=3, freq="M"), + "Date": pd.date_range("2024-01-31", periods=3, freq="ME"), "Fund": [0.01, 0.02, 0.03], } ) @@ -249,7 +249,7 @@ def test_main_detailed_no_results( def fake_load_csv(*_args: object, **_kwargs: object) -> pd.DataFrame: return pd.DataFrame( { - "Date": pd.date_range("2024-01-31", periods=2, freq="M"), + "Date": pd.date_range("2024-01-31", periods=2, freq="ME"), "Fund": [0.01, 0.02], } ) diff --git a/tests/test_script_error_handling.py b/tests/test_script_error_handling.py index b529ab619c..e9db008b5a 100644 --- a/tests/test_script_error_handling.py +++ b/tests/test_script_error_handling.py @@ -107,7 +107,7 @@ def test_scripts_run_without_failure(self): cwd=self.project_root, capture_output=True, text=True, - timeout=30, + timeout=120, # Increased timeout for CI with many changed files ) self.assertIsNotNone(result.returncode, "dev_check.sh should complete") except subprocess.TimeoutExpired: @@ -120,7 +120,7 @@ def test_scripts_run_without_failure(self): cwd=self.project_root, capture_output=True, text=True, - timeout=30, + timeout=120, # Increased timeout for CI with many changed files ) self.assertIsNotNone(result.returncode, "validate_fast.sh should complete") except subprocess.TimeoutExpired: diff --git a/tests/test_signals_engine.py b/tests/test_signals_engine.py index 327317d6c2..cbf84a8f82 100644 --- a/tests/test_signals_engine.py +++ b/tests/test_signals_engine.py @@ -9,7 +9,7 @@ @pytest.fixture def sample_returns() -> pd.DataFrame: - index = pd.date_range("2020-01-31", periods=8, freq="M") + index = pd.date_range("2020-01-31", periods=8, freq="ME") data = { "AssetA": np.linspace(-0.02, 0.03, len(index)), "AssetB": np.cos(np.linspace(0.0, np.pi, len(index))) * 0.02, diff --git a/tests/test_signals_validation.py b/tests/test_signals_validation.py index 0ee80da0b2..3c2fc888a9 100644 --- a/tests/test_signals_validation.py +++ b/tests/test_signals_validation.py @@ -40,7 +40,7 @@ def test_compute_trend_signals_vol_adjust_without_target() -> None: "FundA": [0.01, 0.02, 0.03, 0.01, 0.0, -0.01, -0.02], "FundB": [0.0, 0.01, 0.015, -0.005, -0.01, 0.0, 0.005], }, - index=pd.date_range("2024-01-31", periods=7, freq="M"), + index=pd.date_range("2024-01-31", periods=7, freq="ME"), ) spec = TrendSpec(window=3, vol_adjust=True, vol_target=None) diff --git a/tests/test_time_utils.py b/tests/test_time_utils.py index c2dff45d2c..a38f5e6615 100644 --- a/tests/test_time_utils.py +++ b/tests/test_time_utils.py @@ -30,7 +30,7 @@ def test_align_calendar_removes_weekends_and_holidays(): def test_align_calendar_preserves_monthly_frequency(): - dates = pd.date_range("2024-01-31", periods=4, freq="M") + dates = pd.date_range("2024-01-31", periods=4, freq="ME") df = pd.DataFrame( { "Date": dates, diff --git a/tests/test_trend_reporting_unified_helpers.py b/tests/test_trend_reporting_unified_helpers.py index 93a56b2acc..0093b3b381 100644 --- a/tests/test_trend_reporting_unified_helpers.py +++ b/tests/test_trend_reporting_unified_helpers.py @@ -80,7 +80,7 @@ def _build_result_with_details() -> tuple[SimpleNamespace, SimpleNamespace]: index = pd.period_range("2021-01", periods=6, freq="M") portfolio = pd.Series([0.01, -0.005, 0.012, 0.008, -0.004, 0.015], index=index) turnover = pd.Series( - [0.2, 0.18, 0.22], index=pd.date_range("2021-01-31", periods=3, freq="M") + [0.2, 0.18, 0.22], index=pd.date_range("2021-01-31", periods=3, freq="ME") ) final_weights = pd.Series({"FundA": 0.6, "FundB": 0.4}) regime_table = pd.DataFrame( diff --git a/tests/test_trend_signals_validation.py b/tests/test_trend_signals_validation.py index de4f954420..7dd93daf44 100644 --- a/tests/test_trend_signals_validation.py +++ b/tests/test_trend_signals_validation.py @@ -32,7 +32,7 @@ def test_compute_trend_signals_rejects_empty_returns() -> None: def test_vol_adjust_without_target_inverts_rolling_std() -> None: """When ``vol_target`` is omitted the inverse rolling std should be used.""" - index = pd.date_range("2024-01-31", periods=8, freq="M") + index = pd.date_range("2024-01-31", periods=8, freq="ME") base_data = { "fund_a": np.linspace(-0.01, 0.03, len(index)), "fund_b": np.linspace(0.015, -0.02, len(index)), diff --git a/tests/test_universe_membership.py b/tests/test_universe_membership.py index c54288b61c..bfdda0996f 100644 --- a/tests/test_universe_membership.py +++ b/tests/test_universe_membership.py @@ -142,7 +142,7 @@ def test_gate_universe_matches_date_symbol_pairs() -> None: def test_build_membership_mask_marks_entries_and_exits() -> None: - dates = pd.date_range("2020-01-31", periods=4, freq="M") + dates = pd.date_range("2020-01-31", periods=4, freq="ME") membership = pd.DataFrame( { "fund": ["Alpha", "Beta", "Gamma"], @@ -159,7 +159,7 @@ def test_build_membership_mask_marks_entries_and_exits() -> None: def test_build_membership_mask_accepts_membership_table() -> None: - dates = pd.date_range("2020-01-31", periods=2, freq="M") + dates = pd.date_range("2020-01-31", periods=2, freq="ME") membership = { "AAA": ( MembershipWindow(pd.Timestamp("2020-01-31"), pd.Timestamp("2020-02-29")), diff --git a/tests/test_util_frequency_additional.py b/tests/test_util_frequency_additional.py index ee45f47532..4b2c442ece 100644 --- a/tests/test_util_frequency_additional.py +++ b/tests/test_util_frequency_additional.py @@ -15,7 +15,7 @@ True, ), ( - pd.date_range("2024-01-01", periods=12, freq="M"), + pd.date_range("2024-01-01", periods=12, freq="ME"), "M", False, ), diff --git a/tests/test_util_frequency_targeted.py b/tests/test_util_frequency_targeted.py index 80885cdb0e..7f1a5e1522 100644 --- a/tests/test_util_frequency_targeted.py +++ b/tests/test_util_frequency_targeted.py @@ -99,7 +99,7 @@ def test_detect_frequency_single_entry_defaults_to_monthly() -> None: def test_detect_frequency_falls_back_when_infer_freq_fails( monkeypatch: pytest.MonkeyPatch, ) -> None: - idx = pd.date_range("2024-01-31", periods=6, freq="M") + idx = pd.date_range("2024-01-31", periods=6, freq="ME") monkeypatch.setattr( pd, "infer_freq", lambda _: (_ for _ in ()).throw(ValueError("boom")) diff --git a/tests/test_validators_branch_coverage.py b/tests/test_validators_branch_coverage.py index f6bc6d743a..e56408b53b 100644 --- a/tests/test_validators_branch_coverage.py +++ b/tests/test_validators_branch_coverage.py @@ -91,7 +91,7 @@ def raise_irregular(_index: pd.Index) -> dict[str, object]: monkeypatch.setattr(validators, "classify_frequency", raise_irregular) series = pd.Series( - [1.0, 2.0], index=pd.date_range("2024-01-31", periods=2, freq="M") + [1.0, 2.0], index=pd.date_range("2024-01-31", periods=2, freq="ME") ) label = validators.detect_frequency(series.to_frame()) assert "irregular" in label.lower() @@ -105,7 +105,7 @@ def raise_generic(_index: pd.Index) -> dict[str, object]: monkeypatch.setattr(validators, "classify_frequency", raise_generic) series = pd.Series( - [1.0, 2.0], index=pd.date_range("2024-01-31", periods=2, freq="M") + [1.0, 2.0], index=pd.date_range("2024-01-31", periods=2, freq="ME") ) assert validators.detect_frequency(series.to_frame()) == "unknown" @@ -118,7 +118,7 @@ def return_info(_index: pd.Index) -> dict[str, object]: monkeypatch.setattr(validators, "classify_frequency", return_info) series = pd.Series( - [1.0, 2.0], index=pd.date_range("2024-01-31", periods=2, freq="M") + [1.0, 2.0], index=pd.date_range("2024-01-31", periods=2, freq="ME") ) assert validators.detect_frequency(series.to_frame()) == "W" diff --git a/tests/trend_analysis/test_backtesting_harness.py b/tests/trend_analysis/test_backtesting_harness.py index 24ca29a86e..6628e78f07 100644 --- a/tests/trend_analysis/test_backtesting_harness.py +++ b/tests/trend_analysis/test_backtesting_harness.py @@ -297,7 +297,7 @@ def equal_weight(frame: pd.DataFrame) -> pd.Series: def test_run_backtest_enforces_membership_mask_on_weights() -> None: - dates = pd.date_range("2020-01-31", periods=6, freq="M") + dates = pd.date_range("2020-01-31", periods=6, freq="ME") returns = pd.DataFrame( { "Date": dates, @@ -335,7 +335,7 @@ def equal_weight(frame: pd.DataFrame) -> pd.Series: def test_run_backtest_membership_missing_price_data_raises() -> None: - dates = pd.date_range("2020-01-31", periods=4, freq="M") + dates = pd.date_range("2020-01-31", periods=4, freq="ME") returns = pd.DataFrame( { "Date": dates, @@ -366,7 +366,7 @@ def test_run_backtest_membership_missing_price_data_raises() -> None: def test_run_backtest_membership_policy_skip_masks_missing_rows() -> None: - dates = pd.date_range("2020-01-31", periods=4, freq="M") + dates = pd.date_range("2020-01-31", periods=4, freq="ME") returns = pd.DataFrame( { "Date": dates, @@ -400,7 +400,7 @@ def test_run_backtest_membership_policy_skip_masks_missing_rows() -> None: def test_run_backtest_membership_missing_column_skip_continues() -> None: - dates = pd.date_range("2020-01-31", periods=3, freq="M") + dates = pd.date_range("2020-01-31", periods=3, freq="ME") returns = pd.DataFrame( { "Date": dates, @@ -428,7 +428,7 @@ def test_run_backtest_membership_missing_column_skip_continues() -> None: def test_run_backtest_membership_missing_column_raises() -> None: - dates = pd.date_range("2020-01-31", periods=2, freq="M") + dates = pd.date_range("2020-01-31", periods=2, freq="ME") returns = pd.DataFrame({"Date": dates, "Alpha": [0.01, 0.02]}) membership = pd.DataFrame( diff --git a/tests/unit/util/test_frequency_comprehensive.py b/tests/unit/util/test_frequency_comprehensive.py index bc26fe1c22..1c6593a6da 100644 --- a/tests/unit/util/test_frequency_comprehensive.py +++ b/tests/unit/util/test_frequency_comprehensive.py @@ -225,7 +225,7 @@ def test_intervals_in_days_matches_expected_delta() -> None: [list, tuple, pd.Series], ) def test_detect_frequency_accepts_various_iterables(iterable_type: type) -> None: - values = iterable_type(pd.date_range("2024-01-01", periods=5, freq="M")) + values = iterable_type(pd.date_range("2024-01-01", periods=5, freq="ME")) summary = freq.detect_frequency(values) diff --git a/tests/workflows/test_workflow_multi_failure_demo.py b/tests/workflows/test_workflow_multi_failure_demo.py index 149453ba41..e0a2d60342 100644 --- a/tests/workflows/test_workflow_multi_failure_demo.py +++ b/tests/workflows/test_workflow_multi_failure_demo.py @@ -8,9 +8,10 @@ def test_lint_failure(): assert x == 1 and y == 2 -def test_mypy_failure() -> int: - # Intentional mypy error: wrong return type - return "not an int" +def test_mypy_failure() -> None: + # Intentional mypy error: assigning wrong type to variable + x: int = "not an int" # type: ignore[assignment] + assert x == "not an int" @pytest.mark.cosmetic From 809ea0f75caa13ec59b4b14ca1f7e0ac565b3da4 Mon Sep 17 00:00:00 2001 From: stranske Date: Sun, 30 Nov 2025 06:07:05 +0000 Subject: [PATCH 29/40] chore: review tools/ directory and remove stale workflow catalog tools/ directory review (2025-11-30): - Contains 14 active CI infrastructure utilities - Used by GitHub Actions workflows, tests, and git hooks - Documented each file's purpose and usage in docs/INDEX.md Removed: - update_workflow_catalog.py - Unused generator for stale catalog (workflow_catalog.json was gitignored and not tracked) Also noted: - trend_model.egg-info/ is properly gitignored build artifact --- docs/INDEX.md | 29 +++++++ tools/update_workflow_catalog.py | 130 ------------------------------- 2 files changed, 29 insertions(+), 130 deletions(-) delete mode 100644 tools/update_workflow_catalog.py diff --git a/docs/INDEX.md b/docs/INDEX.md index 709d0b78b2..8df6ea6a62 100644 --- a/docs/INDEX.md +++ b/docs/INDEX.md @@ -142,6 +142,35 @@ Use this index to find the current contributor guides and to understand which ov - Updated path references in harness JS files and test imports - Core fixture `score_frame_2025-06-30.csv` remains in `tests/fixtures/` +**`tools/` folder (reviewed 2025-11-30):** +- CI infrastructure utilities imported by workflows and tests +- **14 active files** used by GitHub Actions and test suite + +| File | Purpose | Used By | +| --- | --- | --- | +| `post_ci_summary.py` | Build consolidated CI summary | `pr-00-gate.yml`, `maint-46-post-ci.yml` | +| `coverage_guard.py` | Maintain rolling coverage baseline | `maint-coverage-guard.yml` | +| `coverage_trend.py` | Compute coverage trend for CI | `reusable-10-ci-python.yml` | +| `enforce_gate_branch_protection.py` | Ensure branch protection rules | `health-44-gate-branch-protection.yml` | +| `disable_legacy_workflows.py` | Disable retired workflows | `maint-47-disable-legacy-workflows.yml` | +| `resolve_mypy_pin.py` | Resolve mypy version pin | `reusable-10-ci-python.yml` | +| `validate_quarantine_ttl.py` | Validate test quarantine TTL | Tests | +| `agents_index.py` | List agent bootstrap files | Tests | +| `simulate_codex_bootstrap.py` | Simulate Codex bootstrap logic | Tests | +| `simulate_failure_tracker.js` | Test failure tracking | Tests | +| `test_failure_signature.py` | Signature hashing for failures | `health_summarize.py` | +| `strip_output.py` | Strip Jupyter notebook outputs | `pre-commit` hook | +| `pre-commit` | Git pre-commit hook | Git hooks | +| `sanitize_workflows.sh` | Sanitize workflow YAML | Utilities | + +**Removed (2025-11-30):** +- `update_workflow_catalog.py` - Generator for stale catalog (catalog itself not tracked) + +**`trend_model.egg-info/` (not reviewed - build artifact):** +- Auto-generated by pip during editable install +- Already in `.gitignore` - not tracked +- Safe to delete, regenerates on `pip install -e .` + ## Overlapping docs and their scopes | Document | Audience | Scope/status | | --- | --- | --- | diff --git a/tools/update_workflow_catalog.py b/tools/update_workflow_catalog.py deleted file mode 100644 index 147b5682ae..0000000000 --- a/tools/update_workflow_catalog.py +++ /dev/null @@ -1,130 +0,0 @@ -#!/usr/bin/env python3 -"""Generate tools/workflow_catalog.json from .github/workflows. - -Heuristics: -- name: top-level 'name:' field; if missing, derive from filename. -- archived: true if 'ARCHIVED' appears in name or comment block + on: {} -- category classification via simple keyword rules. - -Categories (heuristic order): - ci: name contains any of ["CI", "Docker", "CodeQL", "Benchmark", "perf"] - remediation: name contains ["autofix", "fix", "remediation"] - governance: ["auto-merge", "automerge", "approve", "label", "stale", "path", "dependency", "quarantine"] - agents: ["agent", "codex", "copilot"] - release: ["release"] - security: ["codeql", "dependency"] - other: fallback - -Note: Keep logic lightweight; manual curation can adjust JSON after generation. -""" -from __future__ import annotations - -import datetime -import json -import pathlib -import re -import sys -from typing import Any - -import yaml - -ROOT = pathlib.Path(__file__).resolve().parents[1] -WF_DIR = ROOT / ".github" / "workflows" -CATALOG = ROOT / "tools" / "workflow_catalog.json" - -CATEGORY_RULES = [ - ("ci", re.compile(r"\b(CI|Docker|Benchmark|perf)\b", re.I)), - ("remediation", re.compile(r"autofix|remediation|fix", re.I)), - ( - "governance", - re.compile( - r"auto-merge|automerge|approve|label|stale|path|dependency|quarantine", re.I - ), - ), - ("agents", re.compile(r"agent|codex|copilot", re.I)), - ("release", re.compile(r"release", re.I)), - ("security", re.compile(r"codeql|dependency", re.I)), -] - - -def classify(name: str) -> str: - for cat, rx in CATEGORY_RULES: - if rx.search(name): - return cat - return "other" - - -def is_archived(data: dict[str, Any], text: str, name: str) -> bool: - if "on" in data and data["on"] == {}: - return True - if "ARCHIVED" in name.upper(): - return True - if "ARCHIVED WORKFLOW" in text.upper(): - return True - return False - - -def extract_triggers(data: dict[str, Any]) -> Any: - on = data.get("on", {}) - if isinstance(on, list): - return {k: True for k in on} - if isinstance(on, dict): - out = {} - for k, v in on.items(): - if k == "push": - if isinstance(v, dict) and "branches" in v: - out[k] = v["branches"] - else: - out[k] = True - elif k == "workflow_run": - if isinstance(v, dict) and "workflows" in v: - out[k] = v["workflows"] - else: - out[k] = True - else: - out[k] = True - return out - return {} - - -def main() -> int: - workflows = [] - for path in sorted(WF_DIR.glob("*.yml")): - text = path.read_text(encoding="utf-8") - try: - data = yaml.safe_load(text) or {} - except Exception as e: # pragma: no cover - print(f"WARN: YAML parse failed for {path.name}: {e}", file=sys.stderr) - data = {} - name = data.get("name") or path.stem - archived = is_archived(data, text, name) - triggers = extract_triggers(data) - workflows.append( - { - "file": path.name, - "name": name, - "category": classify(name), - "archived": archived, - "triggers": triggers, - "replacement_for": None, - } - ) - catalog = { - "_meta": { - "generated": datetime.datetime.now(datetime.timezone.utc) - .isoformat() - .replace("+00:00", "Z"), - "source": ".github/workflows", - "script": "tools/update_workflow_catalog.py", - }, - "workflows": workflows, - } - CATALOG.write_text( - json.dumps(catalog, indent=2, sort_keys=False) + "\n", encoding="utf-8" - ) - print(f"Updated {CATALOG} with {len(workflows)} entries.") - return 0 - - -if __name__ == "__main__": # pragma: no cover - raise SystemExit(main()) From 6db82cc943454adf5dbb4c8d4c4739e87cd0ee98 Mon Sep 17 00:00:00 2001 From: stranske Date: Sun, 30 Nov 2025 06:17:04 +0000 Subject: [PATCH 30/40] chore: remove tracked src/trend_analysis.egg-info/ build artifact This directory is auto-generated during pip install and should not be tracked. It's already covered by *.egg-info/ in .gitignore. --- src/trend_analysis.egg-info/PKG-INFO | 248 ------------------ src/trend_analysis.egg-info/SOURCES.txt | 81 ------ .../dependency_links.txt | 1 - src/trend_analysis.egg-info/top_level.txt | 2 - 4 files changed, 332 deletions(-) delete mode 100644 src/trend_analysis.egg-info/PKG-INFO delete mode 100644 src/trend_analysis.egg-info/SOURCES.txt delete mode 100644 src/trend_analysis.egg-info/dependency_links.txt delete mode 100644 src/trend_analysis.egg-info/top_level.txt diff --git a/src/trend_analysis.egg-info/PKG-INFO b/src/trend_analysis.egg-info/PKG-INFO deleted file mode 100644 index 63b40f1cad..0000000000 --- a/src/trend_analysis.egg-info/PKG-INFO +++ /dev/null @@ -1,248 +0,0 @@ -Metadata-Version: 2.4 -Name: trend-analysis -Version: 0.1.0 -Summary: Volatility-adjusted trend analysis package -License: MIT -Requires-Python: >=3.11 -Description-Content-Type: text/markdown -Provides-Extra: app -Requires-Dist: streamlit>=1.30; extra == "app" - -# Trend Model Project - -This repository contains experiments and utilities for analyzing volatility-adjusted trend portfolios. The Jupyter notebooks demonstrate how to load hedge fund data, apply trend-following rules, and export the results. - -For a beginner-friendly overview, see [docs/UserGuide.md](docs/UserGuide.md). - - -## Notebooks - -- `Vol_Adj_Trend_Analysis1.2.TrEx.ipynb` – an earlier version of the analysis. -- `Vol_Adj_Trend_Analysis1.4.TrEx.ipynb` – the current main notebook showing the full workflow. -- Additional historical notebooks can be found under `notebooks/old` and `Old/`. - -## Setup - -1. Create a virtual environment and install the required packages: - ```bash - ./scripts/setup_env.sh - ``` - This helper script lives in `scripts/setup_env.sh` and simply wraps - `python -m venv` followed by `pip install -r requirements.txt`. It - creates a `.venv` directory and installs everything from - `requirements.txt`, including `pandas`, `numpy`, `matplotlib`, - `ipywidgets`, `PyYAML` and `xlsxwriter`. -2. Launch Jupyter Lab or Jupyter Notebook: - ```bash - jupyter lab - # or - jupyter notebook - ``` -3. Open `Vol_Adj_Trend_Analysis1.4.TrEx.ipynb` and run the cells in - order. All notebooks reside at the repository root and depend on the - `trend_analysis` package for data loading, metrics and exports. - -## Applying patches - -Some updates are provided as patch files. Apply them from the repository root with: - -```bash -git apply -p1 -``` -The patches usually update modules under the `trend_analysis/` package, -allowing you to rebuild the library incrementally. - -Replace `` with the patch you want to apply (for example `codex.patch`). - -## Command-line usage - -You can also run the analysis pipeline directly from the command line. Invoke -the entry point with an optional configuration file: - -```bash -python -m trend_analysis.run_analysis -c path/to/config.yml -``` -This command invokes `main()` in `trend_analysis/run_analysis.py`. That -script loads the configuration via `trend_analysis.config.load()` and -then runs the pipeline defined in `trend_analysis/pipeline.py`. - -The configuration file **must** define `data.csv_path` pointing to your CSV -data. If ``-c`` is omitted, ``run_analysis`` loads -`config/defaults.yml`, or the path set via the ``TREND_CFG`` environment -variable: - -```bash -TREND_CFG=custom.yml python -m trend_analysis.run_analysis -``` -Here the environment variable ``TREND_CFG`` points the loader in -``trend_analysis.config`` to your custom YAML file, ensuring the same -``main()`` function from `run_analysis.py` uses your overrides. - - -## Ranking-based selection - -`portfolio.selection_mode` supports a new `rank` value for picking funds by -performance metrics. The defaults for this mode live under `portfolio.rank` in -`config/defaults.yml`. Metrics can be combined using z-scored weights so they -are comparable across scales. -The actual ranking logic is implemented in -`trend_analysis/core/rank_selection.py` and wired into the pipeline via -`trend_analysis/pipeline.py`. - -## Information ratio & benchmarks - -The pipeline also calculates each portfolio's **information ratio** relative to -one or more benchmarks. The YAML configuration accepts a `benchmarks` mapping -of labels to column names: - -```yaml -benchmarks: - spx: SPX - tsx: TSX -``` - -When set, additional `OS IR