Skip to content

Migrate portfolio truth lifecycle and operating-path contracts#182

Merged
saagpatel merged 4 commits into
mainfrom
codex/integration-truth-catalog
Jul 14, 2026
Merged

Migrate portfolio truth lifecycle and operating-path contracts#182
saagpatel merged 4 commits into
mainfrom
codex/integration-truth-catalog

Conversation

@saagpatel

Copy link
Copy Markdown
Owner

Stack 5/7. Separates recency from lifecycle, makes archived first-class, and migrates catalog declarations to operating_path with read compatibility. Depends on stack 4.

…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.
@saagpatel saagpatel force-pushed the codex/integration-truth-catalog branch from e32d70f to ac175fd Compare July 14, 2026 04:05
@saagpatel saagpatel force-pushed the codex/integration-attention-resolver branch from 4d48188 to 595339f Compare July 14, 2026 04:05
@saagpatel saagpatel changed the base branch from codex/integration-attention-resolver to main July 14, 2026 04:19
@saagpatel saagpatel marked this pull request as ready for review July 14, 2026 04:19

@chatgpt-codex-connector chatgpt-codex-connector Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

💡 Codex Review

Here are some automated review suggestions for this pull request.

Reviewed commit: 0e6d3d6c09

ℹ️ 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".

Comment on lines +83 to +84
if _text(derived.get("activity_status")) not in ELIGIBLE_ACTIVITY_STATUS:
blockers.append("activity-status-not-eligible")

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

P2 Badge Exclude archived repos from automation candidates

After this schema split, a project can now be both recently active and archived (derived.activity_status == "active" plus derived.archived == true, e.g. a GitHub-archived repo with recent local commits). This gate only checks the recency field, so an archived/read-only repo with high path confidence and sufficient context will be emitted as an automation candidate whenever decision quality is trusted, despite the module contract saying archived repos are not eligible. Add an explicit derived.archived blocker before accepting the activity status.

Useful? React with 👍 / 👎.

Comment on lines +569 to +571
"operating_path": _select_declared(
"operating_path", repo_entry, group_entry, provenance
),

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

P2 Badge Preserve repo legacy path precedence over group paths

For partially migrated catalogs, this selects operating_path from the group before a repo-specific legacy intended_disposition is considered. Because resolve_declared_operating_path then prefers any operating_path, a repo still declaring intended_disposition: archive under a group with operating_path: maintain is reconciled as maintain, losing the normal repo-over-group precedence during the promised read-compat window. Resolve the alias per source order (repo operating path, repo legacy disposition, group operating path, group legacy disposition) before passing it to pathing.

Useful? React with 👍 / 👎.

Comment on lines +469 to 470
if _safe_text(derived.get("activity_status")) == "active":
active_project_count += 1

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

P2 Badge Do not count archived projects as active registry entries

With activity_status now defined as pure recency, archived projects with recent activity keep activity_status: active while carrying archived: true. This summary still feeds the rendered phrase "active registry entries", so those archived/read-only projects are counted as active and the weekly command center reports a healthier/current portfolio than the truth snapshot says. Exclude derived.archived here or count via display_activity_status.

Useful? React with 👍 / 👎.

Comment thread config/scorecards.yaml
label: Archive Disposition
check: catalog_field_in
catalog_field: intended_disposition
catalog_field: operating_path

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

P2 Badge Keep the archive scorecard compatible with legacy disposition

During the one-release compatibility window, catalog entries that still use intended_disposition: archive are accepted and can still select the archive program via the scorecard resolver, but this migrated rule reads only operating_path. In that supported legacy scenario the Archive Disposition rule becomes not_applicable instead of passing, so archive entries are scored without the disposition gate. Normalize the alias before scoring or let this rule accept the legacy field too.

Useful? React with 👍 / 👎.

@saagpatel saagpatel merged commit 2c62c1c into main Jul 14, 2026
4 checks passed
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant