From 8bed53666a5973a9b622a8a53c263e58f1687562 Mon Sep 17 00:00:00 2001 From: Saagar Date: Tue, 7 Jul 2026 00:30:09 -0700 Subject: [PATCH 1/2] fix: resolve portfolio decision queue catalog entries --- config/portfolio-catalog.yaml | 38 +++++++++++++++++++++++++++++++++++ 1 file changed, 38 insertions(+) diff --git a/config/portfolio-catalog.yaml b/config/portfolio-catalog.yaml index 659dfc5..1e52bf6 100644 --- a/config/portfolio-catalog.yaml +++ b/config/portfolio-catalog.yaml @@ -954,6 +954,32 @@ repos: target_maturity: functional automation_eligible: false notes: Active through the June 10-22, 2026 Fable window; staged harness/config changes are operator-installed only, then archive or park the campaign workspace after final index review. + fable-os-divergence: + owner: d + purpose: Fable campaign workspace for agent-OS divergence analysis and follow-up checklists + lifecycle_state: experimental + criticality: medium + review_cadence: ad-hoc + intended_disposition: experiment + category: infrastructure + tool_provenance: claude-ai + maturity_program: experiment + target_maturity: functional + automation_eligible: false + notes: Campaign evidence and next-step planning workspace; keep out of default portfolio attention unless a publish/park/archive decision is active. + fable-site-rebuild: + owner: d + purpose: control room for rebuilding the public portfolio site around the Fable site-rebuild campaign + lifecycle_state: experimental + criticality: medium + review_cadence: ad-hoc + intended_disposition: experiment + category: infrastructure + tool_provenance: claude-ai + maturity_program: experiment + target_maturity: functional + automation_eligible: false + notes: Not a product repo; the product surface is portfolio-index. Keep this workspace out of default attention except when the site-rebuild campaign is actively being dispatched. portfolio-index: owner: d purpose: public-safe static portfolio index for hiring-manager review @@ -978,6 +1004,18 @@ repos: review_cadence: weekly intended_disposition: maintain category: vanity + signal-noise: + owner: d + purpose: public Signal & Noise portfolio surface + lifecycle_state: active + criticality: medium + review_cadence: monthly + intended_disposition: maintain + category: vanity + tool_provenance: codex + maturity_program: maintain + target_maturity: operating + automation_eligible: false BattleGrid: owner: d lifecycle_state: active From 87b80314939f96be25131d9b0d33b11e94958a21 Mon Sep 17 00:00:00 2001 From: Saagar Date: Tue, 7 Jul 2026 00:41:00 -0700 Subject: [PATCH 2/2] fix: honor portfolio catalog aliases --- config/portfolio-catalog.yaml | 24 ++++++++++------------- src/portfolio_catalog.py | 17 ++++++++++++++++- tests/test_portfolio_catalog.py | 34 ++++++++++++++++++++++++++++++++- 3 files changed, 59 insertions(+), 16 deletions(-) diff --git a/config/portfolio-catalog.yaml b/config/portfolio-catalog.yaml index 1e52bf6..7003ca6 100644 --- a/config/portfolio-catalog.yaml +++ b/config/portfolio-catalog.yaml @@ -554,10 +554,18 @@ repos: tool_provenance: claude-code Signal & Noise: owner: d + purpose: public Signal & Noise portfolio surface lifecycle_state: active - review_cadence: weekly + criticality: medium + review_cadence: monthly intended_disposition: maintain + category: vanity tool_provenance: claude-code + maturity_program: maintain + target_maturity: operating + automation_eligible: false + aliases: + - signal-noise SpecCompanion: owner: d lifecycle_state: active @@ -1004,18 +1012,6 @@ repos: review_cadence: weekly intended_disposition: maintain category: vanity - signal-noise: - owner: d - purpose: public Signal & Noise portfolio surface - lifecycle_state: active - criticality: medium - review_cadence: monthly - intended_disposition: maintain - category: vanity - tool_provenance: codex - maturity_program: maintain - target_maturity: operating - automation_eligible: false BattleGrid: owner: d lifecycle_state: active @@ -1335,4 +1331,4 @@ repos: owner: d lifecycle_state: archived review_cadence: quarterly - intended_disposition: archive + intended_disposition: archive \ No newline at end of file diff --git a/src/portfolio_catalog.py b/src/portfolio_catalog.py index 53cfdfc..3ddf2a8 100644 --- a/src/portfolio_catalog.py +++ b/src/portfolio_catalog.py @@ -293,6 +293,10 @@ def _normalize_repo_entries( "matched_by": "full-name" if "/" in key else "bare-name", "has_explicit_entry": True, } + aliases = raw_value.get("aliases") or [] + if aliases and not isinstance(aliases, list): + errors.append(f"Portfolio catalog entry '{key}' aliases must be a list.") + aliases = [] for field_name, allowed in ( ("lifecycle_state", VALID_LIFECYCLE_STATES), ("criticality", VALID_CRITICALITY), @@ -316,6 +320,17 @@ def _normalize_repo_entries( seen_bare_names.add(bare_key) normalized_entries[_normalize_key(key)] = normalized + for raw_alias in aliases: + alias = _safe_text(raw_alias) + if not alias: + continue + normalized_alias = _normalize_key(alias) + if normalized_alias in normalized_entries: + warnings.append( + f"Portfolio catalog alias '{alias}' for '{key}' duplicates an existing repo key." + ) + continue + normalized_entries[normalized_alias] = normalized return normalized_entries @@ -601,4 +616,4 @@ def build_intent_alignment_summary(audits: list[Any]) -> dict[str, Any]: return { "counts": dict(counts), "summary": summary, - } + } \ No newline at end of file diff --git a/tests/test_portfolio_catalog.py b/tests/test_portfolio_catalog.py index f6b3554..376f9e6 100644 --- a/tests/test_portfolio_catalog.py +++ b/tests/test_portfolio_catalog.py @@ -62,6 +62,38 @@ def test_load_portfolio_catalog_accepts_defaults_and_repo_entries(tmp_path: Path assert catalog["repos"]["repob"]["doctor_standard"] == "" +def test_load_portfolio_catalog_indexes_repo_aliases(tmp_path: Path): + path = tmp_path / "portfolio-catalog.yaml" + path.write_text( + """ +repos: + Signal & Noise: + owner: d + purpose: public portfolio surface + lifecycle_state: active + criticality: medium + review_cadence: monthly + intended_disposition: maintain + category: vanity + aliases: + - signal-noise +""", + encoding="utf-8", + ) + + catalog = load_portfolio_catalog(path) + entry = catalog_entry_for_repo( + {"name": "signal-noise", "full_name": "saagpatel/signal-noise", "path": "signal-noise"}, + catalog, + ) + + assert catalog["errors"] == [] + assert entry["has_explicit_entry"] is True + assert entry["catalog_key"] == "Signal & Noise" + assert entry["owner"] == "d" + assert entry["matched_by"] == "path" + + def test_load_portfolio_catalog_normalizes_doctor_standard(tmp_path: Path): path = tmp_path / "portfolio-catalog.yaml" path.write_text( @@ -356,4 +388,4 @@ def test_catalog_line_and_summaries_cover_missing_contracts(): assert catalog_summary["cataloged_repo_count"] == 1 assert catalog_summary["missing_contract_count"] == 1 assert alignment_summary["counts"]["aligned"] == 1 - assert alignment_summary["counts"]["missing-contract"] == 1 + assert alignment_summary["counts"]["missing-contract"] == 1 \ No newline at end of file