Fix portfolio truth authority and attention classification#177
Fix portfolio truth authority and attention classification#177saagpatel wants to merge 14 commits into
Conversation
…ng constants - Delete dead .weight class attributes from all analyzers; scorer.WEIGHTS is the single source of truth. New tests/test_scoring_weights.py asserts weights sum to 1.0, match the composed dimension set, and introspects analyzer modules so a dead weight attr cannot be silently reintroduced. - Remove dead path_confidence parameter from build_risk_entry (accepted, never read) and its call sites. - Make STALE_THRESHOLD_DAYS, GRADE_THRESHOLDS, COMPLETENESS_TIERS overridable via reserved scoring-profile keys; ScoringProfile carries overrides alongside flat weights so existing custom_weights callers and shipped profiles are byte-identical. - Label the unscored description dimension via display_dimension() on operator-facing render surfaces; data fields keep raw dimension slugs.
…tale->parked moves to render derived.registry_status was a pure synonym table over activity_status (_registry_status_for: "parked" if stale else activity_status), forcing every downstream function (build_risk_entry, _attention_state_for, validators, renderers) to carry two parameters for one fact. Traced the "archived" side door precisely: activity_status already produced "archived" directly inside _activity_status_for (github_archived OR declared lifecycle_state == "archived"), and registry_status only ever passed that value through unchanged. The legacy registry file never fed the computation — it only drove an advisory diff warning. So "archived" was a lifecycle fact smuggled inside a recency observation, not a separate input. - activity_status is now pure recency (active/recent/stale), computed without the archived shortcut. - derived.archived: bool is the new first-class lifecycle field (github_archived or declared lifecycle_state == "archived"), passed independently to build_risk_entry, build_operating_path_entry, and _attention_state_for. - The stale->parked relabel moved to one documented function, portfolio_truth_types.display_activity_status, used by every renderer/report surface that used to read registry_status for display (portfolio_truth_render, weekly_command_center, portfolio_context_recovery, the legacy-diff warning). - Snapshot source_summary.registry_status_counts is replaced by activity_status_counts + archived_count. Schema bumped to 0.9.0; 0.8.0 added to LEGACY_SCHEMA_VERSIONS. - portfolio_automation's ELIGIBLE_REGISTRY_STATUS/AutomationCandidate field renamed to activity_status; run_instructions_audit's archived filter now reads the boolean directly. Behavior parity verified: risk tier, attention state, and displayed status are unchanged for every repo. Full suite: 2881 passed, 2 skipped (matches main baseline exactly). ruff check: clean.
…ting_path (read-compat kept) Wires operating_path as a first-class normalized catalog field end-to-end (loader, reconciler declared_values, scorecard program resolution, intent alignment, catalog summaries) -- it was previously accepted by the resolver but never actually populated from the catalog, so every entry resolved through the intended_disposition fallback. Rewrites config/portfolio-catalog.yaml and the example catalog (179 + 3 entries, identity value mapping) to declare operating_path directly, repoints the scorecards.yaml archive-disposition rule at the same field, and keeps intended_disposition as a deprecated read-compat fallback (resolver, loader, scorecards, catalog validator) with a new loader warning when an entry still declares it.
|
|
||
| from src.portfolio_truth_types import truth_latest_path | ||
| from src.report_contracts import RiskLookupEntry, RiskPosture, TopElevatedEntry | ||
| from src.scorer import display_dimension |
|
|
||
|
|
||
| def test_analyzer_classes_do_not_declare_dead_weight_attributes() -> None: | ||
| import src.analyzers as analyzers_package |
There was a problem hiding this comment.
💡 Codex Review
Here are some automated review suggestions for this pull request.
Reviewed commit: bbd4103b02
ℹ️ About Codex in GitHub
Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you
- Open a pull request for review
- Mark a draft as ready
- Comment "@codex review".
If Codex has suggestions, it will comment; otherwise it will react with 👍.
Codex can also answer questions or update the PR. Try commenting "@codex address that feedback".
| if _text(derived.get("activity_status")) not in ELIGIBLE_ACTIVITY_STATUS: | ||
| blockers.append("activity-status-not-eligible") |
There was a problem hiding this comment.
Keep archived repos out of automation candidates
Because activity_status is now pure recency, an archived project with recent local activity has derived.activity_status == "active" and derived.archived == true; this gate no longer checks the archived bit, so a trusted run can surface archived repos as bounded-automation candidates when they also have high path confidence and sufficient context. This regresses the previous registry_status == "archived" blocker and can route retired/read-only work into the automation lane.
Useful? React with 👍 / 👎.
| activity_status=display_activity_status( | ||
| project.derived.activity_status, archived=project.derived.archived | ||
| ), |
There was a problem hiding this comment.
Exclude archived repos from context recovery targets
At this point the plan can label a target as archived, but the selection above still only requires project.derived.activity_status in {"active", "recent"}. Since archived is no longer encoded in activity_status, recently-touched archived projects with weak context become eligible and apply_context_recovery_plan may write managed context blocks into repos that should remain retired; add an explicit not project.derived.archived gate before creating targets.
Useful? React with 👍 / 👎.
Summary
Verification
Boundaries preserved