Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
60 changes: 38 additions & 22 deletions config/portfolio-catalog.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -132,7 +132,7 @@ repos:
ApplyKit:
owner: d
purpose: deterministic local-first application packet generation
lifecycle_state: active
lifecycle_state: manual-only
review_cadence: weekly
operating_path: maintain
category: commercial
Expand Down Expand Up @@ -227,7 +227,7 @@ repos:
MCPAudit:
owner: d
purpose: local MCP security and drift audit tool
lifecycle_state: manual-only
lifecycle_state: active
review_cadence: weekly
operating_path: maintain
category: infrastructure
Expand Down Expand Up @@ -278,7 +278,7 @@ repos:
operant-public:
owner: d
purpose: operating-agent calibration benchmark with shipped public MCP access
lifecycle_state: manual-only
lifecycle_state: active
criticality: high
review_cadence: weekly
operating_path: maintain
Expand Down Expand Up @@ -363,7 +363,7 @@ repos:
JobCommandCenter:
owner: d
purpose: desktop command-center shell for portfolio and operator workflows
lifecycle_state: active
lifecycle_state: manual-only
review_cadence: weekly
operating_path: maintain
category: commercial
Expand All @@ -386,7 +386,7 @@ repos:
tool_provenance: claude-code
AIWorkFlow:
owner: d
lifecycle_state: active
lifecycle_state: manual-only
review_cadence: monthly
operating_path: maintain
category: commercial
Expand All @@ -400,7 +400,7 @@ repos:
Phantom Frequencies:
owner: d
purpose: compact authored supernatural-radio game being finished as an Oddworks release
lifecycle_state: active
lifecycle_state: manual-only
criticality: high
review_cadence: weekly
operating_path: finish
Expand All @@ -419,7 +419,7 @@ repos:
SignalDecay:
owner: d
purpose: one-room 8-12 minute tactile signal-tuning game for the Oddworks label
lifecycle_state: active
lifecycle_state: manual-only
criticality: high
review_cadence: weekly
operating_path: finish
Expand Down Expand Up @@ -626,7 +626,7 @@ repos:
automation_eligible: true
Afterimage:
owner: d
lifecycle_state: active
lifecycle_state: manual-only
review_cadence: weekly
operating_path: maintain
category: commercial
Expand All @@ -648,7 +648,7 @@ repos:
Liminal:
owner: d
purpose: focused atmospheric iOS experience being finished as an Oddworks release
lifecycle_state: active
lifecycle_state: manual-only
criticality: high
review_cadence: weekly
operating_path: finish
Expand Down Expand Up @@ -799,7 +799,7 @@ repos:
DeepTank:
owner: d
purpose: authored aquatic simulation game being evaluated and finished for the Oddworks label
lifecycle_state: active
lifecycle_state: manual-only
criticality: high
review_cadence: weekly
operating_path: finish
Expand Down Expand Up @@ -953,7 +953,7 @@ repos:
operating_path: maintain
cross-system-smoke:
owner: d
lifecycle_state: active
lifecycle_state: manual-only
review_cadence: weekly
operating_path: maintain
category: infrastructure
Expand Down Expand Up @@ -1079,17 +1079,18 @@ repos:
owner: d
purpose: public-safe static portfolio index for hiring-manager review
lifecycle_state: active
criticality: high
review_cadence: monthly
operating_path: maintain
category: vanity
category: commercial
tool_provenance: claude-code
maturity_program: maintain
target_maturity: operating
automation_eligible: false
notes: Keep manual-only unless code or deployment work is active; resume and custom-domain decisions are mostly external to this repo.
notes: Tier-0 public workshop and canonical saagarpatel.dev product surface. Keep in default attention as the public front door for the core portfolio.
rag-knowledge-base:
owner: d
lifecycle_state: active
lifecycle_state: manual-only
review_cadence: weekly
operating_path: maintain
category: infrastructure
Expand All @@ -1102,7 +1103,7 @@ repos:
BattleGrid:
owner: d
purpose: focused tactical grid game being evaluated and finished for the Oddworks label
lifecycle_state: active
lifecycle_state: manual-only
criticality: high
review_cadence: weekly
operating_path: finish
Expand All @@ -1114,7 +1115,7 @@ repos:
OddworksCabinet:
owner: d
purpose: evidence-first gallery and release surface for small authored Oddworks experiences
lifecycle_state: active
lifecycle_state: manual-only
criticality: high
review_cadence: weekly
operating_path: finish
Expand Down Expand Up @@ -1296,7 +1297,7 @@ repos:
maturity_program: finish
mcpaudit-web:
owner: d
lifecycle_state: active
lifecycle_state: manual-only
review_cadence: weekly
operating_path: finish
maturity_program: finish
Expand Down Expand Up @@ -1479,12 +1480,25 @@ repos:
lifecycle_state: archived
review_cadence: quarterly
operating_path: archive
personal-ops:
owner: d
purpose: local operator control plane for cross-system workflows, approvals, and recovery
lifecycle_state: active
criticality: high
review_cadence: weekly
operating_path: maintain
category: infrastructure
tool_provenance: codex
maturity_program: maintain
target_maturity: operating
automation_eligible: false
notes: Tier-0 Operator OS project. The live checkout is outside the Projects workspace and is represented in generated registry output as supp:personal-ops.
# --- 2026-07-17 Portfolio Tribunal: contracts for previously uncataloged KEEP repos ---
Temper:
owner: d
purpose: private local-first macOS instrument for forecast-backed decision receipts
(forecast, deliberate, decide, observe, learn loop)
lifecycle_state: active
lifecycle_state: manual-only
review_cadence: weekly
operating_path: finish
category: commercial
Expand All @@ -1494,7 +1508,7 @@ repos:
owner: d
purpose: Book Two / Field Manual manuscript workspace holding the complete
validation-gated draft
lifecycle_state: active
lifecycle_state: manual-only
review_cadence: weekly
operating_path: finish
category: commercial
Expand All @@ -1518,7 +1532,7 @@ repos:
owner: d
purpose: upstream-contribution fork of the ccusage CLI (Claude Code usage/cost
reporting), kept as an active contribution vehicle
lifecycle_state: active
lifecycle_state: manual-only
review_cadence: monthly
operating_path: maintain
category: infrastructure
Expand All @@ -1535,7 +1549,7 @@ repos:
owner: d
purpose: public publishing imprint for difficult systems explained through direct
manipulation, simulation, annotation, narrative, and evidence
lifecycle_state: active
lifecycle_state: manual-only
review_cadence: weekly
operating_path: finish
category: commercial
Expand All @@ -1546,10 +1560,12 @@ repos:
purpose: public interactive explainer of the personal multi-agent operator OS,
deployed at operator-os-explainer.vercel.app
lifecycle_state: active
criticality: high
review_cadence: monthly
operating_path: maintain
category: vanity
category: commercial
tool_provenance: claude-code
notes: Tier-0 flagship story for the Operator OS and part of the public workshop product surface.
repository-renaissance:
owner: d
purpose: local-first case system for understanding and planning interventions in
Expand Down
59 changes: 50 additions & 9 deletions src/github_security_coverage.py
Original file line number Diff line number Diff line change
Expand Up @@ -26,6 +26,7 @@
DEFAULT_ATTENTION_STATES = frozenset(
{"active-product", "active-infra", "decision-needed"}
)
DEFAULT_EXPECTED_GITHUB_COHORT_COUNT = 9
PROVIDER_NAMES = ("dependabot", "code_scanning", "secret_scanning")
ELIGIBILITY_SOURCE = "github-account-repository-preflight-v1"
ELIGIBILITY_REASON = "private_user_repo_plan_unavailable"
Expand Down Expand Up @@ -151,9 +152,9 @@ def _canonical_repo(value: Any) -> str:
def derive_default_attention_cohort(
portfolio_truth: dict[str, Any],
*,
expected_count: int = 16,
expected_count: int = DEFAULT_EXPECTED_GITHUB_COHORT_COUNT,
) -> tuple[str, ...]:
"""Return the canonical default-attention GitHub cohort, failing on expansion."""
"""Return the repo-backed default-attention cohort, failing on expansion."""
repos: list[str] = []
for project in portfolio_truth.get("projects") or []:
if not isinstance(project, dict):
Expand All @@ -162,7 +163,14 @@ def derive_default_attention_cohort(
if derived.get("attention_state") not in DEFAULT_ATTENTION_STATES:
continue
identity = _mapping(project.get("identity"))
repos.append(_canonical_repo(identity.get("repo_full_name")))
repo_full_name = identity.get("repo_full_name")
if not _text(repo_full_name) and _text(identity.get("project_key")).startswith(
"supp:"
):
# Supplementary projects such as personal-ops are real portfolio
# identities, but they do not have a GitHub repository to query.
continue
repos.append(_canonical_repo(repo_full_name))
if len({repo.lower() for repo in repos}) != len(repos):
raise SecurityCoverageError(
"default-attention cohort contains duplicate canonical repositories"
Expand Down Expand Up @@ -729,7 +737,7 @@ def collect_security_coverage(
portfolio_truth: dict[str, Any],
*,
token: str | None,
expected_cohort_count: int = 16,
expected_cohort_count: int = DEFAULT_EXPECTED_GITHUB_COHORT_COUNT,
base_request_limit: int = DEFAULT_BASE_REQUEST_LIMIT,
total_request_limit: int = DEFAULT_TOTAL_REQUEST_LIMIT,
quota_reserve: int = DEFAULT_QUOTA_RESERVE,
Expand All @@ -751,11 +759,24 @@ def collect_security_coverage(
):
raise SecurityCoverageError("request budget limits exceed the bounded contract")
if prior_receipt is not None:
prior_expected_count = _mapping(prior_receipt.get("cohort")).get(
"expected_count"
)
if not isinstance(prior_expected_count, int):
raise SecurityCoverageError(
"prior receipt cohort expected_count is invalid"
)
validate_security_coverage_receipt(
prior_receipt,
max_age_hours=24 * 365,
expected_cohort_count=prior_expected_count,
now=now,
)
if prior_expected_count != expected_cohort_count:
# A valid receipt for the previous bounded cohort cannot safely
# supply conditional-request or eligibility hints for the new one.
# Ignore it so the policy transition can produce fresh evidence.
prior_receipt = None
cohort = derive_default_attention_cohort(
portfolio_truth, expected_count=expected_cohort_count
)
Expand Down Expand Up @@ -1131,7 +1152,7 @@ def validate_security_coverage_receipt(
payload: Any,
*,
max_age_hours: int = 24,
expected_cohort_count: int = 16,
expected_cohort_count: int = DEFAULT_EXPECTED_GITHUB_COHORT_COUNT,
now: datetime | None = None,
source_path: str = "",
) -> LoadedSecurityCoverage:
Expand Down Expand Up @@ -1264,6 +1285,7 @@ def load_security_coverage_receipt(
path: Path,
*,
max_age_hours: int = 24,
expected_cohort_count: int = DEFAULT_EXPECTED_GITHUB_COHORT_COUNT,
now: datetime | None = None,
) -> LoadedSecurityCoverage:
try:
Expand All @@ -1279,14 +1301,24 @@ def load_security_coverage_receipt(
return validate_security_coverage_receipt(
payload,
max_age_hours=max_age_hours,
expected_cohort_count=expected_cohort_count,
now=now,
source_path=str(path),
)


def write_security_coverage_receipt(payload: dict[str, Any], path: Path) -> None:
def write_security_coverage_receipt(
payload: dict[str, Any],
path: Path,
*,
expected_cohort_count: int = DEFAULT_EXPECTED_GITHUB_COHORT_COUNT,
) -> None:
"""Atomically write a validated receipt payload."""
validate_security_coverage_receipt(payload, max_age_hours=24 * 365)
validate_security_coverage_receipt(
payload,
max_age_hours=24 * 365,
expected_cohort_count=expected_cohort_count,
)
path.parent.mkdir(parents=True, exist_ok=True)
temporary = path.with_name(f".{path.name}.tmp")
temporary.write_text(json.dumps(payload, indent=2, sort_keys=True) + "\n")
Expand Down Expand Up @@ -1330,7 +1362,11 @@ def main() -> None:
default=24,
help="Freshness window used by --validate-only (default: 24)",
)
parser.add_argument("--expected-cohort-count", type=int, default=16)
parser.add_argument(
"--expected-cohort-count",
type=int,
default=DEFAULT_EXPECTED_GITHUB_COHORT_COUNT,
)
parser.add_argument(
"--base-request-limit", type=int, default=DEFAULT_BASE_REQUEST_LIMIT
)
Expand All @@ -1345,6 +1381,7 @@ def main() -> None:
loaded = load_security_coverage_receipt(
args.output,
max_age_hours=args.max_age_hours,
expected_cohort_count=args.expected_cohort_count,
)
print(
json.dumps(
Expand All @@ -1370,7 +1407,11 @@ def main() -> None:
quota_reserve=args.quota_reserve,
prior_receipt=prior,
)
write_security_coverage_receipt(receipt, args.output)
write_security_coverage_receipt(
receipt,
args.output,
expected_cohort_count=args.expected_cohort_count,
)
except SecurityCoverageError as exc:
raise SystemExit(str(exc)) from exc
print(
Expand Down
15 changes: 11 additions & 4 deletions src/portfolio_risk.py
Original file line number Diff line number Diff line change
Expand Up @@ -95,16 +95,23 @@ def build_risk_entry(
if criticality in {"high", "critical"} and not known_risks_present:
factors.append("undocumented-risks")

# Active repo carrying open high- or critical-severity Dependabot alerts.
# A currently active repo, or a stale repo intentionally kept on the maintain
# path, carrying open high- or critical-severity Dependabot alerts.
# High alerts contribute one normal factor toward the 3+ elevation threshold;
# an open critical alert force-elevates on its own (see is_elevated below) — a
# lone unpatched critical CVE cannot hide in an otherwise-clean repo.
active = activity_status in ACTIVE_STATUSES
if active and (security_high_alerts > 0 or security_critical_alerts > 0):
security_relevant = (
activity_status in ACTIVE_STATUSES or operating_path == "maintain"
)
if security_relevant and (
security_high_alerts > 0 or security_critical_alerts > 0
):
factors.append("active-high-severity-alerts")

# Derive tier
security_forces_elevated = active and security_critical_alerts > 0
security_forces_elevated = (
security_relevant and security_critical_alerts > 0
)
is_elevated = (
len(factors) >= 3
or ("weak-context-active" in factors and "investigate-override" in factors)
Expand Down
Loading