From 4ebf37335a30dd698521cfbbd02509248cc3a572 Mon Sep 17 00:00:00 2001 From: saagpatel Date: Sun, 7 Jun 2026 15:09:03 -0700 Subject: [PATCH 1/3] Adopt proof package standard --- README.md | 13 ++ docs/demo-proof/2026-06-07/SUMMARY.md | 19 ++ docs/demo-proof/2026-06-07/proof-package.json | 183 ++++++++++++++++++ docs/proof-package-contract.md | 100 ++++++++++ scripts/validate_proof_package.py | 134 +++++++++++++ .../proof-packages/valid/evidence/example.txt | 1 + .../proof-packages/valid/proof-package.json | 57 ++++++ tests/test_validate_proof_package.py | 48 +++++ 8 files changed, 555 insertions(+) create mode 100644 docs/demo-proof/2026-06-07/SUMMARY.md create mode 100644 docs/demo-proof/2026-06-07/proof-package.json create mode 100644 docs/proof-package-contract.md create mode 100644 scripts/validate_proof_package.py create mode 100644 tests/fixtures/proof-packages/valid/evidence/example.txt create mode 100644 tests/fixtures/proof-packages/valid/proof-package.json create mode 100644 tests/test_validate_proof_package.py diff --git a/README.md b/README.md index 605338c..2b15d3f 100644 --- a/README.md +++ b/README.md @@ -431,6 +431,19 @@ Common fixes: There is also a longer operator guide in [docs/operator-troubleshooting.md](docs/operator-troubleshooting.md). +## Proof Packages + +Cross-repo done-state proof now uses `proof-package.v1`; see +[docs/proof-package-contract.md](docs/proof-package-contract.md). The first +concrete package is the PortfolioCommandCenter five-tab local demo proof at +[docs/demo-proof/2026-06-07/proof-package.json](docs/demo-proof/2026-06-07/proof-package.json). + +Validate a package with: + +```bash +python scripts/validate_proof_package.py docs/demo-proof/2026-06-07/proof-package.json +``` + ## License MIT diff --git a/docs/demo-proof/2026-06-07/SUMMARY.md b/docs/demo-proof/2026-06-07/SUMMARY.md new file mode 100644 index 0000000..d37c650 --- /dev/null +++ b/docs/demo-proof/2026-06-07/SUMMARY.md @@ -0,0 +1,19 @@ +# PortfolioCommandCenter Demo Proof Package + +This package proves the 2026-06-07 local five-tab PortfolioCommandCenter demo. +GithubRepoAuditor is the evidence producer because it owns the portfolio truth +and generated screenshots; PortfolioCommandCenter is the subject repo being +demonstrated. + +Status: passed. + +Key proof points: + +- Portfolio tab: 129 projects. +- Risk + Security tab: 117 scanned repos and 63 with open high/critical alerts. +- Burndown tab: advisory-grouped fix guidance. +- Trends tab: risk and high/critical history charts. +- Weekly Digest tab: current decision ends with `Start with codexkit.` + +Use `proof-package.json` for the machine-readable claim-to-evidence map and +`README.md` for the narrative proof summary. diff --git a/docs/demo-proof/2026-06-07/proof-package.json b/docs/demo-proof/2026-06-07/proof-package.json new file mode 100644 index 0000000..2efa776 --- /dev/null +++ b/docs/demo-proof/2026-06-07/proof-package.json @@ -0,0 +1,183 @@ +{ + "schema_version": "proof-package.v1", + "package_id": "20260607-portfolio-command-center-demo", + "subject": { + "repo": "PortfolioCommandCenter", + "lane": "local-desktop-demo", + "claim": "The five-tab desktop demo reflects the current GithubRepoAuditor portfolio truth snapshot." + }, + "producer": { + "repo": "GithubRepoAuditor", + "mode": "demo", + "commands": [ + "python -m src.cli --portfolio-truth --portfolio-truth-include-security saagpatel", + "python -m src.cli triage saagpatel --control-center", + "pnpm demo:desktop" + ] + }, + "source_state": { + "generated_at": "2026-06-07T17:00:59.463918+00:00", + "git_branch": "main", + "git_status": "dirty-preexisting-delete:.github/pull_request_template.md", + "freshness_window_hours": 24, + "source_truth_schema": "0.5.0" + }, + "claims": [ + { + "id": "portfolio-tab-count", + "statement": "The Portfolio tab shows 129 projects from the truth snapshot.", + "status": "passed", + "evidence": [ + "portfolio-screenshot", + "portfolio-truth" + ] + }, + { + "id": "risk-security-tab", + "statement": "The Risk + Security tab shows 117 scanned repos and 63 repos with open high/critical Dependabot alerts.", + "status": "passed", + "evidence": [ + "risk-security-screenshot", + "portfolio-truth" + ] + }, + { + "id": "burndown-tab", + "statement": "The Burndown tab renders advisory-grouped fix guidance with affected repo counts.", + "status": "passed", + "evidence": [ + "burndown-screenshot" + ] + }, + { + "id": "trends-tab", + "statement": "The Trends tab renders risk-tier and high/critical history charts.", + "status": "passed", + "evidence": [ + "trends-screenshot" + ] + }, + { + "id": "weekly-digest-tab", + "statement": "The Weekly Digest tab shows the current decision ending with 'Start with codexkit.'", + "status": "passed", + "evidence": [ + "weekly-digest-screenshot", + "weekly-digest-json" + ] + }, + { + "id": "five-frame-contact-sheet", + "statement": "A contact sheet exists for quick visual smoke review of all five frames.", + "status": "passed", + "evidence": [ + "contact-sheet" + ] + } + ], + "verification": { + "overall": "passed", + "checks": [ + { + "name": "manifest references local screenshots and source receipts", + "status": "passed" + }, + { + "name": "demo proof README lists commands, source truth, and proof points", + "status": "passed" + } + ], + "missing_receipts": [], + "known_gaps": [ + "This package proves the 2026-06-07 local demo capture, not current live runtime freshness after that timestamp.", + "PortfolioCommandCenter is the subject repo; screenshot evidence is intentionally stored under the GithubRepoAuditor producer repo." + ] + }, + "safety": { + "redaction": "none", + "secrets_checked": true, + "live_write_performed": false + }, + "artifacts": [ + { + "id": "demo-readme", + "kind": "summary", + "path": "README.md", + "description": "Human-readable demo proof summary.", + "required": true + }, + { + "id": "recording-checklist", + "kind": "checklist", + "path": "RECORDING-CHECKLIST.md", + "description": "90-second capture order and publish-time checks.", + "required": true + }, + { + "id": "portfolio-screenshot", + "kind": "screenshot", + "path": "images/01-portfolio.png", + "description": "Portfolio tab screenshot.", + "required": true + }, + { + "id": "risk-security-screenshot", + "kind": "screenshot", + "path": "images/02-risk-security.png", + "description": "Risk + Security tab screenshot.", + "required": true + }, + { + "id": "burndown-screenshot", + "kind": "screenshot", + "path": "images/03-burndown.png", + "description": "Burndown tab screenshot.", + "required": true + }, + { + "id": "trends-screenshot", + "kind": "screenshot", + "path": "images/04-trends.png", + "description": "Trends tab screenshot.", + "required": true + }, + { + "id": "weekly-digest-screenshot", + "kind": "screenshot", + "path": "images/05-weekly-digest.png", + "description": "Weekly Digest tab screenshot.", + "required": true + }, + { + "id": "contact-sheet", + "kind": "screenshot", + "path": "images/contact-sheet.png", + "description": "Five-frame visual smoke contact sheet.", + "required": true + }, + { + "id": "portfolio-truth", + "kind": "json-receipt", + "path": "../../../output/portfolio-truth-latest.json", + "description": "Canonical portfolio truth snapshot consumed by the demo.", + "required": true, + "owner_repo": "GithubRepoAuditor" + }, + { + "id": "weekly-digest-json", + "kind": "json-receipt", + "path": "../../../output/weekly-command-center-saagpatel-2026-06-03.json", + "description": "Weekly command-center digest consumed by the Weekly Digest tab.", + "required": true, + "owner_repo": "GithubRepoAuditor" + }, + { + "id": "portfolio-command-center-readme", + "kind": "repo-doc", + "path": "../../../../PortfolioCommandCenter/README.md", + "description": "Subject repo demo instructions and proof pointer.", + "required": true, + "owner_repo": "PortfolioCommandCenter" + } + ] +} diff --git a/docs/proof-package-contract.md b/docs/proof-package-contract.md new file mode 100644 index 0000000..0b318da --- /dev/null +++ b/docs/proof-package-contract.md @@ -0,0 +1,100 @@ +# Proof Package Contract v1 + +Proof packages are small, durable evidence bundles for done-state claims. They do +not replace each repo's native reports, screenshots, release assets, dry-run +outputs, or health commands. They point at those artifacts and make the claim +auditable from one manifest. + +Use a proof package whenever future work needs to prove that a demo, live write, +dry run, release, sync, health gate, or operational burn-in is actually done. + +## Layout + +```text +docs/proof-packages/-/ + proof-package.json + SUMMARY.md + evidence/ + receipts/ + logs/ +``` + +The package may reference existing artifacts outside the package when copying +them would create churn. Cross-repo references are allowed, but the manifest must +name the producer, subject, and evidence owner explicitly. + +## Manifest + +`proof-package.json` is required. + +Required top-level fields: + +- `schema_version`: must be `proof-package.v1`. +- `package_id`: stable package identifier. +- `subject`: repo, lane, and claim being proven. +- `producer`: repo or command surface that produced the evidence. +- `source_state`: generation time, branch/status when known, and freshness. +- `claims`: list of specific statements with status and evidence. +- `verification`: overall result, checks, missing receipts, and known gaps. +- `safety`: live-write and redaction posture. +- `artifacts`: all referenced files or external evidence. + +Allowed claim and verification statuses: + +- `passed` +- `failed` +- `partial` +- `stale` + +## Artifact Rules + +Each artifact entry should include: + +- `id` +- `kind` +- `path` +- `description` +- `required` + +Optional artifact fields: + +- `external`: set to `true` when the path is outside the manifest directory and + should not be checked by the lightweight validator. +- `owner_repo`: useful for cross-repo proof, such as PortfolioCommandCenter proof + stored under GithubRepoAuditor. + +Local relative artifacts are validated relative to the manifest file. + +## Claim Rules + +Every claim needs: + +- `id` +- `statement` +- `status` +- `evidence` + +`evidence` is a list of artifact IDs. A claim may also include `notes` when the +proof is intentionally bounded or stale-prone. + +## Done-State Rules + +- Demo proof requires source truth plus screenshots or recording. +- Dry-run proof requires planned writes, failed/partial steps, and a live + go/no-go decision. +- Live-write proof requires read-back or downstream receipt. +- Runtime proof requires a health, burn-in, or status output with explicit + failure/drift fields. +- Release proof requires build/test/install or checksum evidence. + +## Validation + +Run: + +```bash +python scripts/validate_proof_package.py docs/proof-packages//proof-package.json +``` + +The validator checks structure and local file references. It intentionally does +not judge whether a claim is true; the package author must still choose honest +claim statements and bounded evidence. diff --git a/scripts/validate_proof_package.py b/scripts/validate_proof_package.py new file mode 100644 index 0000000..27b1921 --- /dev/null +++ b/scripts/validate_proof_package.py @@ -0,0 +1,134 @@ +#!/usr/bin/env python3 +"""Validate a proof-package.v1 manifest. + +This is deliberately lightweight. It verifies structure and local file +references so proof packages stay easy to inspect without becoming a platform. +""" + +from __future__ import annotations + +import argparse +import json +from pathlib import Path +from typing import Any + +ALLOWED_STATUSES = {"passed", "failed", "partial", "stale"} +REQUIRED_TOP_LEVEL = { + "schema_version", + "package_id", + "subject", + "producer", + "source_state", + "claims", + "verification", + "safety", + "artifacts", +} +REQUIRED_ARTIFACT_FIELDS = {"id", "kind", "path", "description", "required"} +REQUIRED_CLAIM_FIELDS = {"id", "statement", "status", "evidence"} + + +def _load_manifest(path: Path) -> dict[str, Any]: + with path.open(encoding="utf-8") as handle: + data = json.load(handle) + if not isinstance(data, dict): + raise ValueError("manifest must be a JSON object") + return data + + +def validate_manifest(path: Path) -> list[str]: + errors: list[str] = [] + manifest = _load_manifest(path) + + missing = sorted(REQUIRED_TOP_LEVEL - set(manifest)) + if missing: + errors.append(f"missing top-level fields: {', '.join(missing)}") + + if manifest.get("schema_version") != "proof-package.v1": + errors.append("schema_version must be proof-package.v1") + + artifacts = manifest.get("artifacts") + artifact_ids: set[str] = set() + if not isinstance(artifacts, list) or not artifacts: + errors.append("artifacts must be a non-empty list") + else: + for index, artifact in enumerate(artifacts): + if not isinstance(artifact, dict): + errors.append(f"artifacts[{index}] must be an object") + continue + missing_artifact = sorted(REQUIRED_ARTIFACT_FIELDS - set(artifact)) + if missing_artifact: + errors.append( + f"artifacts[{index}] missing fields: {', '.join(missing_artifact)}" + ) + artifact_id = artifact.get("id") + if isinstance(artifact_id, str): + if artifact_id in artifact_ids: + errors.append(f"duplicate artifact id: {artifact_id}") + artifact_ids.add(artifact_id) + artifact_path = artifact.get("path") + if ( + isinstance(artifact_path, str) + and not artifact.get("external", False) + and artifact.get("required", False) + ): + candidate = Path(artifact_path) + if not candidate.is_absolute(): + candidate = path.parent / candidate + if not candidate.exists(): + errors.append(f"required artifact missing: {artifact_path}") + + claims = manifest.get("claims") + if not isinstance(claims, list) or not claims: + errors.append("claims must be a non-empty list") + else: + for index, claim in enumerate(claims): + if not isinstance(claim, dict): + errors.append(f"claims[{index}] must be an object") + continue + missing_claim = sorted(REQUIRED_CLAIM_FIELDS - set(claim)) + if missing_claim: + errors.append(f"claims[{index}] missing fields: {', '.join(missing_claim)}") + status = claim.get("status") + if status not in ALLOWED_STATUSES: + errors.append(f"claims[{index}] has invalid status: {status}") + evidence = claim.get("evidence") + if not isinstance(evidence, list) or not evidence: + errors.append(f"claims[{index}] evidence must be a non-empty list") + else: + for evidence_id in evidence: + if evidence_id not in artifact_ids: + errors.append( + f"claims[{index}] references unknown artifact: {evidence_id}" + ) + + verification = manifest.get("verification") + if isinstance(verification, dict): + overall = verification.get("overall") + if overall not in ALLOWED_STATUSES: + errors.append(f"verification.overall has invalid status: {overall}") + checks = verification.get("checks") + if not isinstance(checks, list): + errors.append("verification.checks must be a list") + elif "verification" in manifest: + errors.append("verification must be an object") + + return errors + + +def main() -> int: + parser = argparse.ArgumentParser(description=__doc__) + parser.add_argument("manifest", type=Path) + args = parser.parse_args() + + errors = validate_manifest(args.manifest) + if errors: + for error in errors: + print(f"proof package invalid: {error}") + return 1 + print(f"proof package valid: {args.manifest}") + return 0 + + +if __name__ == "__main__": + raise SystemExit(main()) diff --git a/tests/fixtures/proof-packages/valid/evidence/example.txt b/tests/fixtures/proof-packages/valid/evidence/example.txt new file mode 100644 index 0000000..d70d386 --- /dev/null +++ b/tests/fixtures/proof-packages/valid/evidence/example.txt @@ -0,0 +1 @@ +fixture evidence diff --git a/tests/fixtures/proof-packages/valid/proof-package.json b/tests/fixtures/proof-packages/valid/proof-package.json new file mode 100644 index 0000000..67c545e --- /dev/null +++ b/tests/fixtures/proof-packages/valid/proof-package.json @@ -0,0 +1,57 @@ +{ + "schema_version": "proof-package.v1", + "package_id": "fixture-valid-proof-package", + "subject": { + "repo": "FixtureRepo", + "lane": "demo-proof", + "claim": "The fixture demo proof is structurally valid." + }, + "producer": { + "repo": "FixtureRepo", + "mode": "demo", + "commands": [ + "fixture demo" + ] + }, + "source_state": { + "generated_at": "2026-06-07T00:00:00Z", + "git_branch": "main", + "git_status": "clean", + "freshness_window_hours": 24 + }, + "claims": [ + { + "id": "fixture-evidence-present", + "statement": "The required fixture evidence file exists.", + "status": "passed", + "evidence": [ + "fixture-evidence" + ] + } + ], + "verification": { + "overall": "passed", + "checks": [ + { + "name": "manifest structural validation", + "status": "passed" + } + ], + "missing_receipts": [], + "known_gaps": [] + }, + "safety": { + "redaction": "none", + "secrets_checked": true, + "live_write_performed": false + }, + "artifacts": [ + { + "id": "fixture-evidence", + "kind": "evidence", + "path": "evidence/example.txt", + "description": "Tiny fixture evidence file.", + "required": true + } + ] +} diff --git a/tests/test_validate_proof_package.py b/tests/test_validate_proof_package.py new file mode 100644 index 0000000..5f8ec2e --- /dev/null +++ b/tests/test_validate_proof_package.py @@ -0,0 +1,48 @@ +import json +from pathlib import Path + +from scripts.validate_proof_package import validate_manifest + + +def test_valid_proof_package_fixture() -> None: + manifest = Path("tests/fixtures/proof-packages/valid/proof-package.json") + + assert validate_manifest(manifest) == [] + + +def test_missing_required_artifact_is_reported(tmp_path: Path) -> None: + manifest = { + "schema_version": "proof-package.v1", + "package_id": "missing-artifact", + "subject": {"repo": "Example", "lane": "demo", "claim": "Demo works"}, + "producer": {"repo": "Example", "mode": "demo", "commands": []}, + "source_state": {"generated_at": "2026-06-07T00:00:00Z"}, + "claims": [ + { + "id": "claim-1", + "statement": "Required evidence exists", + "status": "passed", + "evidence": ["missing-file"], + } + ], + "verification": { + "overall": "passed", + "checks": [], + "missing_receipts": [], + "known_gaps": [], + }, + "safety": {"redaction": "none", "secrets_checked": True, "live_write_performed": False}, + "artifacts": [ + { + "id": "missing-file", + "kind": "receipt", + "path": "receipts/missing.json", + "description": "Missing required receipt", + "required": True, + } + ], + } + path = tmp_path / "proof-package.json" + path.write_text(json.dumps(manifest), encoding="utf-8") + + assert validate_manifest(path) == ["required artifact missing: receipts/missing.json"] From 2d0f90d16c40f5a408ab433c425db8885143dc48 Mon Sep 17 00:00:00 2001 From: saagpatel Date: Sun, 7 Jun 2026 21:51:27 -0700 Subject: [PATCH 2/3] fix(portfolio): separate activity from attention --- docs/weekly-review.md | 2 +- src/portfolio_truth_reconcile.py | 48 +++++++++++++++++ src/portfolio_truth_render.py | 16 ++++-- src/portfolio_truth_types.py | 13 ++++- src/portfolio_truth_validate.py | 5 ++ src/weekly_command_center.py | 21 ++++++-- tests/test_portfolio_truth.py | 83 ++++++++++++++++++++++++++++- tests/test_weekly_command_center.py | 33 +++++++++++- 8 files changed, 209 insertions(+), 12 deletions(-) diff --git a/docs/weekly-review.md b/docs/weekly-review.md index 0870b5f..9e25f1f 100644 --- a/docs/weekly-review.md +++ b/docs/weekly-review.md @@ -21,7 +21,7 @@ Use this guide for the normal ongoing operator loop. If you need the broader pro The primary workbook, HTML, Markdown, review-pack, and scheduled-handoff surfaces all tell the same compressed operator story: - `Act Now` means blocked or urgent pressure is active right now. -- `Watch Closely` means the repo is active and deserves attention, but it does not outrank the highest-pressure work yet. +- `Watch Closely` means the repo has an active attention state or concrete decision signal, but it does not outrank the highest-pressure work yet. - `Improving` means the path is stabilizing and recent action is helping. - `Fragile` means progress is real but easy to lose. - `Revalidate` means confidence still needs to be rebuilt before the repo should be treated as restored. diff --git a/src/portfolio_truth_reconcile.py b/src/portfolio_truth_reconcile.py index 74d2b45..ca50dbf 100644 --- a/src/portfolio_truth_reconcile.py +++ b/src/portfolio_truth_reconcile.py @@ -61,6 +61,7 @@ "derived.last_meaningful_activity_at": ["git", "workspace"], "derived.activity_status": ["derived"], "derived.registry_status": ["derived"], + "derived.attention_state": ["derived"], "derived.path_override": ["normalized"], "derived.path_confidence": ["normalized"], "derived.path_rationale": ["normalized"], @@ -222,6 +223,9 @@ def build_portfolio_truth_snapshot( "registry_status_counts": dict( Counter(project.derived.registry_status for project in projects) ), + "attention_state_counts": dict( + Counter(project.derived.attention_state for project in projects) + ), "duplicate_display_names": _duplicate_display_names(projects), "unresolved_duplicate_display_names": _unresolved_duplicate_display_names(projects), } @@ -458,6 +462,15 @@ def _build_truth_project( security_high_alerts=security.dependabot_high, security_critical_alerts=security.dependabot_critical, ) + attention_state = _attention_state_for( + registry_status=registry_status, + lifecycle_state=declared_values["lifecycle_state"], + operating_path=path_entry.get("operating_path", ""), + intended_disposition=declared_values["intended_disposition"], + category=declared_values["category"], + path_override=path_entry.get("path_override", ""), + risk_entry=risk_entry, + ) declared = DeclaredFields( owner=declared_values["owner"], @@ -482,6 +495,7 @@ def _build_truth_project( } provenance["derived.activity_status"] = {"source": "derived", "detail": activity_status} provenance["derived.registry_status"] = {"source": "derived", "detail": registry_status} + provenance["derived.attention_state"] = {"source": "derived", "detail": attention_state} provenance["derived.stack"] = {"source": "workspace", "detail": ", ".join(raw_project["stack"])} provenance["derived.context_files"] = { "source": "workspace", @@ -543,6 +557,7 @@ def _build_truth_project( last_meaningful_activity_at=last_activity, activity_status=activity_status, registry_status=registry_status, + attention_state=attention_state, path_override=path_entry.get("path_override", ""), path_confidence=path_entry.get("path_confidence", "legacy"), path_rationale=path_entry.get("path_rationale", ""), @@ -723,3 +738,36 @@ def _registry_status_for(activity_status: str) -> str: if activity_status == "stale": return "parked" return activity_status + + +def _attention_state_for( + *, + registry_status: str, + lifecycle_state: str, + operating_path: str, + intended_disposition: str, + category: str, + path_override: str, + risk_entry: dict[str, Any], +) -> str: + if registry_status == "archived" or lifecycle_state == "archived" or operating_path == "archive": + return "archived" + if ( + operating_path == "experiment" + or intended_disposition == "experiment" + or lifecycle_state == "experimental" + ): + return "experiment" + if registry_status == "parked": + return "parked" + if path_override == "investigate" or not operating_path or risk_entry.get("security_risk"): + return "decision-needed" + if registry_status in {"active", "recent"} and operating_path in {"maintain", "finish"}: + if category == "infrastructure": + return "active-infra" + if category == "commercial": + return "active-product" + return "manual-only" + if registry_status in {"active", "recent"}: + return "manual-only" + return "parked" diff --git a/src/portfolio_truth_render.py b/src/portfolio_truth_render.py index 043db19..8b4dae9 100644 --- a/src/portfolio_truth_render.py +++ b/src/portfolio_truth_render.py @@ -96,6 +96,7 @@ def render_portfolio_report_markdown( grouped = _group_projects(snapshot.projects) context_counts = Counter(project.derived.context_quality for project in snapshot.projects) registry_counts = Counter(project.derived.registry_status for project in snapshot.projects) + attention_counts = Counter(project.derived.attention_state for project in snapshot.projects) operating_path_counts = Counter( project.declared.operating_path or "unspecified" for project in snapshot.projects ) @@ -140,13 +141,14 @@ def render_portfolio_report_markdown( "- The truth layer scans the local workspace first, using directory metadata and small allowlisted context files only.", "- Declared ownership, lifecycle, review cadence, category, and tool hints come from `portfolio-catalog.yaml` when present.", "- Local git recency and safe filesystem timestamps drive the derived activity and compatibility status fields.", + "- Registry status describes activity recency; attention state decides whether an item deserves default operator attention.", "- Legacy registry values are treated as migration evidence only; they do not override derived activity or context truth.", "- Optional Notion fields are advisory and are not allowed to replace declared lifecycle or owner data.", "", "## Canonical Portfolio Truth Table", "", - "| Project | Path | Group | Operating Path | Path Status | Lifecycle | Registry Status | Context | Tool | Category | Risk |", - "|---------|------|-------|----------------|-------------|-----------|-----------------|---------|------|----------|------|", + "| Project | Path | Group | Operating Path | Path Status | Lifecycle | Registry Status | Attention State | Context | Tool | Category | Risk |", + "|---------|------|-------|----------------|-------------|-----------|-----------------|-----------------|---------|------|----------|------|", ] for project in snapshot.projects: path_status = project.derived.path_confidence @@ -156,7 +158,8 @@ def render_portfolio_report_markdown( f"| {project.identity.display_name} | `{project.identity.path}` | {project.identity.section_marker} | " f"{project.declared.operating_path or '—'} | {path_status} | " f"{project.declared.lifecycle_state or '—'} | {project.derived.registry_status} | " - f"{project.derived.context_quality} | {project.declared.tool_provenance or 'unknown'} | {project.declared.category or 'unknown'} | {project.risk.risk_tier} |" + f"{project.derived.attention_state} | {project.derived.context_quality} | " + f"{project.declared.tool_provenance or 'unknown'} | {project.declared.category or 'unknown'} | {project.risk.risk_tier} |" ) lines.extend( @@ -166,6 +169,7 @@ def render_portfolio_report_markdown( "", f"- Context coverage: full `{context_counts.get('full', 0)}`, standard `{context_counts.get('standard', 0)}`, minimum-viable `{context_counts.get('minimum-viable', 0)}`, boilerplate `{context_counts.get('boilerplate', 0)}`, none `{context_counts.get('none', 0)}`", f"- Registry status distribution: active `{registry_counts.get('active', 0)}`, recent `{registry_counts.get('recent', 0)}`, parked `{registry_counts.get('parked', 0)}`, archived `{registry_counts.get('archived', 0)}`", + f"- Default attention distribution: active-product `{attention_counts.get('active-product', 0)}`, active-infra `{attention_counts.get('active-infra', 0)}`, decision-needed `{attention_counts.get('decision-needed', 0)}`, manual-only `{attention_counts.get('manual-only', 0)}`, experiment `{attention_counts.get('experiment', 0)}`, parked `{attention_counts.get('parked', 0)}`, archived `{attention_counts.get('archived', 0)}`", f"- Operating path distribution: maintain `{operating_path_counts.get('maintain', 0)}`, finish `{operating_path_counts.get('finish', 0)}`, archive `{operating_path_counts.get('archive', 0)}`, experiment `{operating_path_counts.get('experiment', 0)}`, unspecified `{operating_path_counts.get('unspecified', 0)}`", f"- Investigate overrides currently surfaced: `{override_counts.get('investigate', 0)}`", f"- Risk posture: elevated `{risk_tier_counts.get('elevated', 0)}`, moderate `{risk_tier_counts.get('moderate', 0)}`, baseline `{risk_tier_counts.get('baseline', 0)}`, deferred `{risk_tier_counts.get('deferred', 0)}`", @@ -185,6 +189,12 @@ def render_portfolio_report_markdown( f" | Parked `{sum(1 for item in projects if item.derived.registry_status == 'parked')}`" f" | Archived `{sum(1 for item in projects if item.derived.registry_status == 'archived')}`" ) + lines.append( + f"- Default attention: active-product `{sum(1 for item in projects if item.derived.attention_state == 'active-product')}`, " + f"active-infra `{sum(1 for item in projects if item.derived.attention_state == 'active-infra')}`, " + f"decision-needed `{sum(1 for item in projects if item.derived.attention_state == 'decision-needed')}`, " + f"non-default `{sum(1 for item in projects if item.derived.attention_state not in {'active-product', 'active-infra', 'decision-needed'})}`" + ) lines.append( f"- Context: full `{sum(1 for item in projects if item.derived.context_quality == 'full')}`, " f"standard `{sum(1 for item in projects if item.derived.context_quality == 'standard')}`, " diff --git a/src/portfolio_truth_types.py b/src/portfolio_truth_types.py index 1610513..3bfa1ad 100644 --- a/src/portfolio_truth_types.py +++ b/src/portfolio_truth_types.py @@ -6,7 +6,7 @@ from pathlib import Path from typing import Any -SCHEMA_VERSION = "0.5.0" +SCHEMA_VERSION = "0.6.0" # The published "latest" portfolio-truth artifact. The producer # (portfolio_truth_publish) writes it; every reader resolves it through @@ -22,6 +22,16 @@ def truth_latest_path(output_dir: Path) -> Path: VALID_CONTEXT_QUALITY = {"full", "standard", "minimum-viable", "boilerplate", "none"} VALID_ACTIVITY_STATUS = {"active", "recent", "stale", "archived"} VALID_REGISTRY_STATUS = {"active", "recent", "parked", "archived"} +VALID_ATTENTION_STATES = { + "active-product", + "active-infra", + "decision-needed", + "parked", + "archived", + "experiment", + "evidence-history", + "manual-only", +} VALID_LIFECYCLE_STATES = {"active", "maintenance", "dormant", "experimental", "archived"} VALID_CATEGORY_TAGS = { "commercial", @@ -105,6 +115,7 @@ class DerivedFields: last_meaningful_activity_at: datetime | None = None activity_status: str = "stale" registry_status: str = "parked" + attention_state: str = "parked" path_override: str = "" path_confidence: str = "legacy" path_rationale: str = "" diff --git a/src/portfolio_truth_validate.py b/src/portfolio_truth_validate.py index fbd1943..7747a87 100644 --- a/src/portfolio_truth_validate.py +++ b/src/portfolio_truth_validate.py @@ -12,6 +12,7 @@ from src.portfolio_truth_types import ( SCHEMA_VERSION, VALID_ACTIVITY_STATUS, + VALID_ATTENTION_STATES, VALID_CONTEXT_QUALITY, VALID_DOCTOR_STANDARDS, VALID_LIFECYCLE_STATES, @@ -49,6 +50,10 @@ def validate_truth_snapshot(snapshot: PortfolioTruthSnapshot) -> None: raise ValueError( f"Invalid registry status for {key}: {project.derived.registry_status}" ) + if project.derived.attention_state not in VALID_ATTENTION_STATES: + raise ValueError( + f"Invalid attention state for {key}: {project.derived.attention_state}" + ) completeness_flags = ( project.derived.project_summary_present, project.derived.current_state_present, diff --git a/src/weekly_command_center.py b/src/weekly_command_center.py index c08c7ec..d9f481b 100644 --- a/src/weekly_command_center.py +++ b/src/weekly_command_center.py @@ -193,7 +193,7 @@ def render_weekly_command_center_markdown(digest: dict[str, Any]) -> str: f"- Next Step: {_safe_text(digest.get('next_step'))}", f"- Decision Quality: `{_safe_text(decision_quality.get('status'))}` — {_safe_text(decision_quality.get('summary'))}", f"- Operating Paths: {_safe_text(digest.get('operating_paths_summary')) or 'No operating-path summary is recorded yet.'}", - f"- Portfolio Truth: {portfolio_truth.get('project_count', 0)} projects, {portfolio_truth.get('active_project_count', 0)} active, {portfolio_truth.get('investigate_override_count', 0)} with investigate override, {portfolio_truth.get('low_confidence_path_count', 0)} low-confidence paths", + f"- Portfolio Truth: {portfolio_truth.get('project_count', 0)} projects, {portfolio_truth.get('active_project_count', 0)} active registry entries, {portfolio_truth.get('default_attention_count', 0)} default attention, {portfolio_truth.get('decision_needed_count', 0)} decision-needed", f"- Risk Posture: {risk_posture.get('elevated_count', 0)} elevated, {tier_counts.get('moderate', 0)} moderate, {tier_counts.get('baseline', 0)} baseline", f"- Security Posture: {security_posture.get('scanned_count', 0)} scanned, {security_posture.get('repos_with_open_high_critical', 0)} with open high/critical Dependabot alerts ({security_posture.get('total_open_critical', 0)} critical, {security_posture.get('total_open_high', 0)} high)", "", @@ -206,7 +206,7 @@ def render_weekly_command_center_markdown(digest: dict[str, Any]) -> str: else: for item in path_attention: lines.append( - f"- {item['repo']} — {item['headline']} ({item['registry_status']}, {item['context_quality']} context)" + f"- {item['repo']} — {item['headline']} ({item['attention_state']}, {item['registry_status']} registry, {item['context_quality']} context)" ) lines.extend(["", "## Automation Candidates"]) @@ -285,6 +285,7 @@ def _build_truth_summary(portfolio_truth: dict[str, Any]) -> dict[str, Any]: path_counts: dict[str, int] = {} override_counts: dict[str, int] = {} risk_tier_counts: dict[str, int] = {} + attention_state_counts: dict[str, int] = {} active_project_count = 0 low_confidence_path_count = 0 @@ -298,6 +299,8 @@ def _build_truth_summary(portfolio_truth: dict[str, Any]) -> dict[str, Any]: path_counts[operating_path] = path_counts.get(operating_path, 0) + 1 override = _safe_text(derived.get("path_override")) or "none" override_counts[override] = override_counts.get(override, 0) + 1 + attention_state = _safe_text(derived.get("attention_state")) or "manual-only" + attention_state_counts[attention_state] = attention_state_counts.get(attention_state, 0) + 1 tier = _safe_text(risk.get("risk_tier")) or "baseline" risk_tier_counts[tier] = risk_tier_counts.get(tier, 0) + 1 if _safe_text(derived.get("registry_status")) == "active": @@ -311,8 +314,14 @@ def _build_truth_summary(portfolio_truth: dict[str, Any]) -> dict[str, Any]: "context_quality_counts": context_counts, "operating_path_counts": path_counts, "path_override_counts": override_counts, + "attention_state_counts": attention_state_counts, "risk_tier_counts": risk_tier_counts, "elevated_risk_count": risk_tier_counts.get("elevated", 0), + "default_attention_count": sum( + attention_state_counts.get(state, 0) + for state in ("active-product", "active-infra", "decision-needed") + ), + "decision_needed_count": attention_state_counts.get("decision-needed", 0), "low_confidence_path_count": low_confidence_path_count, "investigate_override_count": override_counts.get("investigate", 0), } @@ -321,7 +330,7 @@ def _build_truth_summary(portfolio_truth: dict[str, Any]) -> dict[str, Any]: def _build_path_attention_items(portfolio_truth: dict[str, Any]) -> list[dict[str, Any]]: projects = list(portfolio_truth.get("projects") or []) candidates: list[dict[str, Any]] = [] - status_rank = {"active": 0, "candidate": 1, "parked": 2, "archived": 3} + status_rank = {"decision-needed": 0, "active-product": 1, "active-infra": 2} context_rank = {"none": 0, "boilerplate": 1, "minimum-viable": 2, "standard": 3, "full": 4} for project in projects: @@ -329,7 +338,8 @@ def _build_path_attention_items(portfolio_truth: dict[str, Any]) -> list[dict[st declared = _mapping(project.get("declared")) derived = _mapping(project.get("derived")) registry_status = _safe_text(derived.get("registry_status")) - if registry_status not in {"active", "candidate"}: + attention_state = _safe_text(derived.get("attention_state")) + if attention_state != "decision-needed": continue operating_path = _safe_text(declared.get("operating_path")) override = _safe_text(derived.get("path_override")) @@ -348,6 +358,7 @@ def _build_path_attention_items(portfolio_truth: dict[str, Any]) -> list[dict[st { "repo": _safe_text(identity.get("display_name")) or "Repo", "headline": headline, + "attention_state": attention_state, "registry_status": registry_status or "unknown", "context_quality": context_quality, "path_confidence": _safe_text(derived.get("path_confidence")) or "legacy", @@ -359,7 +370,7 @@ def _build_path_attention_items(portfolio_truth: dict[str, Any]) -> list[dict[st candidates.sort( key=lambda item: ( - status_rank.get(item["registry_status"], 9), + status_rank.get(item["attention_state"], 9), 0 if item["operating_path"] == "unspecified" else 1, 0 if item["path_confidence"] == "low" else 1, context_rank.get(item["context_quality"], 9), diff --git a/tests/test_portfolio_truth.py b/tests/test_portfolio_truth.py index 407dabc..c74cf8b 100644 --- a/tests/test_portfolio_truth.py +++ b/tests/test_portfolio_truth.py @@ -229,6 +229,7 @@ def test_truth_snapshot_respects_declared_and_derived_fields( assert alpha.declared.category == "commercial" assert alpha.derived.context_quality == "full" assert alpha.derived.registry_status == "active" + assert alpha.derived.attention_state == "active-product" assert alpha.derived.primary_context_file == "CLAUDE.md" assert alpha.derived.project_summary_present is True assert alpha.derived.next_recommended_move_present is True @@ -242,11 +243,91 @@ def test_truth_snapshot_respects_declared_and_derived_fields( assert beta.declared.category == "it-work" assert beta.derived.context_quality == "boilerplate" assert beta.derived.registry_status == "parked" + assert beta.derived.attention_state == "parked" assert gamma.identity.section_marker == "iOS Projects" assert gamma.derived.stack == ["Swift"] - assert result.snapshot.schema_version == "0.5.0" + assert result.snapshot.schema_version == "0.6.0" + assert result.snapshot.source_summary["attention_state_counts"]["active-product"] == 1 + assert result.snapshot.source_summary["attention_state_counts"]["parked"] == 1 + + +def test_attention_state_classifier_separates_activity_from_operator_attention() -> None: + from src.portfolio_truth_reconcile import _attention_state_for + + assert ( + _attention_state_for( + registry_status="active", + lifecycle_state="active", + operating_path="maintain", + intended_disposition="maintain", + category="commercial", + path_override="", + risk_entry={"security_risk": False}, + ) + == "active-product" + ) + assert ( + _attention_state_for( + registry_status="active", + lifecycle_state="active", + operating_path="maintain", + intended_disposition="maintain", + category="infrastructure", + path_override="", + risk_entry={"security_risk": False}, + ) + == "active-infra" + ) + assert ( + _attention_state_for( + registry_status="active", + lifecycle_state="active", + operating_path="maintain", + intended_disposition="maintain", + category="vanity", + path_override="investigate", + risk_entry={"security_risk": False}, + ) + == "decision-needed" + ) + assert ( + _attention_state_for( + registry_status="active", + lifecycle_state="active", + operating_path="maintain", + intended_disposition="maintain", + category="fun", + path_override="", + risk_entry={"security_risk": False}, + ) + == "manual-only" + ) + assert ( + _attention_state_for( + registry_status="active", + lifecycle_state="active", + operating_path="experiment", + intended_disposition="experiment", + category="vanity", + path_override="investigate", + risk_entry={"security_risk": True}, + ) + == "experiment" + ) + assert ( + _attention_state_for( + registry_status="archived", + lifecycle_state="archived", + operating_path="archive", + intended_disposition="archive", + category="commercial", + path_override="investigate", + risk_entry={"security_risk": True}, + ) + == "archived" + ) def test_build_security_fields_maps_ghas_entry() -> None: diff --git a/tests/test_weekly_command_center.py b/tests/test_weekly_command_center.py index fe30078..8386e00 100644 --- a/tests/test_weekly_command_center.py +++ b/tests/test_weekly_command_center.py @@ -14,6 +14,7 @@ def _make_portfolio_truth() -> dict: "declared": {"operating_path": "maintain"}, "derived": { "registry_status": "active", + "attention_state": "decision-needed", "activity_status": "active", "path_override": "investigate", "path_confidence": "low", @@ -34,6 +35,7 @@ def _make_portfolio_truth() -> dict: "declared": {"operating_path": ""}, "derived": { "registry_status": "active", + "attention_state": "decision-needed", "activity_status": "active", "path_override": "investigate", "path_confidence": "low", @@ -49,11 +51,33 @@ def _make_portfolio_truth() -> dict: "path_risk": True, }, }, + { + "identity": {"display_name": "QuietActive"}, + "declared": {"operating_path": "maintain"}, + "derived": { + "registry_status": "active", + "attention_state": "manual-only", + "activity_status": "active", + "path_override": "", + "path_confidence": "high", + "context_quality": "standard", + "path_rationale": "Active registry entry, but not default operator attention.", + }, + "risk": { + "risk_tier": "baseline", + "risk_factors": [], + "risk_summary": "No current attention decision.", + "doctor_gap": False, + "context_risk": False, + "path_risk": False, + }, + }, { "identity": {"display_name": "ArchiveMe"}, "declared": {"operating_path": "archive"}, "derived": { "registry_status": "archived", + "attention_state": "archived", "activity_status": "stale", "path_override": "", "path_confidence": "high", @@ -116,15 +140,22 @@ def test_build_weekly_command_center_digest_surfaces_truth_and_guardrails() -> N assert digest["contract_version"] == "weekly_command_center_digest_v1" assert digest["authority_cap"] == "bounded-automation" assert digest["decision_quality"]["status"] == "needs-skepticism" - assert digest["portfolio_truth"]["project_count"] == 3 + assert digest["portfolio_truth"]["project_count"] == 4 + assert digest["portfolio_truth"]["active_project_count"] == 3 + assert digest["portfolio_truth"]["default_attention_count"] == 2 + assert digest["portfolio_truth"]["decision_needed_count"] == 2 assert digest["portfolio_truth"]["investigate_override_count"] == 2 + assert digest["portfolio_truth"]["attention_state_counts"]["manual-only"] == 1 assert digest["path_attention"][0]["repo"] == "JobCommandCenter" assert digest["path_attention"][0]["headline"] == "Unspecified stable path" + assert all(item["attention_state"] == "decision-needed" for item in digest["path_attention"]) + assert "QuietActive" not in {item["repo"] for item in digest["path_attention"]} assert digest["report_only_guardrail"].startswith("This digest is descriptive only.") # Risk posture assertions assert digest["risk_posture"]["elevated_count"] == 2 assert digest["portfolio_truth"]["risk_tier_counts"]["elevated"] == 2 + assert digest["portfolio_truth"]["risk_tier_counts"]["baseline"] == 1 assert digest["portfolio_truth"]["risk_tier_counts"]["deferred"] == 1 rendered_md = render_weekly_command_center_markdown(digest) From e1af93e518f7bc5717e0096df80ed27712d76599 Mon Sep 17 00:00:00 2001 From: saagpatel Date: Sun, 7 Jun 2026 22:05:48 -0700 Subject: [PATCH 3/3] docs(demo): add public fixture proof package --- CASE-STUDY.md | 129 +++ DEMO-PLAN.md | 122 +++ README.md | 15 +- docs/demo-proof/public-fixture/README.md | 51 ++ .../public-fixture/RECORDING-CHECKLIST.md | 32 + docs/demo-proof/public-fixture/SUMMARY.md | 18 + .../public-fixture/proof-package.json | 227 +++++ docs/product/operator-os-product-brief.md | 97 ++ .../dashboard-sample-user-2026-04-12.html | 864 ++++++++++++++++++ output/demo/demo-report.json | 557 +++++++++++ output/demo/demo-workbook.xlsx | Bin 0 -> 144109 bytes output/demo/operator-control-center-demo.json | 134 +++ output/demo/operator-control-center-demo.md | 43 + output/demo/pending-proposals.json | 4 + .../portfolio-truth-2026-04-05T120000Z.json | 245 +++++ .../portfolio-truth-2026-04-12T120000Z.json | 245 +++++ output/demo/portfolio-truth-latest.json | 245 +++++ output/demo/portfolio-warehouse.db | Bin 0 -> 385024 bytes ...urity-burndown-sample-user-2026-04-12.json | 30 + ...command-center-sample-user-2026-04-12.json | 69 ++ scripts/build_demo_artifacts.py | 299 +++++- 21 files changed, 3406 insertions(+), 20 deletions(-) create mode 100644 CASE-STUDY.md create mode 100644 DEMO-PLAN.md create mode 100644 docs/demo-proof/public-fixture/README.md create mode 100644 docs/demo-proof/public-fixture/RECORDING-CHECKLIST.md create mode 100644 docs/demo-proof/public-fixture/SUMMARY.md create mode 100644 docs/demo-proof/public-fixture/proof-package.json create mode 100644 docs/product/operator-os-product-brief.md create mode 100644 output/demo/dashboard-sample-user-2026-04-12.html create mode 100644 output/demo/demo-report.json create mode 100644 output/demo/demo-workbook.xlsx create mode 100644 output/demo/operator-control-center-demo.json create mode 100644 output/demo/operator-control-center-demo.md create mode 100644 output/demo/pending-proposals.json create mode 100644 output/demo/portfolio-truth-2026-04-05T120000Z.json create mode 100644 output/demo/portfolio-truth-2026-04-12T120000Z.json create mode 100644 output/demo/portfolio-truth-latest.json create mode 100644 output/demo/portfolio-warehouse.db create mode 100644 output/demo/security-burndown-sample-user-2026-04-12.json create mode 100644 output/demo/weekly-command-center-sample-user-2026-04-12.json diff --git a/CASE-STUDY.md b/CASE-STUDY.md new file mode 100644 index 0000000..631195f --- /dev/null +++ b/CASE-STUDY.md @@ -0,0 +1,129 @@ +# Operator OS: A Multi-Agent Control Plane Over A Software Portfolio + +Operator OS is a local-first control plane for AI-assisted builders: it turns a sprawling repo portfolio and multiple coding agents into verified truth, visible risk, and one operator-approved next move. + +GitHub Repo Auditor is the truth engine behind the first public wedge. It began as a repository auditor, but the stronger product shape is a portfolio operating layer: one system that can say which projects are healthy, which are drifting, which are blocked, what changed, and what deserves attention next. + +## Who This Is For + +- Solo builders with dozens of repos and not enough trust in their own backlog. +- Staff engineers and technical leads who need decision-grade visibility across experimental, internal, and production projects. +- AI-native developers using Codex, Claude Code, ChatGPT, or similar tools across many workstreams. +- Devtools teams studying how agent-created work should be verified, prioritized, and governed. + +## The Problem + +AI coding tools make it easier to start and modify projects. They do not automatically make it easier to know what is true afterward. + +Once a portfolio has enough projects and enough agent-touched work, normal tools flatten the wrong things: + +- `git log` shows activity, not whether the work matters. +- GitHub alerts show risk, not which fix clears the most portfolio pain. +- Notes and handoffs preserve intent, but can drift from the current repo state. +- Agent transcripts are useful history, but they are not proof. +- Dashboards can look polished while hiding stale or private source data. + +Operator OS starts from a stricter premise: local evidence wins. Every product surface should be traceable back to files, commands, generated artifacts, or explicit operator approval. + +## Before And After + +| Before | After | +| --- | --- | +| A long list of repos | A portfolio truth snapshot with risk, readiness, context quality, and security posture | +| Agent work scattered across chats | Agent provenance and follow-through visible in operator surfaces | +| Weekly review rebuilt from memory | Weekly command-center artifacts generated from current audit facts | +| Security alerts handled repo by repo | Advisory-grouped burndown showing the dependency bump that clears risk across repos | +| Handoffs as stale prose | Restart-safe handoffs that say what was checked, what must be rechecked, and what not to touch | +| Automation as blind trust | Dry-run-first proposals, explicit approvals, and evidence-backed execution gates | + +## System Shape + +```mermaid +flowchart LR + A["Local repos"] --> B["GitHub Repo Auditor"] + B --> C["Portfolio truth JSON"] + B --> D["Workbook / HTML / Markdown outputs"] + C --> E["Portfolio Command Center"] + D --> E + E --> F["Operator decision"] + F --> G["Manual or gated follow-through"] +``` + +The public wedge keeps this system deliberately narrow: + +- `GithubRepoAuditor` produces portfolio truth and weekly/operator artifacts. +- `PortfolioCommandCenter` reads those artifacts and presents the operating view. +- Fixture or sanitized data drives the public demo. +- Private systems remain private implementation references, not public data sources. + +The broader local machine adds other surfaces in private use: + +- `bridge-db` for compact cross-agent receipts and state coordination. +- `personal-ops` for private inbox, planning, approvals, and local operator workflows. +- `notification-hub` for local event routing, review queues, and noise control. +- `SecondBrain` for private synthesized knowledge and source-grounded lessons. +- Codex and ChatGPT Pro workflow docs for advisory-only model review. + +Those adjacent systems are useful because they prove the operating model under real pressure. They are not required for the public demo. + +## What The Demo Shows + +The public-safe demo should show the Portfolio Command Center running over fixture or sanitized portfolio truth: + +1. A full portfolio table with risk, status, context quality, tool provenance, and security columns. +2. A risk/security tab that turns raw alert counts into portfolio-level attention. +3. A burndown tab that groups advisories by the fix that clears the most risk. +4. Trend charts that show whether risk is improving or getting worse. +5. A weekly digest that gives one headline, one decision, and one next move. + +The private local proof package for the 2026-06-07 five-tab demo lives under `docs/demo-proof/2026-06-07/`. It proves the live local demo, but it is not the public publishing package because it may reveal real local portfolio details. + +For public sharing, use the fixture-backed package under `docs/demo-proof/public-fixture/`. + +## What Stays Private + +The product should not expose raw local operating state. These surfaces are private by design: + +- Local Codex sessions, memories, reports, hooks, secrets, config, and SQLite state. +- Gmail, Calendar, Drive, task, approval, and daemon state from `personal-ops`. +- Raw SecondBrain captures, conversation exports, vault history, and private notes. +- Real Notion databases, project rows, tokens, API traces, and live write receipts. +- `bridge-db` live SQLite contents, handoffs, snapshots, receipts, recall logs, and activity rows. +- `notification-hub` events, Slack routing, local queue state, and review logs. +- Private repo names, local absolute paths, branch state, and security findings unless they are intentionally sanitized. + +The productizable asset is the pattern: local truth, bounded context, visible provenance, approval gates, and operator-facing decisions. + +## Why It Is Hard To Copy + +The moat is not a chart. Charts are easy. + +The hard part is the lived-in operating discipline: + +- One canonical truth contract feeding multiple views. +- Generated artifacts that agree with each other instead of becoming separate stories. +- Dry-run-first action flows that preserve human approval. +- Explicit stale-state handling instead of cheerful lies. +- Agent role boundaries: advisory models advise; local agents verify and execute. +- Restart-safe handoffs that force the next session back to current evidence. +- Private-by-default local operation with public-safe fixture demos. + +Most products start with a dashboard and bolt trust on later. Operator OS starts with trust and lets the dashboard expose it. + +## Public Wedge + +The first wedge is Portfolio Command Center: + +- simple enough to demo in 90 seconds; +- grounded in concrete repo facts; +- visually understandable to developers immediately; +- impressive without needing private email, calendar, Notion, or agent transcripts; +- extensible into the broader Operator OS story. + +## Demo Links + +- [90-second demo plan](DEMO-PLAN.md) +- [Fixture demo source](fixtures/demo/sample-report.json) +- [Public fixture proof package](docs/demo-proof/public-fixture/README.md) +- [Private local demo proof package](docs/demo-proof/2026-06-07/README.md) +- [Portfolio Command Center](../PortfolioCommandCenter/README.md) diff --git a/DEMO-PLAN.md b/DEMO-PLAN.md new file mode 100644 index 0000000..31b776a --- /dev/null +++ b/DEMO-PLAN.md @@ -0,0 +1,122 @@ +# Portfolio Command Center Demo Plan + +This is the public-safe demo plan for the Operator OS wedge. + +The demo should prove one thing quickly: a serious builder can turn repo sprawl and agent-touched work into verified truth, visible risk, and one next move. + +## Demo Thesis + +Git history tells you what changed. Portfolio Command Center tells you what the change means. + +## Demo Modes + +Use one of two modes: + +| Mode | Use for | Data source | Public-safe | +| --- | --- | --- | --- | +| Fixture mode | Public recording, docs, external sharing | `fixtures/demo/sample-report.json` via `make demo` | Yes | +| Live local mode | Private operator proof and internal review | `output/portfolio-truth-latest.json` from the real local portfolio | No, unless redacted | + +Default to fixture mode for anything public. + +## Fixture Demo Setup + +From this repo: + +```sh +make demo +``` + +Expected outputs: + +- `output/demo/demo-report.json` +- `output/demo/demo-workbook.xlsx` +- `output/demo/dashboard-*.html` +- `output/demo/operator-control-center-demo.json` +- `output/demo/operator-control-center-demo.md` +- `output/demo/portfolio-truth-latest.json` +- `output/demo/portfolio-warehouse.db` + +Then launch the desktop shell from the sibling app: + +```sh +cd ../PortfolioCommandCenter +pnpm install +pnpm demo:desktop +``` + +In the app header, set the output directory to: + +```text +../GithubRepoAuditor/output/demo +``` + +If the recording needs live-shaped data, create a sanitized output directory first. Do not point a public recording at the private live `output/` directory. + +## 90-Second Arc + +| Time | Frame | Spoken line | +| --- | --- | --- | +| 0:00-0:10 | Portfolio table | "This is the problem AI builders are about to have: not one repo, but a portfolio of agent-touched work." | +| 0:10-0:25 | Risk/context/status columns | "A commit timestamp is not enough. I need to know which projects are healthy, blocked, risky, stale, or worth ignoring." | +| 0:25-0:42 | Risk + Security | "The control plane turns raw alerts and project facts into an attention map, so risk stops hiding in individual repos." | +| 0:42-0:58 | Burndown | "The useful question is not just 'what is broken?' It is 'which fix clears the most portfolio pain?'" | +| 0:58-1:12 | Trends | "Because it keeps history, I can tell whether the portfolio is improving or just getting noisier." | +| 1:12-1:25 | Weekly Digest | "Every week, the system reduces the mess to one headline, one decision, and one next move." | +| 1:25-1:30 | Return to Portfolio | "That is Operator OS: verified truth for builders using agents at portfolio scale." | + +## Must-Land Product Points + +- The app is reading generated artifacts, not a hand-maintained spreadsheet. +- Portfolio truth, weekly digest, burndown, and charts come from the same evidence chain. +- The operator remains in charge. +- Public demo data is fixture-backed or sanitized. +- Private local systems are implementation references, not public data sources. + +## Do Not Show Publicly + +- Real private repo names. +- Local absolute paths under the user's home directory. +- Real GitHub security alert details. +- Notion database rows or page IDs. +- Gmail, Calendar, Drive, Slack, or task data. +- Codex sessions, memories, hook logs, or SQLite databases. +- SecondBrain raw captures or conversation exports. +- Tokens, cookies, env values, terminal scrollback, hostnames, or account settings. + +## Redaction Checklist + +Before publishing: + +- [ ] Confirm the app is using `output/demo` or another sanitized output directory. +- [ ] Confirm no private repo names are readable. +- [ ] Confirm no terminal panes or local paths are visible. +- [ ] Confirm no account names, tokens, hostnames, or private URLs are visible. +- [ ] Confirm screenshots and video frames do not expose Notion, email, calendar, Slack, or SecondBrain. +- [ ] Confirm any local live proof package is described as private/local evidence only. + +## Verification Checklist + +Run: + +```sh +make demo +python scripts/validate_proof_package.py docs/demo-proof/public-fixture/proof-package.json +``` + +For the desktop shell: + +```sh +cd ../PortfolioCommandCenter +pnpm typecheck +pnpm test +pnpm build +``` + +Visual verification is complete only after the app is opened against the fixture output and the Portfolio, Risk + Security, Burndown, Trends, and Weekly Digest tabs all render without private data. + +## Final Public Framing + +Use this closing sentence: + +> Operator OS is the missing control plane for AI-assisted builders: it turns scattered agent work and repo sprawl into verified truth, visible risk, and one operator-approved next move. diff --git a/README.md b/README.md index 2b15d3f..573e257 100644 --- a/README.md +++ b/README.md @@ -109,6 +109,10 @@ Treat campaign/writeback, GitHub Projects, Notion sync, catalog overrides, score - Safe demo path: run `make demo` after a local clone to generate sample artifacts from the committed fixture without a GitHub token. - Demo fixture: [fixtures/demo/sample-report.json](fixtures/demo/sample-report.json) +- Operator OS case study: [CASE-STUDY.md](CASE-STUDY.md) +- Public-safe recording plan: [DEMO-PLAN.md](DEMO-PLAN.md) +- Product brief: [docs/product/operator-os-product-brief.md](docs/product/operator-os-product-brief.md) +- Public fixture proof package: [docs/demo-proof/public-fixture/README.md](docs/demo-proof/public-fixture/README.md) - Product modes: [docs/modes.md](docs/modes.md) - Web UI operator guide: [docs/audit-serve.md](docs/audit-serve.md) - CLI migration (flat → subcommand): [docs/audit-cli-migration.md](docs/audit-cli-migration.md) @@ -192,6 +196,8 @@ pip install "github-repo-auditor[serve]" ### Try the safe demo The demo uses committed fixture data and writes only to `output/demo/`. +Use this path for public recordings and screenshots. The live local portfolio +output is private operator evidence unless it has been intentionally sanitized. ```bash git clone https://github.com/saagpatel/GithubRepoAuditor.git @@ -204,8 +210,10 @@ Expected outputs include `output/demo/demo-report.json`, `output/demo/demo-workbook.xlsx`, `output/demo/dashboard-*.html`, `output/demo/operator-control-center-demo.json`, `output/demo/operator-control-center-demo.md`, -`output/demo/portfolio-truth-latest.json`, and -`output/demo/portfolio-warehouse.db`. +`output/demo/portfolio-truth-latest.json`, +`output/demo/weekly-command-center-sample-user-2026-04-12.json`, +`output/demo/security-burndown-sample-user-2026-04-12.json`, +`output/demo/pending-proposals.json`, and `output/demo/portfolio-warehouse.db`. To browse the same fixture in the local web UI: @@ -214,6 +222,9 @@ pip install -e ".[serve]" audit serve --output-dir output/demo ``` +To record the Portfolio Command Center wedge from the same fixture, follow +[DEMO-PLAN.md](DEMO-PLAN.md) and point the desktop app at `output/demo/`. + ### Quick start (subcommand form) ```bash diff --git a/docs/demo-proof/public-fixture/README.md b/docs/demo-proof/public-fixture/README.md new file mode 100644 index 0000000..ac3fec0 --- /dev/null +++ b/docs/demo-proof/public-fixture/README.md @@ -0,0 +1,51 @@ +# Public Fixture Demo Proof + +This proof package covers the public-safe Portfolio Command Center demo path. + +Unlike the private local proof package in `../2026-06-07/`, this package is +designed for external sharing. It uses committed fixture data and generated demo +artifacts under `output/demo/`, so it does not require private repo state, +tokens, Notion, bridge-db, personal-ops, SecondBrain, or notification-hub. + +## Generate The Evidence + +From the GitHub Repo Auditor repo: + +```sh +make demo +python scripts/validate_proof_package.py docs/demo-proof/public-fixture/proof-package.json +``` + +Expected generated artifacts: + +- `output/demo/demo-report.json` +- `output/demo/demo-workbook.xlsx` +- `output/demo/dashboard-sample-user-2026-04-12.html` +- `output/demo/operator-control-center-demo.json` +- `output/demo/operator-control-center-demo.md` +- `output/demo/portfolio-truth-latest.json` +- `output/demo/weekly-command-center-sample-user-2026-04-12.json` +- `output/demo/security-burndown-sample-user-2026-04-12.json` +- `output/demo/pending-proposals.json` +- `output/demo/portfolio-warehouse.db` + +## Desktop Demo + +From the sibling Portfolio Command Center repo: + +```sh +pnpm install +pnpm demo:desktop +``` + +Then set the output directory in the app header to: + +```text +../GithubRepoAuditor/output/demo +``` + +## Safety Claim + +This package proves the demo can be produced from fixture data. It does not +prove that a recording is visually redacted. A final public recording still +needs a human pass for frame-level privacy review. diff --git a/docs/demo-proof/public-fixture/RECORDING-CHECKLIST.md b/docs/demo-proof/public-fixture/RECORDING-CHECKLIST.md new file mode 100644 index 0000000..eac5cbf --- /dev/null +++ b/docs/demo-proof/public-fixture/RECORDING-CHECKLIST.md @@ -0,0 +1,32 @@ +# Public Fixture Recording Checklist + +Use this checklist for a public-safe Portfolio Command Center recording. + +## Preflight + +- [ ] Run `make demo` from `GithubRepoAuditor`. +- [ ] Run `pnpm demo:desktop` from `PortfolioCommandCenter`. +- [ ] Point Portfolio Command Center at `GithubRepoAuditor/output/demo`. +- [ ] Confirm the visible data is fixture data, not the private live portfolio. +- [ ] Hide terminals, path bars, desktop clutter, account menus, and notification banners. + +## Shot Order + +| Time | Tab | What to show | +| --- | --- | --- | +| 0:00-0:10 | Portfolio | The table and portfolio summary. | +| 0:10-0:25 | Portfolio | Risk, status, context, and tool/provenance columns. | +| 0:25-0:42 | Risk + Security | Portfolio-level risk and security posture. | +| 0:42-0:58 | Burndown | Advisory-grouped fix guidance. | +| 0:58-1:12 | Trends | Risk and alert history. | +| 1:12-1:25 | Weekly Digest | One headline, one decision, one next move. | +| 1:25-1:30 | Portfolio | Close on the Operator OS thesis. | + +## Do Not Publish If Visible + +- private repo names; +- local absolute paths; +- hostnames, usernames, or account menus; +- real security advisory details; +- Notion, email, calendar, Slack, bridge-db, or SecondBrain content; +- terminal scrollback, env vars, tokens, cookies, or config files. diff --git a/docs/demo-proof/public-fixture/SUMMARY.md b/docs/demo-proof/public-fixture/SUMMARY.md new file mode 100644 index 0000000..d39f5b5 --- /dev/null +++ b/docs/demo-proof/public-fixture/SUMMARY.md @@ -0,0 +1,18 @@ +# Public Fixture Demo Summary + +Status: fixture proof package, pending visual capture. + +This package establishes the safe public data path for the Operator OS / +Portfolio Command Center demo: + +- fixture input: `fixtures/demo/sample-report.json`; +- generated artifacts: `output/demo/`, including the PortfolioCommandCenter + `projects` schema, weekly digest, burndown, trend snapshots, and empty + proposal queue; +- desktop consumer: `PortfolioCommandCenter` pointed at `output/demo`; +- private services required: none; +- live writes performed: none. + +The next step before publishing is to capture screenshots or video frames from +Portfolio Command Center while it is pointed at the fixture output directory, +then add those images to this package. diff --git a/docs/demo-proof/public-fixture/proof-package.json b/docs/demo-proof/public-fixture/proof-package.json new file mode 100644 index 0000000..09c60d2 --- /dev/null +++ b/docs/demo-proof/public-fixture/proof-package.json @@ -0,0 +1,227 @@ +{ + "schema_version": "proof-package.v1", + "package_id": "public-fixture-portfolio-command-center-demo", + "subject": { + "repo": "PortfolioCommandCenter", + "lane": "public-fixture-demo", + "claim": "Portfolio Command Center can be demonstrated from fixture-backed GitHub Repo Auditor artifacts without private local operating data." + }, + "producer": { + "repo": "GithubRepoAuditor", + "mode": "fixture", + "commands": [ + "make demo", + "python scripts/validate_proof_package.py docs/demo-proof/public-fixture/proof-package.json", + "pnpm demo:desktop" + ] + }, + "source_state": { + "source_data_mode": "fixture", + "fixture": "../../../fixtures/demo/sample-report.json", + "generated_output_dir": "../../../output/demo", + "source_truth_schema": "demo-pcc-v1", + "freshness_window_hours": null + }, + "claims": [ + { + "id": "fixture-input", + "statement": "The public demo source is a committed fixture file, not the private live portfolio output.", + "status": "passed", + "evidence": [ + "fixture-report" + ] + }, + { + "id": "demo-generation", + "statement": "The fixture demo command generates the JSON, workbook, dashboard, control-center, truth, and warehouse artifacts under output/demo.", + "status": "passed", + "evidence": [ + "demo-make-target", + "demo-build-script", + "demo-report", + "demo-workbook", + "demo-dashboard", + "demo-control-center-json", + "demo-control-center-markdown", + "demo-portfolio-truth", + "demo-weekly-digest", + "demo-security-burndown", + "demo-history-previous", + "demo-history-current", + "demo-proposals", + "demo-warehouse" + ] + }, + { + "id": "desktop-compatible-schema", + "statement": "The generated portfolio truth uses the PortfolioCommandCenter projects schema rather than the older lightweight repos demo shape.", + "status": "passed", + "evidence": [ + "demo-portfolio-truth", + "demo-weekly-digest", + "demo-security-burndown" + ] + }, + { + "id": "public-recording-boundary", + "statement": "The public recording checklist requires fixture output and blocks private local data exposure.", + "status": "passed", + "evidence": [ + "recording-checklist" + ] + }, + { + "id": "visual-capture", + "statement": "Final public screenshots or video frames still need a frame-level privacy review after capture.", + "status": "partial", + "evidence": [ + "summary" + ] + } + ], + "verification": { + "overall": "partial", + "checks": [ + { + "name": "manifest references fixture input and generated output paths", + "status": "passed" + }, + { + "name": "visual capture from Portfolio Command Center", + "status": "partial" + } + ], + "missing_receipts": [], + "known_gaps": [ + "This package proves the data path and recording boundary. It does not include captured public screenshots yet.", + "Portfolio Command Center must be pointed at output/demo during recording." + ] + }, + "safety": { + "redaction": "fixture-only", + "secrets_checked": true, + "live_write_performed": false, + "private_data_required": false + }, + "artifacts": [ + { + "id": "summary", + "kind": "summary", + "path": "SUMMARY.md", + "description": "Human-readable public fixture demo summary.", + "required": true + }, + { + "id": "recording-checklist", + "kind": "checklist", + "path": "RECORDING-CHECKLIST.md", + "description": "Public-safe recording checklist and redaction guard.", + "required": true + }, + { + "id": "fixture-report", + "kind": "fixture", + "path": "../../../fixtures/demo/sample-report.json", + "description": "Committed fixture report used as the public demo source.", + "required": true + }, + { + "id": "demo-make-target", + "kind": "repo-doc", + "path": "../../../Makefile", + "description": "Make target that runs the fixture demo generator.", + "required": true + }, + { + "id": "demo-build-script", + "kind": "script", + "path": "../../../scripts/build_demo_artifacts.py", + "description": "Fixture artifact generator for output/demo.", + "required": true + }, + { + "id": "demo-report", + "kind": "json", + "path": "../../../output/demo/demo-report.json", + "description": "Generated demo report.", + "required": true + }, + { + "id": "demo-workbook", + "kind": "workbook", + "path": "../../../output/demo/demo-workbook.xlsx", + "description": "Generated demo workbook.", + "required": true + }, + { + "id": "demo-dashboard", + "kind": "html", + "path": "../../../output/demo/dashboard-sample-user-2026-04-12.html", + "description": "Generated demo HTML dashboard.", + "required": true + }, + { + "id": "demo-control-center-json", + "kind": "json", + "path": "../../../output/demo/operator-control-center-demo.json", + "description": "Generated demo operator control-center JSON.", + "required": true + }, + { + "id": "demo-control-center-markdown", + "kind": "markdown", + "path": "../../../output/demo/operator-control-center-demo.md", + "description": "Generated demo operator control-center Markdown.", + "required": true + }, + { + "id": "demo-portfolio-truth", + "kind": "json", + "path": "../../../output/demo/portfolio-truth-latest.json", + "description": "Generated demo portfolio truth snapshot.", + "required": true + }, + { + "id": "demo-weekly-digest", + "kind": "json", + "path": "../../../output/demo/weekly-command-center-sample-user-2026-04-12.json", + "description": "Generated demo weekly command-center digest.", + "required": true + }, + { + "id": "demo-security-burndown", + "kind": "json", + "path": "../../../output/demo/security-burndown-sample-user-2026-04-12.json", + "description": "Generated demo security burndown report.", + "required": true + }, + { + "id": "demo-history-previous", + "kind": "json", + "path": "../../../output/demo/portfolio-truth-2026-04-05T120000Z.json", + "description": "Generated previous demo truth snapshot for trends.", + "required": true + }, + { + "id": "demo-history-current", + "kind": "json", + "path": "../../../output/demo/portfolio-truth-2026-04-12T120000Z.json", + "description": "Generated current demo truth snapshot for trends.", + "required": true + }, + { + "id": "demo-proposals", + "kind": "json", + "path": "../../../output/demo/pending-proposals.json", + "description": "Generated empty automation proposal queue.", + "required": true + }, + { + "id": "demo-warehouse", + "kind": "sqlite", + "path": "../../../output/demo/portfolio-warehouse.db", + "description": "Generated demo warehouse snapshot.", + "required": true + } + ] +} diff --git a/docs/product/operator-os-product-brief.md b/docs/product/operator-os-product-brief.md new file mode 100644 index 0000000..b6fad41 --- /dev/null +++ b/docs/product/operator-os-product-brief.md @@ -0,0 +1,97 @@ +# Operator OS Product Brief + +## Strongest Narrative + +Operator OS is a local-first control plane for AI-assisted builders. + +It turns a sprawling repo portfolio and multiple coding agents into verified truth, visible risk, and one operator-approved next move. + +## Product Wedge + +The first public wedge is Portfolio Command Center, a desktop command center over GitHub Repo Auditor's portfolio truth snapshot. + +This wedge is strong because it is concrete: + +- developers understand repo sprawl immediately; +- the data can be fixture-backed for public demos; +- the value is visible in under 90 seconds; +- the trust model can be explained without exposing private personal systems. + +## Target Users + +- AI-native solo builders with many active and abandoned repos. +- Staff engineers coordinating experiments, internal tools, and production-adjacent prototypes. +- Engineering leaders who need a decision-ready view of project risk and readiness. +- Devtools teams exploring human-supervised agent workflows. + +## Jobs To Be Done + +- "Tell me which projects are worth attention this week." +- "Show me where risk is building before it becomes an incident." +- "Help me know whether agent-created work is actually verified." +- "Give me one next move without hiding the evidence." +- "Let me use AI agents without giving them silent authority over real systems." + +## Product Pillars + +1. **Truth before advice** + Generated artifacts and local checks outrank memory, transcripts, and summaries. + +2. **Operator-approved movement** + Risky actions stay dry-run-first, reviewable, and explicitly approved. + +3. **Private by default** + Local operating data stays local. Public demos use fixtures or sanitized data. + +4. **Multi-agent clarity** + Advisory models advise. Local execution agents verify. The operator decides. + +5. **One next move** + The interface should reduce noise into a decision, not produce another dashboard to babysit. + +## What Is Uniquely Hard To Copy + +- A canonical portfolio truth contract feeding JSON, Markdown, workbook, HTML, and desktop surfaces. +- Follow-through state that tracks whether recommendations were attempted, stale, recovering, or retired. +- Explicit stale-state handling and restart-safe handoffs. +- Dry-run-first approval gates across repo, Notion, and workflow surfaces. +- Local/private operation with public-safe proof packages. +- Real usage across Codex, Claude Code, ChatGPT Pro, bridge state, notifications, and personal operations without blurring ownership. + +## Too Private To Productize Directly + +- Personal email, calendar, Drive, task, approval, and daemon state. +- Raw SecondBrain captures and conversation exports. +- Live bridge-db SQLite state, handoffs, recall logs, and shipped-sync receipts. +- Notification logs, Slack routing, and local queue state. +- Notion database rows, page IDs, tokens, and live write receipts. +- Codex sessions, secrets, memories, hook state, and machine-local SQLite databases. +- Real private repo security posture unless explicitly sanitized. + +## Public Demo + +Use fixture-backed Portfolio Command Center: + +1. Generate fixture artifacts with `make demo`. +2. Open Portfolio Command Center against `output/demo`. +3. Show five frames: Portfolio, Risk + Security, Burndown, Trends, Weekly Digest. +4. Close on the Operator OS thesis. + +The public demo should not require GitHub tokens, Notion tokens, bridge-db, personal-ops, SecondBrain, notification-hub, or local private logs. + +## MVP Product Package + +- `CASE-STUDY.md`: the public case study. +- `DEMO-PLAN.md`: the recording and safety plan. +- `docs/demo-proof/public-fixture/`: machine-readable proof package for public demo safety. +- PortfolioCommandCenter README: live mode and public fixture mode clearly separated. +- GitHub Repo Auditor fixture data: repeatable public artifact generation. + +## Future Directions + +- A hosted static fixture demo that never touches local data. +- A sanitized sample portfolio generator. +- A web-first viewer for the same portfolio truth contract. +- A plugin model for organization-specific analyzers. +- An explicit "agent provenance" schema for which agent touched which repo and with what verification. +- A trust dashboard for dry runs, approvals, and follow-through outcomes. diff --git a/output/demo/dashboard-sample-user-2026-04-12.html b/output/demo/dashboard-sample-user-2026-04-12.html new file mode 100644 index 0000000..b46a418 --- /dev/null +++ b/output/demo/dashboard-sample-user-2026-04-12.html @@ -0,0 +1,864 @@ + + + + +Portfolio Dashboard: sample-user + + + + + +
+

Portfolio Dashboard: sample-user

+

Generated 2026-04-12 | 3 repos audited | Grade B

+
+ +
+
Avg Score
0.65
+
Shipped
1
+
Functional
1
+
Needs Work
0
+
+ +
+

Risk Posture

+
+
Elevated
+
2
+
Moderate
+
0
+
Baseline
+
1
+
Deferred
+
0
+
+
  • RepoB: Security follow-through needs operator review.
  • RepoC: Security follow-through needs operator review.
+
+ + +
+

Operator Control Center

+
+
Headline: RepoC still needs security follow-through before the queue will calm down.
+
Run Changes: Average score moved +0.020; 0 meaningful improvements, 0 regressions, 1 promotions, and 1 demotions were recorded.
+
Queue Pressure: 1 blocked, 1 urgent, 1 ready, and 1 deferred item(s) are currently in the queue.
+
Trust / Actionability: verify-first — The recommendation is sound, but recent reopen noise means it should still be reviewed before acting.
+
Top Recommendation: Review RepoC first, then close RepoB's reopened checklist item.
+
Source Run: sample-user:2026-04-12T12:00:00+00:00
+
Next Recommended Run: incremental
+
Watch Strategy: adaptive
+
Watch Decision: The current baseline is still compatible, so incremental watch remains safe for the next run.
+
What Changed: RepoC drift needs review and RepoB reopened a release checklist item.
+
Why It Matters: Live drift is still present, so security work should stay ahead of lower-pressure cleanup.
+
What To Do Next: Review RepoC first, then close RepoB's reopened checklist item.
+
Trend: Queue pressure is stable but still sticky.
+
Accountability: No accountability summary is recorded yet.
+
Follow-Through: One urgent item is still repeating in the recent window.
+
Next Checkpoint: Use the next run or linked artifact to confirm whether the recommendation moved.
+
Escalation: No stronger follow-through escalation is currently surfaced.
+
Recovery / Retirement: No follow-through recovery or escalation-retirement signal is currently surfaced.
+
Recovery Persistence: No follow-through recovery persistence signal is currently surfaced.
+
Relapse Churn: No relapse churn is currently surfaced.
+
Recovery Freshness: No follow-through recovery freshness signal is currently surfaced.
+
Recovery Memory Reset: No follow-through recovery memory reset signal is currently surfaced.
+
Recovery Rebuild Strength: No follow-through recovery rebuild-strength signal is currently surfaced.
+
Recovery Reacquisition: No follow-through recovery reacquisition signal is currently surfaced.
+
Reacquisition Durability: No follow-through reacquisition durability signal is currently surfaced.
+
Reacquisition Confidence: No follow-through reacquisition confidence-consolidation signal is currently surfaced.
+
Reacquisition Softening Decay: No reacquisition softening-decay signal is currently surfaced.
+
Reacquisition Confidence Retirement: No reacquisition confidence-retirement signal is currently surfaced.
+
Revalidation Recovery: No post-revalidation recovery or confidence re-earning signal is currently surfaced.
+
Primary Target: No active target
+
Why This Is The Top Target: RepoC remains the top target because live drift is still open.
+
What Counts As Done: No done-state guidance is recorded yet.
+
Closure Guidance: Clear RepoC's security drift before moving to lower-pressure work.
+
What We Tried: No intervention evidence is recorded yet.
+
Resolution Evidence: No resolution evidence is recorded yet.
+
Primary Target Confidence: low (0.00)
+
Confidence Reasons: No confidence rationale is recorded yet.
+
Next Action Confidence: low (0.00)
+
Trust Policy: verify-first — The recommendation is sound, but recent reopen noise means it should still be reviewed before acting.
+
Why This Confidence Is Actionable: No adaptive confidence summary is recorded yet.
+
Trust Policy Exception: none — No trust-policy exception reason is recorded yet.
+
Exception Pattern Learning: none — No exception-pattern reason is recorded yet.
+
Trust Recovery: none — No trust-recovery reason is recorded yet.
+
Recovery Confidence: low (0.00) — No recovery-confidence summary is recorded yet.
+
Exception Retirement: none — No exception-retirement reason is recorded yet.
+
Policy Debt Cleanup: none — No policy-debt reason is recorded yet.
+
Class-Level Trust Normalization: none — No class-normalization reason is recorded yet.
+
Class Memory Freshness: insufficient-data — No class-memory freshness reason is recorded yet.
+
Trust Decay Controls: none — No class-decay reason is recorded yet.
+
Class Trust Reweighting: neutral (0.00)
+
Why Class Guidance Shifted: No class reweighting rationale is recorded yet.
+
Class Trust Momentum: insufficient-data (0.00)
+
Reweighting Stability: watch — none: No class transition reason is recorded yet.
+
Class Transition Health: none — No class transition health reason is recorded yet.
+
Pending Transition Resolution: none — No class transition resolution reason is recorded yet.
+
Transition Closure Confidence: low (0.00) — none
+
Class Pending Debt Audit: none — No class pending-debt reason is recorded yet.
+
Pending Debt Freshness: insufficient-data — No pending-debt freshness reason is recorded yet.
+
Closure Forecast Reweighting: neutral (0.00)
+
Closure Forecast Momentum: insufficient-data (0.00)
+
Closure Forecast Freshness: insufficient-data — No closure-forecast freshness reason is recorded yet.
+
Closure Forecast Hysteresis: watch — none: No closure-forecast hysteresis reason is recorded yet.
+
Hysteresis Decay Controls: none — No closure-forecast decay reason is recorded yet.
+
Closure Forecast Refresh Recovery: none (0.00)
+
Reacquisition Controls: none — No closure-forecast reacquisition reason is recorded yet.
+
Reacquisition Persistence: none (0.00; 0 run(s))
+
Recovery Churn Controls: none — No recovery-churn reason is recorded yet.
+
Reacquisition Freshness: insufficient-data — No reacquisition-freshness reason is recorded yet.
+
Persistence Reset Controls: none — No persistence-reset reason is recorded yet.
+
Reset Refresh Recovery: none (0.00)
+
Reset Re-entry Controls: none — No reset re-entry reason is recorded yet.
+
Reset Re-entry Persistence: none (0.00; 0 run(s))
+
Reset Re-entry Churn Controls: none — No reset re-entry churn reason is recorded yet.
+
Reset Re-entry Freshness: insufficient-data — No reset re-entry freshness reason is recorded yet.
+
Reset Re-entry Reset Controls: none — No reset re-entry reset reason is recorded yet.
+
Reset Re-entry Refresh Recovery: none (0.00)
+
Reset Re-entry Rebuild Controls: none — No reset re-entry rebuild reason is recorded yet.
+
Reset Re-entry Rebuild Freshness: insufficient-data — No reset re-entry rebuild freshness reason is recorded yet.
+
Reset Re-entry Rebuild Reset Controls: none — No reset re-entry rebuild reset reason is recorded yet.
+
Reset Re-entry Rebuild Refresh Recovery: none (0.00)
+
Reset Re-entry Rebuild Re-entry Controls: none — No reset re-entry rebuild re-entry reason is recorded yet.
+
Reset Re-entry Rebuild Re-Entry Persistence: none (0.00; 0 run(s))
+
Reset Re-entry Rebuild Re-Entry Churn Controls: none — No reset re-entry rebuild re-entry churn reason is recorded yet.
+
Reset Re-entry Rebuild Re-Entry Freshness: insufficient-data — No reset re-entry rebuild re-entry freshness reason is recorded yet.
+
Reset Re-entry Rebuild Re-Entry Reset Controls: none — No reset re-entry rebuild re-entry reset reason is recorded yet.
+
Reset Re-entry Rebuild Re-Entry Refresh Recovery: none — No reset re-entry rebuild re-entry refresh recovery summary is recorded yet.
+
Reset Re-entry Rebuild Re-Entry Restore Controls: none — No reset re-entry rebuild re-entry restore reason is recorded yet.
+
Reset Re-entry Rebuild Re-Entry Restore Freshness: insufficient-data — No reset re-entry rebuild re-entry restore freshness reason is recorded yet.
+
Reset Re-entry Rebuild Re-Entry Restore Reset Controls: none — No reset re-entry rebuild re-entry restore reset reason is recorded yet.
+
Reset Re-entry Rebuild Re-Entry Restore Refresh Recovery: none — No reset re-entry rebuild re-entry restore refresh recovery summary is recorded yet.
+
Reset Re-entry Rebuild Re-Entry Restore Re-Restore Controls: none — No reset re-entry rebuild re-entry restore re-restore reason is recorded yet.
+
Reset Re-entry Rebuild Re-Entry Restore Re-Restore Persistence: none (0.00; 0 run(s))
+
Reset Re-entry Rebuild Re-Entry Restore Re-Restore Churn Controls: none — No reset re-entry rebuild re-entry restore re-restore churn reason is recorded yet.
+
Reset Re-entry Rebuild Re-Entry Restore Re-Restore Freshness: insufficient-data — No reset re-entry rebuild re-entry restore re-restore freshness reason is recorded yet.
+
Reset Re-entry Rebuild Re-Entry Restore Re-Restore Reset Controls: none — No reset re-entry rebuild re-entry restore re-restore reset reason is recorded yet.
+
Reset Re-entry Rebuild Re-Entry Restore Re-Restore Refresh Recovery: none — No reset re-entry rebuild re-entry restore re-restore refresh recovery summary is recorded yet.
+
Reset Re-entry Rebuild Re-Entry Restore Re-Re-Restore Controls: none — No reset re-entry rebuild re-entry restore re-re-restore reason is recorded yet.
+
Reset Re-entry Rebuild Re-Entry Restore Re-Re-Restore Persistence: none (0.00; 0 run(s))
+
Reset Re-entry Rebuild Re-Entry Restore Re-Re-Restore Churn Controls: none — No reset re-entry rebuild re-entry restore re-re-restore churn reason is recorded yet.
+
Reset Re-entry Rebuild Re-Entry Restore Re-Re-Restore Freshness: insufficient-data — No reset re-entry rebuild re-entry restore re-re-restore freshness reason is recorded yet.
+
Reset Re-entry Rebuild Re-Entry Restore Re-Re-Restore Reset Controls: none — No reset re-entry rebuild re-entry restore re-re-restore reset reason is recorded yet.
+
Reset Re-entry Rebuild Re-Entry Restore Re-Re-Restore Refresh Recovery: none — No reset re-entry rebuild re-entry restore re-re-restore refresh recovery summary is recorded yet.
+
Reset Re-entry Rebuild Re-Entry Restore Re-Re-Re-Restore Controls: none — No reset re-entry rebuild re-entry restore re-re-re-restore reason is recorded yet.
+
Reset Re-entry Rebuild Re-Entry Restore Re-Re-Re-Restore Persistence: none (0.00; 0 run(s))
+
Reset Re-entry Rebuild Re-Entry Restore Re-Re-Re-Restore Churn Controls: none — No reset re-entry rebuild re-entry restore re-re-re-restore churn reason is recorded yet.
+
Reset Re-entry Rebuild Persistence: none (0.00; 0 run(s))
+
Reset Re-entry Rebuild Churn Controls: none — No reset re-entry rebuild churn reason is recorded yet.
+
Recommendation Drift: stable — No recommendation-drift summary is recorded yet.
+
Exception Pattern Summary: No exception-pattern summary is recorded yet.
+
Exception Retirement Summary: No exception-retirement summary is recorded yet.
+
Policy Debt Summary: No policy-debt summary is recorded yet.
+
Trust Normalization Summary: No trust-normalization summary is recorded yet.
+
Class Memory Summary: No class-memory summary is recorded yet.
+
Class Decay Summary: No class-decay summary is recorded yet.
+
Class Reweighting Summary: No class reweighting summary is recorded yet.
+
Class Momentum Summary: No class momentum summary is recorded yet.
+
Reweighting Stability Summary: No reweighting stability summary is recorded yet.
+
Class Transition Health Summary: No class transition health summary is recorded yet.
+
Pending Transition Resolution Summary: No class transition resolution summary is recorded yet.
+
Transition Closure Confidence Summary: No transition-closure confidence summary is recorded yet.
+
Class Pending Debt Summary: No class pending-debt summary is recorded yet.
+
Class Pending Resolution Summary: No class pending-resolution summary is recorded yet.
+
Pending Debt Freshness Summary: No pending-debt freshness summary is recorded yet.
+
Pending Debt Decay Summary: No pending-debt decay summary is recorded yet.
+
Closure Forecast Reweighting Summary: No closure-forecast reweighting summary is recorded yet.
+
Closure Forecast Momentum Summary: No closure-forecast momentum summary is recorded yet.
+
Closure Forecast Freshness Summary: No closure-forecast freshness summary is recorded yet.
+
Closure Forecast Stability Summary: No closure-forecast stability summary is recorded yet.
+
Closure Forecast Hysteresis Summary: No closure-forecast hysteresis summary is recorded yet.
+
Closure Forecast Decay Summary: No closure-forecast decay summary is recorded yet.
+
Closure Forecast Refresh Recovery Summary: No closure-forecast refresh-recovery summary is recorded yet.
+
Closure Forecast Reacquisition Summary: No closure-forecast reacquisition summary is recorded yet.
+
Reacquisition Persistence Summary: No reacquisition-persistence summary is recorded yet.
+
Recovery Churn Summary: No recovery-churn summary is recorded yet.
+
Reacquisition Freshness Summary: No reacquisition-freshness summary is recorded yet.
+
Persistence Reset Summary: No persistence-reset summary is recorded yet.
+
Reset Refresh Recovery Summary: No reset-refresh recovery summary is recorded yet.
+
Reset Re-entry Summary: No reset re-entry summary is recorded yet.
+
Reset Re-entry Persistence Summary: No reset re-entry persistence summary is recorded yet.
+
Reset Re-entry Churn Summary: No reset re-entry churn summary is recorded yet.
+
Reset Re-entry Freshness Summary: No reset re-entry freshness summary is recorded yet.
+
Reset Re-entry Reset Summary: No reset re-entry reset summary is recorded yet.
+
Reset Re-entry Refresh Recovery Summary: No reset re-entry refresh-recovery summary is recorded yet.
+
Reset Re-entry Rebuild Summary: No reset re-entry rebuild summary is recorded yet.
+
Reset Re-entry Rebuild Freshness Summary: No reset re-entry rebuild-freshness summary is recorded yet.
+
Reset Re-entry Rebuild Reset Summary: No reset re-entry rebuild-reset summary is recorded yet.
+
Reset Re-entry Rebuild Refresh Recovery Summary: No reset re-entry rebuild-refresh-recovery summary is recorded yet.
+
Reset Re-entry Rebuild Re-entry Summary: No reset re-entry rebuild re-entry summary is recorded yet.
+
Reset Re-entry Rebuild Re-Entry Persistence Summary: No reset re-entry rebuild re-entry persistence summary is recorded yet.
+
Reset Re-entry Rebuild Re-Entry Churn Summary: No reset re-entry rebuild re-entry churn summary is recorded yet.
+
Reset Re-entry Rebuild Re-Entry Freshness Summary: No reset re-entry rebuild re-entry freshness summary is recorded yet.
+
Reset Re-entry Rebuild Re-Entry Reset Summary: No reset re-entry rebuild re-entry reset summary is recorded yet.
+
Reset Re-entry Rebuild Re-Entry Refresh Recovery Summary: No reset re-entry rebuild re-entry refresh recovery summary is recorded yet.
+
Reset Re-entry Rebuild Re-Entry Restore Summary: No reset re-entry rebuild re-entry restore summary is recorded yet.
+
Reset Re-entry Rebuild Re-Entry Restore Freshness Summary: No reset re-entry rebuild re-entry restore freshness summary is recorded yet.
+
Reset Re-entry Rebuild Re-Entry Restore Reset Summary: No reset re-entry rebuild re-entry restore reset summary is recorded yet.
+
Reset Re-entry Rebuild Re-Entry Restore Refresh Recovery Summary: No reset re-entry rebuild re-entry restore refresh recovery summary is recorded yet.
+
Reset Re-entry Rebuild Re-Entry Restore Re-Restore Summary: No reset re-entry rebuild re-entry restore re-restore summary is recorded yet.
+
Reset Re-entry Rebuild Re-Entry Restore Re-Restore Persistence Summary: No reset re-entry rebuild re-entry restore re-restore persistence summary is recorded yet.
+
Reset Re-entry Rebuild Re-Entry Restore Re-Restore Churn Summary: No reset re-entry rebuild re-entry restore re-restore churn summary is recorded yet.
+
Reset Re-entry Rebuild Re-Entry Restore Re-Restore Freshness Summary: No reset re-entry rebuild re-entry restore re-restore freshness summary is recorded yet.
+
Reset Re-entry Rebuild Re-Entry Restore Re-Restore Reset Summary: No reset re-entry rebuild re-entry restore re-restore reset summary is recorded yet.
+
Reset Re-entry Rebuild Re-Entry Restore Re-Restore Refresh Recovery Summary: No reset re-entry rebuild re-entry restore re-restore refresh recovery summary is recorded yet.
+
Reset Re-entry Rebuild Re-Entry Restore Re-Re-Restore Summary: No reset re-entry rebuild re-entry restore re-re-restore summary is recorded yet.
+
Reset Re-entry Rebuild Re-Entry Restore Re-Re-Restore Persistence Summary: No reset re-entry rebuild re-entry restore re-re-restore persistence summary is recorded yet.
+
Reset Re-entry Rebuild Re-Entry Restore Re-Re-Restore Churn Summary: No reset re-entry rebuild re-entry restore re-re-restore churn summary is recorded yet.
+
Reset Re-entry Rebuild Re-Entry Restore Re-Re-Restore Freshness Summary: No reset re-entry rebuild re-entry restore re-re-restore freshness summary is recorded yet.
+
Reset Re-entry Rebuild Re-Entry Restore Re-Re-Restore Reset Summary: No reset re-entry rebuild re-entry restore re-re-restore reset summary is recorded yet.
+
Reset Re-entry Rebuild Re-Entry Restore Re-Re-Restore Refresh Recovery Summary: No reset re-entry rebuild re-entry restore re-re-restore refresh recovery summary is recorded yet.
+
Reset Re-entry Rebuild Re-Entry Restore Re-Re-Re-Restore Summary: No reset re-entry rebuild re-entry restore re-re-re-restore summary is recorded yet.
+
Reset Re-entry Rebuild Re-Entry Restore Re-Re-Re-Restore Persistence Summary: No reset re-entry rebuild re-entry restore re-re-re-restore persistence summary is recorded yet.
+
Reset Re-entry Rebuild Re-Entry Restore Re-Re-Re-Restore Churn Summary: No reset re-entry rebuild re-entry restore re-re-re-restore churn summary is recorded yet.
+
Reset Re-entry Rebuild Persistence Summary: No reset re-entry rebuild-persistence summary is recorded yet.
+
Reset Re-entry Rebuild Churn Summary: No reset re-entry rebuild-churn summary is recorded yet.
+
Recommendation Quality: No recommendation-quality summary is recorded yet.
+
Confidence Validation: insufficient-data — No confidence-calibration summary is recorded yet.
+
Recent Confidence Outcomes: No recent judged confidence outcomes are recorded yet.
+
Blocked: 1 | Urgent: 1 | Ready: 1 | Deferred: 1
+
  • [Blocked] RepoC: Security drift needs review
    RepoC still needs a governance decision before the security review can settle.
    Why this lane: Governed security drift is still unresolved.
    Next: Open the governed control preview and decide whether to apply CodeQL.
    Last movement: Current run
    Follow-through: Unknown — No follow-through evidence is recorded yet.
    Checkpoint timing: Unknown
    Escalation: Unknown — No stronger follow-through escalation is currently surfaced.
    Recovery / Retirement: None — No follow-through recovery or escalation-retirement signal is currently surfaced.
    Recovery Persistence: None — No follow-through recovery persistence signal is currently surfaced.
    Relapse Churn: None — No relapse churn is currently surfaced.
    Recovery Freshness: None — No follow-through recovery freshness signal is currently surfaced.
    Recovery Memory Reset: None — No follow-through recovery memory reset signal is currently surfaced.
    Recovery Rebuild Strength: None — No follow-through recovery rebuild-strength signal is currently surfaced.
    Recovery Reacquisition: None — No follow-through recovery reacquisition signal is currently surfaced.
    Reacquisition Durability: None — No follow-through reacquisition durability signal is currently surfaced.
    Reacquisition Confidence: None — No follow-through reacquisition confidence-consolidation signal is currently surfaced.
    Reacquisition Softening Decay: None — No reacquisition softening-decay signal is currently surfaced.
    Reacquisition Confidence Retirement: None — No reacquisition confidence-retirement signal is currently surfaced.
    Revalidation Recovery: None — No post-revalidation recovery or confidence re-earning signal is currently surfaced.
    Next checkpoint: Use the next run or linked artifact to confirm whether the recommendation moved.
    Artifact: https://github.com/sample-user/RepoC/issues/1
  • [Needs Attention Now] RepoB: Release checklist reopened
    RepoB needs a small release follow-through pass.
    Why this lane: A previously quiet repo reopened a visible checklist item.
    Next: Re-run the release checklist and close the missing item.
    Last movement: Current run
    Follow-through: Unknown — No follow-through evidence is recorded yet.
    Checkpoint timing: Unknown
    Escalation: Unknown — No stronger follow-through escalation is currently surfaced.
    Recovery / Retirement: None — No follow-through recovery or escalation-retirement signal is currently surfaced.
    Recovery Persistence: None — No follow-through recovery persistence signal is currently surfaced.
    Relapse Churn: None — No relapse churn is currently surfaced.
    Recovery Freshness: None — No follow-through recovery freshness signal is currently surfaced.
    Recovery Memory Reset: None — No follow-through recovery memory reset signal is currently surfaced.
    Recovery Rebuild Strength: None — No follow-through recovery rebuild-strength signal is currently surfaced.
    Recovery Reacquisition: None — No follow-through recovery reacquisition signal is currently surfaced.
    Reacquisition Durability: None — No follow-through reacquisition durability signal is currently surfaced.
    Reacquisition Confidence: None — No follow-through reacquisition confidence-consolidation signal is currently surfaced.
    Reacquisition Softening Decay: None — No reacquisition softening-decay signal is currently surfaced.
    Reacquisition Confidence Retirement: None — No reacquisition confidence-retirement signal is currently surfaced.
    Revalidation Recovery: None — No post-revalidation recovery or confidence re-earning signal is currently surfaced.
    Next checkpoint: Use the next run or linked artifact to confirm whether the recommendation moved.
    Artifact: No linked artifact available yet.
  • [Ready for Manual Action] RepoA: Protect shipped momentum
    A small polish pass would keep the showcase repo strong.
    Why this lane: RepoA is healthy enough that a small polish task would keep it strong.
    Next: Tidy the release notes and publish the next small maintenance release.
    Last movement: Current run
    Follow-through: Unknown — No follow-through evidence is recorded yet.
    Checkpoint timing: Unknown
    Escalation: Unknown — No stronger follow-through escalation is currently surfaced.
    Recovery / Retirement: None — No follow-through recovery or escalation-retirement signal is currently surfaced.
    Recovery Persistence: None — No follow-through recovery persistence signal is currently surfaced.
    Relapse Churn: None — No relapse churn is currently surfaced.
    Recovery Freshness: None — No follow-through recovery freshness signal is currently surfaced.
    Recovery Memory Reset: None — No follow-through recovery memory reset signal is currently surfaced.
    Recovery Rebuild Strength: None — No follow-through recovery rebuild-strength signal is currently surfaced.
    Recovery Reacquisition: None — No follow-through recovery reacquisition signal is currently surfaced.
    Reacquisition Durability: None — No follow-through reacquisition durability signal is currently surfaced.
    Reacquisition Confidence: None — No follow-through reacquisition confidence-consolidation signal is currently surfaced.
    Reacquisition Softening Decay: None — No reacquisition softening-decay signal is currently surfaced.
    Reacquisition Confidence Retirement: None — No reacquisition confidence-retirement signal is currently surfaced.
    Revalidation Recovery: None — No post-revalidation recovery or confidence re-earning signal is currently surfaced.
    Next checkpoint: Use the next run or linked artifact to confirm whether the recommendation moved.
    Artifact: No linked artifact available yet.
  • [Safe to Defer] RepoA: Archive old brainstorm notes
    Backlog cleanup is optional this week.
    Why this lane: This is cleanup-only work with no current pressure.
    Next: Leave this alone unless priorities change.
    Last movement: Current run
    Follow-through: Unknown — No follow-through evidence is recorded yet.
    Checkpoint timing: Unknown
    Escalation: Unknown — No stronger follow-through escalation is currently surfaced.
    Recovery / Retirement: None — No follow-through recovery or escalation-retirement signal is currently surfaced.
    Recovery Persistence: None — No follow-through recovery persistence signal is currently surfaced.
    Relapse Churn: None — No relapse churn is currently surfaced.
    Recovery Freshness: None — No follow-through recovery freshness signal is currently surfaced.
    Recovery Memory Reset: None — No follow-through recovery memory reset signal is currently surfaced.
    Recovery Rebuild Strength: None — No follow-through recovery rebuild-strength signal is currently surfaced.
    Recovery Reacquisition: None — No follow-through recovery reacquisition signal is currently surfaced.
    Reacquisition Durability: None — No follow-through reacquisition durability signal is currently surfaced.
    Reacquisition Confidence: None — No follow-through reacquisition confidence-consolidation signal is currently surfaced.
    Reacquisition Softening Decay: None — No reacquisition softening-decay signal is currently surfaced.
    Reacquisition Confidence Retirement: None — No reacquisition confidence-retirement signal is currently surfaced.
    Revalidation Recovery: None — No post-revalidation recovery or confidence re-earning signal is currently surfaced.
    Next checkpoint: Use the next run or linked artifact to confirm whether the recommendation moved.
    Artifact: No linked artifact available yet.
+
Recently Changed:
+
  • No recent operator changes were loaded.
+
+
+ +
+

Weekly Review Pack

+
+
+
Product Mode: Action Sync: use this artifact to confirm the local campaign story first, then preview or apply GitHub, GitHub Projects, or Notion mirrors only after the repo-level decision is settled.
+
Artifact Role: Local report remains authoritative; campaigns, writeback, and GitHub Projects are managed mirrors of the decision already made here.
+
Suggested Reading Order: Read Review Queue first, then the control-center headline and primary target, then the campaign preview or writeback section before syncing outward.
+
Next Best Workflow Step: Keep the local artifact as the source of truth, then use campaign preview or writeback only when the repo decision is already clear.
+
Portfolio Headline: RepoC still needs security follow-through before the queue will calm down.
+
Run Changes: Average score moved +0.020; 0 meaningful improvements, 0 regressions, 1 promotions, and 1 demotions were recorded.
+
Queue Pressure: 1 blocked, 1 urgent, 1 ready, and 1 deferred item(s) are currently in the queue.
+
Trust / Actionability: verify-first — The recommendation is sound, but recent reopen noise means it should still be reviewed before acting.
+
What To Do This Week: Review RepoC first, then close RepoB's reopened checklist item. Start with RepoC if you need a concrete place to begin.
+
Portfolio Catalog: No portfolio catalog contract is recorded yet.
+
Operating Paths: No normalized operating-path contract is recorded yet.
+
Intent Alignment: Intent alignment cannot be judged until a portfolio catalog contract exists.
+
Scorecards: No maturity scorecard is recorded yet.
+
Implementation Hotspots: No meaningful implementation hotspots are currently surfaced.
+
Operator Outcomes: Not enough operator history is recorded yet to judge whether recent actions are improving portfolio outcomes.
+
Operator Effectiveness: Not enough judged recommendation history is recorded yet to judge operator effectiveness.
+
High-Pressure Queue Trend: High-pressure queue trend is not ready yet.
+
Action Sync Readiness: No current campaign needs Action Sync yet, so the safest next move is to keep the story local.
+
Next Action Sync Step: Stay local for now; no current campaign needs preview or apply.
+
Apply Packet: No current campaign has a safe execution handoff yet, so the local story should stay local for now.
+
Next Apply Candidate: Stay local for now; no current campaign has a safe execution handoff.
+
Action Sync Command Hint: No Action Sync command is recommended yet.
+
Post-Apply Monitoring: No recent Action Sync apply needs post-apply monitoring yet, so the local weekly story can stay local.
+
Next Monitoring Step: Stay local for now; no recent Action Sync apply needs post-apply follow-up yet.
+
Campaign Tuning: Campaign tuning stays neutral until there is enough outcome history to bias tied recommendations.
+
Next Tie-Break Candidate: No current campaign needs a tie-break candidate yet.
+
Historical Portfolio Intelligence: Historical portfolio intelligence is still thin, so the weekly story should stay grounded in the current run and recent operator queue.
+
Next Historical Focus: Stay local for now; no repo has enough cross-run intervention evidence to demand a historical follow-up read yet.
+
Automation Guidance: Automation guidance stays quiet until a campaign has a clearly safe preview, follow-up, or manual-only posture.
+
Next Safe Automation Step: Stay local for now; no current campaign has a stronger safe automation posture than manual review.
+
Approval Workflow: No current approval needs review yet, so the approval workflow can stay local for now.
+
Next Approval Review: Stay local for now; no current approval needs review.
+ +
+

Action Sync Readiness

+
Summary: No current campaign needs Action Sync yet, so the safest next move is to keep the story local.
+
Next Step: Stay local for now; no current campaign needs preview or apply.
+
State: idle
+
  • No supporting evidence is currently surfaced.
+
+ +
+

Apply Packet

+
Summary: No current campaign has a safe execution handoff yet, so the local story should stay local for now.
+
Next Candidate: Stay local for now; no current campaign has a safe execution handoff.
+
State: idle
+
  • No supporting evidence is currently surfaced.
+
+ +
+

Post-Apply Monitoring

+
Summary: No recent Action Sync apply needs post-apply monitoring yet, so the local weekly story can stay local.
+
Next Step: Stay local for now; no recent Action Sync apply needs post-apply follow-up yet.
+
State: idle
+
  • No supporting evidence is currently surfaced.
+
+ +
+

Campaign Tuning

+
Summary: Campaign tuning stays neutral until there is enough outcome history to bias tied recommendations.
+
Next Tie-Break Candidate: No current campaign needs a tie-break candidate yet.
+
State: idle
+
  • No supporting evidence is currently surfaced.
+
+ +
+

Historical Portfolio Intelligence

+
Summary: Historical portfolio intelligence is still thin, so the weekly story should stay grounded in the current run and recent operator queue.
+
Next Focus: Stay local for now; no repo has enough cross-run intervention evidence to demand a historical follow-up read yet.
+
State: idle
+
  • No supporting evidence is currently surfaced.
+
+ +
+

Automation Guidance

+
Summary: Automation guidance stays quiet until a campaign has a clearly safe preview, follow-up, or manual-only posture.
+
Next Step: Stay local for now; no current campaign has a stronger safe automation posture than manual review.
+
State: idle
+
  • No supporting evidence is currently surfaced.
+
+ +
+

Approval Workflow

+
Summary: No current approval needs review yet, so the approval workflow can stay local for now.
+
Next Approval Review: Stay local for now; no current approval needs review.
+
State: idle
+
  • No supporting evidence is currently surfaced.
+
+ +
+

Operator Focus

+
Summary: 2 item(s) need immediate action first, led by RepoC, RepoB.
+
Next Checkpoint: Use the next run or linked artifact to confirm whether the recommendation moved.
+
State: act-now
+
  • RepoC — Governed security drift is still unresolved.
  • RepoB — A previously quiet repo reopened a visible checklist item.
  • RepoA — No follow-through evidence is recorded yet.
  • RepoA — No follow-through evidence is recorded yet.
+
+ +
Operator Focus: 2 item(s) need immediate action first, led by RepoC, RepoB.
+
Next Checkpoint: Use the next run or linked artifact to confirm whether the recommendation moved.
+
Act Now:
  • RepoC: Security drift needs review — Governed security drift is still unresolved.
  • RepoB: Release checklist reopened — A previously quiet repo reopened a visible checklist item.
Watch Closely:
  • RepoA: Protect shipped momentum — No follow-through evidence is recorded yet.
  • RepoA: Archive old brainstorm notes — No follow-through evidence is recorded yet.
Improving:
  • No clearly improving hotspots are currently surfaced.
Fragile:
  • No fragile hotspots are currently surfaced.
Revalidate:
  • No revalidation hotspots are currently surfaced.
+

Top Attention

+
  • RepoC: Security drift needs review
    What Changed: Current run
    Why It Matters: Governed security drift is still unresolved.
    What To Do Next: Open the governed control preview and decide whether to apply CodeQL.
    Operator Focus: Act Now: Governed security drift is still unresolved.
    Catalog: No portfolio catalog contract is recorded yet.
    Operating Path: Unspecified (legacy confidence) — No operating-path rationale is recorded yet.
    Intent Alignment: missing-contract: Intent alignment cannot be judged until a portfolio catalog contract exists.
    Scorecard: No maturity scorecard is recorded yet.
    Maturity Gap: No maturity gap summary is recorded yet.
    Evidence: Operator Focus: Act Now: Governed security drift is still unresolved.; Action Sync: Action Sync: stay local until a campaign has meaningful actions and healthy writeback prerequisites.; Automation Guidance: Automation Guidance: keep the next step human-led until a bounded safe posture is surfaced.; Approval Workflow: Approval Workflow: no current approval needs review yet.
    Checkpoint Timing: Unknown
    Next Checkpoint: Use the next run or linked artifact to confirm whether the recommendation moved.
  • RepoB: Release checklist reopened
    What Changed: Current run
    Why It Matters: A previously quiet repo reopened a visible checklist item.
    What To Do Next: Re-run the release checklist and close the missing item.
    Operator Focus: Act Now: A previously quiet repo reopened a visible checklist item.
    Catalog: No portfolio catalog contract is recorded yet.
    Operating Path: Unspecified (legacy confidence) — No operating-path rationale is recorded yet.
    Intent Alignment: missing-contract: Intent alignment cannot be judged until a portfolio catalog contract exists.
    Scorecard: No maturity scorecard is recorded yet.
    Maturity Gap: No maturity gap summary is recorded yet.
    Evidence: Operator Focus: Act Now: A previously quiet repo reopened a visible checklist item.; Action Sync: Action Sync: stay local until a campaign has meaningful actions and healthy writeback prerequisites.; Automation Guidance: Automation Guidance: keep the next step human-led until a bounded safe posture is surfaced.; Approval Workflow: Approval Workflow: no current approval needs review yet.
    Checkpoint Timing: Unknown
    Next Checkpoint: Use the next run or linked artifact to confirm whether the recommendation moved.
  • RepoA: Protect shipped momentum
    What Changed: Current run
    Why It Matters: RepoA is healthy enough that a small polish task would keep it strong.
    What To Do Next: Tidy the release notes and publish the next small maintenance release.
    Operator Focus: Watch Closely: No follow-through evidence is recorded yet.
    Catalog: No portfolio catalog contract is recorded yet.
    Operating Path: Unspecified (legacy confidence) — No operating-path rationale is recorded yet.
    Intent Alignment: missing-contract: Intent alignment cannot be judged until a portfolio catalog contract exists.
    Scorecard: No maturity scorecard is recorded yet.
    Maturity Gap: No maturity gap summary is recorded yet.
    Evidence: Operator Focus: Watch Closely: No follow-through evidence is recorded yet.; Action Sync: Action Sync: stay local until a campaign has meaningful actions and healthy writeback prerequisites.; Automation Guidance: Automation Guidance: keep the next step human-led until a bounded safe posture is surfaced.; Approval Workflow: Approval Workflow: no current approval needs review yet.
    Checkpoint Timing: Unknown
    Next Checkpoint: Use the next run or linked artifact to confirm whether the recommendation moved.
  • RepoA: Archive old brainstorm notes
    What Changed: Current run
    Why It Matters: This is cleanup-only work with no current pressure.
    What To Do Next: Leave this alone unless priorities change.
    Operator Focus: Watch Closely: No follow-through evidence is recorded yet.
    Catalog: No portfolio catalog contract is recorded yet.
    Operating Path: Unspecified (legacy confidence) — No operating-path rationale is recorded yet.
    Intent Alignment: missing-contract: Intent alignment cannot be judged until a portfolio catalog contract exists.
    Scorecard: No maturity scorecard is recorded yet.
    Maturity Gap: No maturity gap summary is recorded yet.
    Evidence: Operator Focus: Watch Closely: No follow-through evidence is recorded yet.; Action Sync: Action Sync: stay local until a campaign has meaningful actions and healthy writeback prerequisites.; Automation Guidance: Automation Guidance: keep the next step human-led until a bounded safe posture is surfaced.; Approval Workflow: Approval Workflow: no current approval needs review yet.
    Checkpoint Timing: Unknown
    Next Checkpoint: Use the next run or linked artifact to confirm whether the recommendation moved.
+
+
+

Top Repo Drilldowns

+ +
+

RepoC — 0.44 (wip)

+
Current State: Score 0.44, grade D, wip tier, Python, trend: No history is recorded yet, so this view is using the current run only.
+
What Changed: Regressed 0.080 versus the last run. Tier moved functional -> wip. Score regressed 0.080 since the last run. Tier moved functional -> wip.
+
Why It Matters: Strongest drivers: Security (0.28), Testing (0.18). Biggest drags: Testing (0.18), Security (0.28). Next tier gap: Needs +0.31 to reach shipped.
+
Where To Start: No meaningful implementation hotspot is currently surfaced.
+
What To Do Next: Open the governed control preview and decide whether to apply CodeQL. No action rationale is recorded yet.
+
Operator Focus: Act Now: Governed security drift is still unresolved.
+
Catalog: No portfolio catalog contract is recorded yet.
+
Operating Path: Unspecified (legacy confidence) — No operating-path rationale is recorded yet.
+
Intent Alignment: missing-contract: Intent alignment cannot be judged until a portfolio catalog contract exists.
+
Scorecard: No maturity scorecard is recorded yet.
+
Maturity Gap: No maturity gap summary is recorded yet.
+
Evidence: Where To Start: No meaningful implementation hotspot is currently surfaced.; Operator Focus: Act Now: Governed security drift is still unresolved.; Action Sync: Action Sync: stay local until a campaign has meaningful actions and healthy writeback prerequisites.; Automation Guidance: Automation Guidance: keep the next step human-led until a bounded safe posture is surfaced.
+
Checkpoint Timing: Unknown
+
What Would Count As Progress: Use the next run or linked artifact to confirm whether the recommendation moved.
+
+ +
+

RepoB — 0.62 (functional)

+
Current State: Score 0.62, grade C, functional tier, TypeScript, trend: No history is recorded yet, so this view is using the current run only.
+
What Changed: Regressed 0.060 versus the last run. Score regressed 0.060 since the last run.
+
Why It Matters: Strongest drivers: Security (0.66), Testing (0.55), Release (0.48). Biggest drags: Release (0.48), Testing (0.55), Security (0.66). Next tier gap: Needs +0.13 to reach shipped.
+
Where To Start: No meaningful implementation hotspot is currently surfaced.
+
What To Do Next: Re-run the release checklist and close the missing item. No action rationale is recorded yet.
+
Operator Focus: Act Now: A previously quiet repo reopened a visible checklist item.
+
Catalog: No portfolio catalog contract is recorded yet.
+
Operating Path: Unspecified (legacy confidence) — No operating-path rationale is recorded yet.
+
Intent Alignment: missing-contract: Intent alignment cannot be judged until a portfolio catalog contract exists.
+
Scorecard: No maturity scorecard is recorded yet.
+
Maturity Gap: No maturity gap summary is recorded yet.
+
Evidence: Where To Start: No meaningful implementation hotspot is currently surfaced.; Operator Focus: Act Now: A previously quiet repo reopened a visible checklist item.; Action Sync: Action Sync: stay local until a campaign has meaningful actions and healthy writeback prerequisites.; Automation Guidance: Automation Guidance: keep the next step human-led until a bounded safe posture is surfaced.
+
Checkpoint Timing: Unknown
+
What Would Count As Progress: Use the next run or linked artifact to confirm whether the recommendation moved.
+
+ +
+

RepoA — 0.88 (shipped)

+
Current State: Score 0.88, grade A, shipped tier, Python, trend: No history is recorded yet, so this view is using the current run only.
+
What Changed: Improved 0.090 versus the last run. Tier moved functional -> shipped. Score improved 0.090 since the last run. Tier moved functional -> shipped.
+
Why It Matters: Strongest drivers: Testing (0.90), Documentation (0.85), Security (0.82). Biggest drags: Security (0.82), Documentation (0.85), Testing (0.90). Next tier gap: Already at shipped tier; focus on protecting momentum and preventing drift.
+
Where To Start: No meaningful implementation hotspot is currently surfaced.
+
What To Do Next: Tidy the release notes and publish the next small maintenance release. No action rationale is recorded yet.
+
Operator Focus: Watch Closely: No follow-through evidence is recorded yet.
+
Catalog: No portfolio catalog contract is recorded yet.
+
Operating Path: Unspecified (legacy confidence) — No operating-path rationale is recorded yet.
+
Intent Alignment: missing-contract: Intent alignment cannot be judged until a portfolio catalog contract exists.
+
Scorecard: No maturity scorecard is recorded yet.
+
Maturity Gap: No maturity gap summary is recorded yet.
+
Evidence: Where To Start: No meaningful implementation hotspot is currently surfaced.; Operator Focus: Watch Closely: No follow-through evidence is recorded yet.; Action Sync: Action Sync: stay local until a campaign has meaningful actions and healthy writeback prerequisites.; Automation Guidance: Automation Guidance: keep the next step human-led until a bounded safe posture is surfaced.
+
Checkpoint Timing: Unknown
+
What Would Count As Progress: Use the next run or linked artifact to confirm whether the recommendation moved.
+
+ +
+
+
+ +
+

Top Attention / Next Action

+
+
  • RepoC: Security drift needs review
    Why it matters: Governed security drift is still unresolved.
    What to do next: Open the governed control preview and decide whether to apply CodeQL.
    Operator Focus: Act Now: Governed security drift is still unresolved.
    Catalog: No portfolio catalog contract is recorded yet.
    Operating Path: Unspecified (legacy confidence) — No operating-path rationale is recorded yet.
    Intent Alignment: missing-contract: Intent alignment cannot be judged until a portfolio catalog contract exists.
    Scorecard: No maturity scorecard is recorded yet.
    Maturity Gap: No maturity gap summary is recorded yet.
    Action Sync: Action Sync: stay local until a campaign has meaningful actions and healthy writeback prerequisites.
    Apply Packet: Apply Packet: no current execution handoff is surfaced.
    Post-Apply Monitoring: Post-Apply Monitoring: no recent Action Sync apply needs follow-up yet.
    Campaign Tuning: Campaign Tuning: recommendations stay neutral until more outcome history is available.
    Approval Workflow: Approval Workflow: no current approval needs review yet.
    Checkpoint timing: Unknown
  • RepoB: Release checklist reopened
    Why it matters: A previously quiet repo reopened a visible checklist item.
    What to do next: Re-run the release checklist and close the missing item.
    Operator Focus: Act Now: A previously quiet repo reopened a visible checklist item.
    Catalog: No portfolio catalog contract is recorded yet.
    Operating Path: Unspecified (legacy confidence) — No operating-path rationale is recorded yet.
    Intent Alignment: missing-contract: Intent alignment cannot be judged until a portfolio catalog contract exists.
    Scorecard: No maturity scorecard is recorded yet.
    Maturity Gap: No maturity gap summary is recorded yet.
    Action Sync: Action Sync: stay local until a campaign has meaningful actions and healthy writeback prerequisites.
    Apply Packet: Apply Packet: no current execution handoff is surfaced.
    Post-Apply Monitoring: Post-Apply Monitoring: no recent Action Sync apply needs follow-up yet.
    Campaign Tuning: Campaign Tuning: recommendations stay neutral until more outcome history is available.
    Approval Workflow: Approval Workflow: no current approval needs review yet.
    Checkpoint timing: Unknown
  • RepoA: Protect shipped momentum
    Why it matters: RepoA is healthy enough that a small polish task would keep it strong.
    What to do next: Tidy the release notes and publish the next small maintenance release.
    Operator Focus: Watch Closely: No follow-through evidence is recorded yet.
    Catalog: No portfolio catalog contract is recorded yet.
    Operating Path: Unspecified (legacy confidence) — No operating-path rationale is recorded yet.
    Intent Alignment: missing-contract: Intent alignment cannot be judged until a portfolio catalog contract exists.
    Scorecard: No maturity scorecard is recorded yet.
    Maturity Gap: No maturity gap summary is recorded yet.
    Action Sync: Action Sync: stay local until a campaign has meaningful actions and healthy writeback prerequisites.
    Apply Packet: Apply Packet: no current execution handoff is surfaced.
    Post-Apply Monitoring: Post-Apply Monitoring: no recent Action Sync apply needs follow-up yet.
    Campaign Tuning: Campaign Tuning: recommendations stay neutral until more outcome history is available.
    Approval Workflow: Approval Workflow: no current approval needs review yet.
    Checkpoint timing: Unknown
+
+
+ +
+

Analyst View

+
+
+
Profile: default
+
Collection: all
+
showcase: 1
+
+
+

Profile Leaders

+ + + +
RepoProfile ScoreTier
RepoA0.880shipped
RepoB0.620functional
RepoC0.440wip
+
+
+
+ +
+

Decision Lenses

+
ship readiness
0.71
Delivery readiness
showcase value
0.63
Story and polish
+
+ +
+

Security Overview

+
+
+
Avg Security Score
+
0.58
+
Portfolio-wide merged security posture.
+
+
+
GitHub Coverage
+
3
+
Repos with GitHub-native security evidence available.
+
+
+
Scorecard Coverage
+
0
+
Repos with external Scorecard evidence loaded.
+
+
+
Open Alerts
+
3
+
Combined code and secret scanning alerts.
+
+
+
+

Completeness vs Interest

+ +
+
+ +
+

All Repos

+
+ + + + + +
+ + + + + + +
RepoProfileGradeScoreInterestTierRiskLanguageCollectionsTrendDescription
RepoA0.880A0.8800.610shippedbaselinePythonshowcaseA polished shipped project.
Next: Publish the next maintenance release
Gap: Already at shipped tier; focus on protecting momentum and preventing drift.
RepoB0.620C0.6200.370functionalelevatedTypeScriptA functional project with follow-through left to do.
Next: Close the reopened release item
Gap: Needs +0.13 to reach shipped.
RepoC0.440D0.4400.160wipelevatedPythonA risky work-in-progress project.
Next: Preview governance controls
Gap: Needs +0.31 to reach shipped.
+
+ +
+

Repo Drilldowns

+
+ +
+

RepoA — 0.88 (shipped)

+
Current State: Score 0.88, grade A, shipped tier, Python, trend: No history is recorded yet, so this view is using the current run only.
+
Description: A polished shipped project.
+
Why This Repo Looks This Way: Strongest drivers: Testing (0.90), Documentation (0.85), Security (0.82). Biggest drags: Security (0.82), Documentation (0.85), Testing (0.90). Next tier gap: Already at shipped tier; focus on protecting momentum and preventing drift.
+
What Changed: Improved 0.090 versus the last run. Tier moved functional -> shipped. Score improved 0.090 since the last run. Tier moved functional -> shipped.
+
Hotspot Context: Keep release notes fresh
+
Where To Start: No meaningful implementation hotspot is currently surfaced.
+
  • No implementation hotspots are currently surfaced.
+
What To Do Next: Tidy the release notes and publish the next small maintenance release.
+
Rationale: No action rationale is recorded yet.
+
Follow-Through: Unknown: No follow-through evidence is recorded yet.
+
Checkpoint Timing: Unknown
+
Escalation: Unknown: No stronger follow-through escalation is currently surfaced.
+
What Would Count As Progress: Use the next run or linked artifact to confirm whether the recommendation moved.
+
Linked Artifact: No linked artifact available yet.
+
+ +
+

RepoB — 0.62 (functional)

+
Current State: Score 0.62, grade C, functional tier, TypeScript, trend: No history is recorded yet, so this view is using the current run only.
+
Description: A functional project with follow-through left to do.
+
Why This Repo Looks This Way: Strongest drivers: Security (0.66), Testing (0.55), Release (0.48). Biggest drags: Release (0.48), Testing (0.55), Security (0.66). Next tier gap: Needs +0.13 to reach shipped.
+
What Changed: Regressed 0.060 versus the last run. Score regressed 0.060 since the last run.
+
Hotspot Context: Finish release checklist
+
Where To Start: No meaningful implementation hotspot is currently surfaced.
+
  • No implementation hotspots are currently surfaced.
+
What To Do Next: Re-run the release checklist and close the missing item.
+
Rationale: No action rationale is recorded yet.
+
Follow-Through: Unknown: No follow-through evidence is recorded yet.
+
Checkpoint Timing: Unknown
+
Escalation: Unknown: No stronger follow-through escalation is currently surfaced.
+
What Would Count As Progress: Use the next run or linked artifact to confirm whether the recommendation moved.
+
Linked Artifact: No linked artifact available yet.
+
+ +
+

RepoC — 0.44 (wip)

+
Current State: Score 0.44, grade D, wip tier, Python, trend: No history is recorded yet, so this view is using the current run only.
+
Description: A risky work-in-progress project.
+
Why This Repo Looks This Way: Strongest drivers: Security (0.28), Testing (0.18). Biggest drags: Testing (0.18), Security (0.28). Next tier gap: Needs +0.31 to reach shipped.
+
What Changed: Regressed 0.080 versus the last run. Tier moved functional -> wip. Score regressed 0.080 since the last run. Tier moved functional -> wip.
+
Hotspot Context: Security posture needs attention
+
Where To Start: No meaningful implementation hotspot is currently surfaced.
+
  • No implementation hotspots are currently surfaced.
+
What To Do Next: Open the governed control preview and decide whether to apply CodeQL.
+
Rationale: No action rationale is recorded yet.
+
Follow-Through: Unknown: No follow-through evidence is recorded yet.
+
Checkpoint Timing: Unknown
+
Escalation: Unknown: No stronger follow-through escalation is currently surfaced.
+
What Would Count As Progress: Use the next run or linked artifact to confirm whether the recommendation moved.
+
Linked Artifact: No linked artifact available yet.
+
+ +
+
+ +
+

Portfolio Trends

+

Not enough historical data for trends. Run audits over time to see portfolio evolution.

+
+ +
+

Run Changes

+
+
+
Summary: Average score moved +0.020; 0 meaningful improvements, 0 regressions, 1 promotions, and 1 demotions were recorded.
+
Why It Matters: 1 blocked, 1 urgent, 1 ready, and 1 deferred item(s) are currently in the queue.
+
What To Do Next: Review RepoC first, then close RepoB's reopened checklist item. Start with RepoC if you need a concrete place to begin.
+
Improving: 0 | Regressing: 0
+
Promotions: 1 | Demotions: 1
+
Security / Governance: 1 / 1
+
+
+ + + +
RepoDeltaTier Change
RepoA+0.090functional → shipped
RepoC-0.080functional → wip
+
+
+
+ +
+

Compare

+
+
+
Average score delta: +0.020
+ + + +
LensDelta
ship_readiness+0.030
security_posture-0.010
+
+
+

Top Movers

+ + + +
RepoScore DeltaTier
RepoA+0.090functional → shipped
RepoC-0.080functional → wip
+
+
+
+ +
+

Scenario Preview

+
+
+
Projected average score delta: +0.000
+
Projected promotions: 0
+
Selected repos: 3
+
+
+ + + +
LeverLensReposAvg Lift
Publish the next maintenance release1+0.000
Close the reopened release item1+0.000
Preview governance controls1+0.000
+
+
+
+ +
+

Governance Operator State

+
Headline: Governed security drift needs review.
Status: drifted
Approved: no | Needs Re-Approval: no
Drift Count: 1 | Applied Results: 0 | Rollback Available: 1
+ + + +
RepoStateActionExpected LiftSource
RepoCreadyEnable CodeQL default setup0.12github
+
+ +
+

Campaign

+
+
+
Campaign: Security Review
+
Actions: 1
+
Repos: 1
+
Sync mode: reconcile
+
Drift: 1
+
Action Sync: Stay local for now; no current campaign needs preview or apply.
+
Apply Packet: No current campaign has a safe execution handoff yet, so the local story should stay local for now.
+
Command Hint: No Action Sync command is recommended yet.
+
Post-Apply Monitoring: No recent Action Sync apply needs post-apply monitoring yet, so the local weekly story can stay local.
+
Next Monitoring Step: Stay local for now; no recent Action Sync apply needs post-apply follow-up yet.
+
Campaign Tuning: Campaign tuning stays neutral until there is enough outcome history to bias tied recommendations.
+
Next Tie-Break Candidate: No current campaign needs a tie-break candidate yet.
+
Automation Guidance: Automation guidance stays quiet until a campaign has a clearly safe preview, follow-up, or manual-only posture.
+
Next Safe Automation Step: Stay local for now; no current campaign has a stronger safe automation posture than manual review.
+
Approval Workflow: No current approval needs review yet, so the approval workflow can stay local for now.
+
Next Approval Review: Stay local for now; no current approval needs review.
+
GitHub Projects: disabled + (— #0, 0 items)
+
+
+ + + +
RepoManaged IssueTopicsProjectsNotion
RepoC[Repo Auditor] Security Review101
+
+
+
+ +
+

Writeback Results

+
Mode: apply | + Target: github
+
Managed drift: 1
+ + + +
RepoTargetStatusDetails
sample-user/RepoCgithub-issuecreatedhttps://github.com/sample-user/RepoC/issues/1
+
+ +
+

Tech Radar

+ + + +
LanguageReposTrendCategory
TypeScript44▁▂▆▆▆▆▆▇▇█Adopt
Rust32▁▁▁▁▁▁▁███Hold
Python19▁▂▄▄▄▄▄▅██Adopt
Swift16▅▅▅▅▅▅▅▅▅▅Hold
Shell4▁▁▁▁▂▂▂▂██Trial
Makefile3▁█▆▆▆▆▆▆▆▆Trial
GDScript3▅▅▅▅▅▅▅▅▅▅Hold
JavaScript2▅▅▅▅▅▅▅▅▅▅Hold
PLpgSQL1▅▅▅▅▅▅▅▅▅▅Hold
Go1▁▁████████Trial
+
+ +
+

Tier Distribution

+
Shipped
1
Functional
1
Wip
1
Skeleton
0
Abandoned
0
+
+ + + + + + \ No newline at end of file diff --git a/output/demo/demo-report.json b/output/demo/demo-report.json new file mode 100644 index 0000000..5d48864 --- /dev/null +++ b/output/demo/demo-report.json @@ -0,0 +1,557 @@ +{ + "username": "sample-user", + "generated_at": "2026-04-12T12:00:00+00:00", + "repos_audited": 3, + "total_repos": 3, + "average_score": 0.65, + "portfolio_grade": "B", + "portfolio_health_score": 0.69, + "tier_distribution": { + "shipped": 1, + "functional": 1, + "wip": 1, + "skeleton": 0, + "abandoned": 0 + }, + "language_distribution": { + "Python": 2, + "TypeScript": 1 + }, + "profiles": { + "default": { + "description": "Balanced portfolio scoring." + } + }, + "collections": { + "showcase": { + "description": "Best examples to show other people.", + "repos": [ + { + "name": "RepoA", + "reason": "Strong showcase candidate." + } + ] + } + }, + "lenses": { + "ship_readiness": { + "description": "Delivery readiness", + "average_score": 0.71 + }, + "showcase_value": { + "description": "Story and polish", + "average_score": 0.63 + } + }, + "scenario_summary": { + "top_levers": [ + { + "key": "testing", + "title": "Strengthen tests", + "lens": "ship_readiness", + "repo_count": 2, + "average_expected_lens_delta": 0.09, + "projected_tier_promotions": 1 + } + ], + "portfolio_projection": { + "selected_repo_count": 3, + "projected_average_score_delta": 0.05, + "projected_tier_promotions": 1 + } + }, + "security_posture": { + "average_score": 0.58, + "critical_repos": [ + "RepoC" + ], + "repos_with_secrets": [], + "provider_coverage": { + "github": { + "available_repos": 3, + "total_repos": 3 + } + }, + "open_alerts": { + "code_scanning": 2, + "secret_scanning": 1 + } + }, + "security_governance_preview": [ + { + "repo": "RepoC", + "priority": "high", + "title": "Enable CodeQL default setup", + "expected_posture_lift": 0.12, + "effort": "medium", + "source": "github", + "why": "Code scanning is not configured." + } + ], + "governance_summary": { + "headline": "Governed security drift needs review.", + "status": "drifted", + "needs_reapproval": false, + "drift_count": 1, + "applyable_count": 1, + "applied_count": 0, + "rollback_available_count": 1, + "top_actions": [ + { + "repo": "RepoC", + "title": "Enable CodeQL default setup", + "operator_state": "ready", + "expected_posture_lift": 0.12, + "source": "github" + } + ] + }, + "campaign_summary": { + "campaign_type": "security-review", + "label": "Security Review", + "action_count": 1, + "repo_count": 1 + }, + "writeback_preview": { + "sync_mode": "reconcile", + "repos": [ + { + "repo": "RepoC", + "topics": [ + "ghra-call-security-review" + ], + "issue_title": "[Repo Auditor] Security Review", + "notion_action_count": 1 + } + ] + }, + "writeback_results": { + "mode": "apply", + "target": "github", + "results": [ + { + "repo_full_name": "sample-user/RepoC", + "target": "github-issue", + "status": "created", + "url": "https://github.com/sample-user/RepoC/issues/1" + } + ] + }, + "managed_state_drift": [ + { + "repo_full_name": "sample-user/RepoC", + "target": "github-issue", + "drift_state": "managed-issue-edited" + } + ], + "governance_drift": [ + { + "repo_full_name": "sample-user/RepoC", + "drift_type": "already-enabled" + } + ], + "review_summary": { + "review_id": "sample-review-1", + "status": "open", + "source_run_id": "sample-user:2026-04-12T12:00:00+00:00" + }, + "review_targets": [ + { + "repo": "RepoC", + "title": "Security posture needs attention", + "severity": 0.84, + "next_step": "Preview governance controls", + "decision_hint": "ready-for-governance-approval", + "safe_to_defer": false + } + ], + "review_history": [ + { + "review_id": "sample-review-1", + "generated_at": "2026-04-12T12:00:00+00:00", + "material_change_count": 2, + "status": "open", + "decision_state": "needs-review", + "sync_state": "local-only", + "emitted": true + } + ], + "material_changes": [ + { + "change_type": "security-change", + "repo": "RepoC", + "severity": 0.84, + "title": "Security posture needs attention" + }, + { + "change_type": "reopened-review", + "repo": "RepoB", + "severity": 0.51, + "title": "Release checklist reopened" + } + ], + "operator_summary": { + "headline": "RepoC still needs security follow-through before the queue will calm down.", + "counts": { + "blocked": 1, + "urgent": 1, + "ready": 1, + "deferred": 1 + }, + "source_run_id": "sample-user:2026-04-12T12:00:00+00:00", + "next_recommended_run_mode": "incremental", + "watch_strategy": "adaptive", + "watch_decision_summary": "The current baseline is still compatible, so incremental watch remains safe for the next run.", + "what_changed": "RepoC drift needs review and RepoB reopened a release checklist item.", + "why_it_matters": "Live drift is still present, so security work should stay ahead of lower-pressure cleanup.", + "what_to_do_next": "Review RepoC first, then close RepoB's reopened checklist item.", + "trend_summary": "Queue pressure is stable but still sticky.", + "follow_through_summary": "One urgent item is still repeating in the recent window.", + "primary_target_reason": "RepoC remains the top target because live drift is still open.", + "closure_guidance": "Clear RepoC's security drift before moving to lower-pressure work.", + "primary_target_trust_policy": "verify-first", + "primary_target_trust_policy_reason": "The recommendation is sound, but recent reopen noise means it should still be reviewed before acting.", + "control_center_reference": "output/demo/operator-control-center-sample-user-2026-04-12.json" + }, + "operator_queue": [ + { + "repo": "RepoC", + "title": "Security drift needs review", + "lane": "blocked", + "lane_label": "Blocked", + "lane_reason": "Governed security drift is still unresolved.", + "kind": "campaign", + "priority": 1, + "summary": "RepoC still needs a governance decision before the security review can settle.", + "recommended_action": "Open the governed control preview and decide whether to apply CodeQL.", + "repo_url": "https://github.com/sample-user/RepoC", + "links": [ + { + "label": "GitHub Issue", + "url": "https://github.com/sample-user/RepoC/issues/1" + } + ] + }, + { + "repo": "RepoB", + "title": "Release checklist reopened", + "lane": "urgent", + "lane_label": "Needs Attention Now", + "lane_reason": "A previously quiet repo reopened a visible checklist item.", + "kind": "review", + "priority": 2, + "summary": "RepoB needs a small release follow-through pass.", + "recommended_action": "Re-run the release checklist and close the missing item.", + "repo_url": "https://github.com/sample-user/RepoB" + }, + { + "repo": "RepoA", + "title": "Protect shipped momentum", + "lane": "ready", + "lane_label": "Ready for Manual Action", + "lane_reason": "RepoA is healthy enough that a small polish task would keep it strong.", + "kind": "maintenance", + "priority": 3, + "summary": "A small polish pass would keep the showcase repo strong.", + "recommended_action": "Tidy the release notes and publish the next small maintenance release.", + "repo_url": "https://github.com/sample-user/RepoA" + }, + { + "repo": "RepoA", + "title": "Archive old brainstorm notes", + "lane": "deferred", + "lane_label": "Safe to Defer", + "lane_reason": "This is cleanup-only work with no current pressure.", + "kind": "cleanup", + "priority": 4, + "summary": "Backlog cleanup is optional this week.", + "recommended_action": "Leave this alone unless priorities change.", + "repo_url": "https://github.com/sample-user/RepoA" + } + ], + "run_change_summary": "Average score moved +0.020; 0 meaningful improvements, 0 regressions, 1 promotions, and 1 demotions were recorded.", + "run_change_counts": { + "new_repos": 0, + "removed_repos": 0, + "tier_promotions": 1, + "tier_demotions": 1, + "score_improvements": 0, + "score_regressions": 0, + "security_changes": 1, + "hotspot_changes": 2, + "collection_changes": 1, + "notable_repo_changes": 2 + }, + "audits": [ + { + "metadata": { + "name": "RepoA", + "full_name": "sample-user/RepoA", + "html_url": "https://github.com/sample-user/RepoA", + "description": "A polished shipped project.", + "language": "Python", + "private": false, + "archived": false, + "stars": 12, + "topics": [ + "python", + "cli" + ] + }, + "overall_score": 0.88, + "interest_score": 0.61, + "grade": "A", + "completeness_tier": "shipped", + "badges": [ + "fresh", + "tested" + ], + "flags": [], + "lenses": { + "ship_readiness": { + "score": 0.89, + "summary": "Ready" + }, + "momentum": { + "score": 0.75, + "summary": "Holding" + }, + "security_posture": { + "score": 0.82, + "summary": "Healthy" + }, + "portfolio_fit": { + "score": 0.86, + "summary": "Strong" + } + }, + "security_posture": { + "label": "healthy", + "score": 0.82 + }, + "hotspots": [ + { + "title": "Keep release notes fresh", + "severity": 0.21, + "category": "finish-line" + } + ], + "action_candidates": [ + { + "title": "Publish the next maintenance release" + } + ], + "analyzer_results": [ + { + "dimension": "testing", + "score": 0.9, + "findings": [ + "Healthy test coverage" + ] + }, + { + "dimension": "documentation", + "score": 0.85, + "findings": [ + "README is strong" + ] + } + ], + "score_explanation": { + "repo": "RepoA", + "top_positive_drivers": [ + "Testing (0.90)", + "Documentation (0.85)", + "Security (0.82)" + ], + "top_negative_drivers": [ + "Security (0.82)", + "Documentation (0.85)", + "Testing (0.90)" + ], + "next_tier_gap_summary": "Already at shipped tier; focus on protecting momentum and preventing drift.", + "next_best_action": "Publish the next maintenance release", + "next_best_action_rationale": null + } + }, + { + "metadata": { + "name": "RepoB", + "full_name": "sample-user/RepoB", + "html_url": "https://github.com/sample-user/RepoB", + "description": "A functional project with follow-through left to do.", + "language": "TypeScript", + "private": false, + "archived": false, + "stars": 5, + "topics": [ + "typescript", + "web" + ] + }, + "overall_score": 0.62, + "interest_score": 0.37, + "grade": "C", + "completeness_tier": "functional", + "badges": [], + "flags": [ + "release-checklist-open" + ], + "lenses": { + "ship_readiness": { + "score": 0.63, + "summary": "Needs work" + }, + "momentum": { + "score": 0.54, + "summary": "Mixed" + }, + "security_posture": { + "score": 0.66, + "summary": "Watch" + }, + "portfolio_fit": { + "score": 0.58, + "summary": "Useful" + } + }, + "security_posture": { + "label": "watch", + "score": 0.66 + }, + "hotspots": [ + { + "title": "Finish release checklist", + "severity": 0.56, + "category": "quality" + } + ], + "action_candidates": [ + { + "title": "Close the reopened release item" + } + ], + "analyzer_results": [ + { + "dimension": "testing", + "score": 0.55, + "findings": [ + "A few test gaps remain" + ] + }, + { + "dimension": "release", + "score": 0.48, + "findings": [ + "Checklist is incomplete" + ] + } + ], + "score_explanation": { + "repo": "RepoB", + "top_positive_drivers": [ + "Security (0.66)", + "Testing (0.55)", + "Release (0.48)" + ], + "top_negative_drivers": [ + "Release (0.48)", + "Testing (0.55)", + "Security (0.66)" + ], + "next_tier_gap_summary": "Needs +0.13 to reach shipped.", + "next_best_action": "Close the reopened release item", + "next_best_action_rationale": null + } + }, + { + "metadata": { + "name": "RepoC", + "full_name": "sample-user/RepoC", + "html_url": "https://github.com/sample-user/RepoC", + "description": "A risky work-in-progress project.", + "language": "Python", + "private": false, + "archived": false, + "stars": 1, + "topics": [ + "python", + "security" + ] + }, + "overall_score": 0.44, + "interest_score": 0.16, + "grade": "D", + "completeness_tier": "wip", + "badges": [], + "flags": [ + "no-tests", + "security-review" + ], + "lenses": { + "ship_readiness": { + "score": 0.42, + "summary": "Thin" + }, + "momentum": { + "score": 0.31, + "summary": "Fragile" + }, + "security_posture": { + "score": 0.28, + "summary": "Risky" + }, + "portfolio_fit": { + "score": 0.36, + "summary": "Questionable" + } + }, + "security_posture": { + "label": "critical", + "score": 0.28 + }, + "hotspots": [ + { + "title": "Security posture needs attention", + "severity": 0.84, + "category": "security-debt" + } + ], + "action_candidates": [ + { + "title": "Preview governance controls" + } + ], + "analyzer_results": [ + { + "dimension": "security", + "score": 0.22, + "findings": [ + "Security controls are missing" + ] + }, + { + "dimension": "testing", + "score": 0.18, + "findings": [ + "No meaningful tests found" + ] + } + ], + "score_explanation": { + "repo": "RepoC", + "top_positive_drivers": [ + "Security (0.28)", + "Testing (0.18)" + ], + "top_negative_drivers": [ + "Testing (0.18)", + "Security (0.28)" + ], + "next_tier_gap_summary": "Needs +0.31 to reach shipped.", + "next_best_action": "Preview governance controls", + "next_best_action_rationale": null + } + } + ] +} \ No newline at end of file diff --git a/output/demo/demo-workbook.xlsx b/output/demo/demo-workbook.xlsx new file mode 100644 index 0000000000000000000000000000000000000000..c16bfb76bc6e71c6b95ba63e7430596565e98b2b GIT binary patch literal 144109 zcmagEV~{A_vMt)SZQHhO+qP|MwQbwB&DFMT+uirud*3*5_KSFNf6S_^S(&ru$gGNt ztQ-o`z#u39000mGp7mooVq>xrDgRte|1%K&87B6|3QqP8&h&;34s;&2HnOv_(1Q#x zV0(Q^ZfzNnc*Srcypg%xvvjVZt(3MQAGg;a{C1w6#23Ugpzb312A+Sg666fsfvK4aQj}1*4+>D6J{x@K^z*cX!#_R2D|*zX@&hh zSh``z!00W|MQD1JzmYTe8Y!n}Q}L)H%^2C~0vu{LFK_RWEA%0eWEn$Gq}bg0VVEv? z9~=DUcdRRG-72X3so$)65WA6T&ulIKm))S-+=;LvIVv_BRgBVZ8m3w zT+88yB5K6gc$y@H`1gskAxx#hUMI?SX7PZ~oPW-Uil3fwcs}0H8J&eiBtLiImet+$LzT$rwP;xa3~~5QAR`TJ1w}zfd!S6M=Gblvc(l%P+qA z?p|hDWJASh%P(5HZ!gCF8LgS~fbG4P4w0a%o9M{#|Qbe2!)zBzAb|g@oF2 zEU-ubpyA-Q@^=9^Rgdz+H5qFiw`*Ha=T75>^AFQ`!IBn+!b>F(hMZ zLD*aKXf@&e3QOC>AK$cjfw|9wq14=ys&bTTxUU|1Rn8BztOpR5G(4|U1LPxhj~T{1n%hg3qG zWfO6k3)%D;GuD7u9ky$@#R8Al59oU~D-=!wHZG7kc9R%kh-KFuUL8qnX3ZcXwGf{X zCL5Mh3tC{SV?~I87SiavhulIl;+JMMYZ9Nq_|&!|59Acs#`#-ufQSpd3%gi=3v9IDw=u$`UWM%y4Of29{&c>xCAS?=jI6vpaK)8k_*bxD+KoO%6M-xhqi_tzimBq4Q~nzY1d@zQ}!f+X!< zQImI6!;oht+N6+EDvPGlA?=lvE8EwMT)e;|qOcqD9XfPSbSs z59bpPH%m=h?CL1pF>Q&II0r4$kljwIAwxt$3SJ_&EJVX@bM#^cF~w zP$KJLKnc;E4sUOhtlXnlKWGANLsXbdmeD7L{|xXlI|;9;kUrLKkU@uT9;i%rVfB(3 zNDq10<3Jr-r`;WdRjXL+>`idO$>tl+&f?Q%M7a_s=?ogmW)7yAwP zMn(o8RvGnn*2%wM>@tvK1Z4 zLGf(;+``rm4#)0aNA&^zcLIsOmYS!A1pt`i0sz4HPXckbcd~Z2Fg0~?rvLZp-&v$a z+tz-Q1L=pF$Dh&xeYMqu`wu3MEx7`s<;6SRsjYDFwHt zfj&|Kb2j@753>>-n^12t^(e}FN9@56&yB9`nYsMKh0y$aOhgEY6KCHQZ1~R7>sQmx-i43})d8b-BFXfM zHC5Xx4N}(BPPsbI+h7`XD7=BYP})^Sh5bZQ$SxS^Z+x9*wi6=q1X@~;e9?N{4<*tW z?(e=$(#@C5LdqJC1fE}5lHiD8+!yKa2WLKFaB%m;%xzy$AtDd%ARWt$P6WEigLFg) zh0@>g7tTK%P>@E{2|i}fu0w?or1xGSV3B=|anW7g_YdlQG zCy)=&BFPuOiL$-!Kx~kWD8-D!1Ou64@4x5rhq=NKJi>dd5Z#8*f%Xtz!txl{L5`0h ziqHeY2r_WIhE@=zut80!-(_Zfa1(-dI@cN6m1oPLDA+`f>dc7?u1F1jsZ5@X3JwT%_#k2Db)3p|q33y+@OltB z5oyhGJOJlXh&@Uo^3IRi?Y^ZIM4CuKKH^g?}XW%fKat*@#!! z44q#N(O%kEbf-a63WQbqP?lG_$!NQKOQOqB<)@}(J!C>)GO`mMaDd+7+!&eCvT5bU z(`d-psj=uaE7MjEQUt-2>Id~0hrTizqR&Yy=~?JVg0`4MJ&W_A(x2y%NDvx~_ydzi z2|GR~f?(*mJZGBpXMmZ|LP@yeFf{1%C&aU+eafcYK%LWVbuw+M*JZWWc&VvSJxvnV zMKIkXlrjeiCyJ9z4x+biLwEg<3uMzT*=B`5VupGM7FgJCi1Ugy?#A8LY&Q+b7B`|< z9kHvRSi>7iOBzb$CI~;Xkc^vDvYISW)}xR3E;LP;3_MhA+^o2*$p1`NcHg@mO@|4; zo$7z|u~EzAsBLwr!)fQHw(_`AMHs@k??G$#(?$SWU*+7)tDQJI{}LM}Qni1@0n|Fo zn~nIsq*$;A(0iaHq&F~-Ql8Ow4Ei7e_Fq(`psYKIp1>f%EOuOn&uC&710FSz6|4>8 z)g+wq-Epf9MD`<7@K4oD+u4pS#FJr=!qv=5 z*UYvc*wVd0p@Aj|n^44bIphdrOynR%xC)_$hxiF83A!zjV$>Pk zRPw6ZTqj$D??iJQZ2++g$Vf3}%m5_!w@ialUxU+%S6|kh*}n zhev=0MwmCoiCBWo;|1I~u2dJgI#QQ2KXgu)gXo}N=V<~0ItA0U%LvNc>A{RaF=VtJ zhc`E#AhJ~pOpm)mx$1WvGe3ZX=#!;kM0-e>N(2zV05R$jT@7FW`vi8e@q~TeqLcYAxlWz#&Q=qdL6ey=d(MFTW89MDX?pv7# zx=a44fSnUI2%oVHb=_z{$TpC|8yba5+5MKuKLlmnbkr?pj90F!tdA>|>v`}Bj7`=Y z-rGRA19O3JJrM+jg$evos*xL~mS+S-+>R=K&jB<5UagIzr2flz9vMzZ@uz3f|5x*B z`Z4K56Ubbo5eeoo!3Rp8Qf0V)4R)`^fO!{9=qpPg1$+vGhG^GF15C|gx@O!3EXent zt&qy4H3T@oDwS1CcKWh&xf-qJ%utrjvmMi!uvSiPo&BA7LG$S#)hCUxre1Lm>#lj> zDXO4xdBt^E>-QM}JK@Hd75beM{3X!YP(QYF`60Wn<38&g?mN%7kF>YRLC$d(6L6HS z37gF@z-%d^!RkBOzLM0NBb;0W*k6i^7E?%g_)Ibn4@J2&Do!bbl4J)#%CZt`xzFV6 zwuJ(C<#pqjsWJ#)ciAW`$(YG8x6qc2H(x{r*sByhnerP14h==Sum}0mI*ceq0y5>5 zZSGkvqIPT_X$-H<=k6U|SrcP^b1P^1>;cE^e(hQ_pGavlOL!}^8gw|(?PP!l2J6a_ zjWDr@9)So7I(?)PbM$~^^!#%VR_@&gq`gxXAg8r431U6 zv0wiLjUfJ-dLF((m#UsL70w$VdItl*&bF@Yh&f8R>X93zhY`K|AKTn&k3!TDL#N1i zz(Ai?KFUB#y8uviH+B3PtLe&mKOlq0Xi%u>Qv!u3ZHP_1@;ukCp=4IM*wQe84Em4^D>ahgVecQb$Y!_M)tc z?e`M9#jD=u-81dBTz$r}jc~5fHr!4ljkMQ}zJYYw(he=+oO9O`vB~6qtR>D~Gq+#7 z8q@7QRr%wX954QS9L6A<2wMnF#C2ZYn*at+JUuHrn!kiRcR==Je^BaBv}^-*Fx41s zVIh7wL-*!tfW_mDUtiv0cHFGLAp=m*9KFGA=bkz9J%<{{UD{rt=+FR0UFh3~(-1X^ zICadF8yZ1?fu%V$D2EaAwok<`wO&1!JH3$0UUm!88Ek#ON5?L1CjupXlpm-TI4i5u z+VQ>vFzeZyz1<)9Vj3!H_$$n6bGzKDu+Hh@Jw(l#26e&Xw9lv~Y?oC#MQS?vZ*8wP zUBPwDe-{PqZ~b>DuD-cLeL0lYI%}%*7M{QVlNEru zkFObwB_C(v8_>SITwcw-PSn2E38bnnxw@8RS*d7~xOfs|GNRE7Yn4na@%8NijbZ?o z=&rxd@3B_&XVtzdZtXU5NnECmAeB<4r~JfcODjI1&nEH%>>)jvQKCd|3>H%%b55Gl zg>Try5Jslb1WX#F9N98OIBp~Rg)sApsusW5-D+^bD6(&;o?dm`7@G4DOx$dgqpaX4 zm;MqqWC%7JyT0CcE^q6y6}$I#iF$`sLdOP)g=#l+?#`EOGug1@YuHae?UURN0^@|1 z0vKDGWJkY&O?J}Q8mWKzUT55@Ms{^2o5v$Hj1m`F$s$+X;QCJ5-eaox_g<^-iU>|7 zex1$?V`j1QmK`uQn_eqJ{Q7Q3-l}(YDSj0xSOWcOrQ87A#rbp?Ra}%sXx?R>S=-j$ z&rFlC#1qM0!glLkzXp2v>r`BaHG%o^KcEDbtG>&9#okIjE%BeWOnM%l<7heH!ge|a zbD;~lwON1hL0rmH#cU(EmDySj)xY|IhkcuHB_(xl+OUv;s?b|?=FRFFN%63!`YHt>^5i`0qSdKKnCyXEVEa3uYcs-$($(pSzwyJ z?DO>0<)hqT#aa*U>=lTNXcZ2bSLO1Dp z#NcGdeCvYYyMn9bU+TD`TgQmOj-E^d^7ffT#m@ENGLf72^ouTSeI2cTBeZFBK>~<*19EfnM55)+$lB(`BnPtx;<757&c- zhGn8~2a6Ul-u)G_Ygkw-Yc*?}nW|;1=Vn{X0Co&bHw{}Cnq4*TWz3YO3oy_3EvvF2 zkLHbXy(BE)L$IXL%4N2(J8RU7FZ((NcJT)rSIrn%MvIC?H2Invu7KWY8owSt72{en zM>=$yFpgyDEKsZ`@1|0CH{*7@rJ)2KZPBXLS2X?0PwNWlttj>o@f|OZ#GXgfw-kbn%R8psNHBqr(MDoXm!uj6Zzp7fDa$sr>&Hr`UNDke8tP zzo+Q-{0hvv99~7HQ*z@8H-t`Q(pVg=QW1b*FQ0H5n0bv%3|mC0Sz>$uyjt#T)E>3; zDR$zp8J={?AUi}`5*%2OHCUpG^CJpWN_`Kx1#Kn*&VDM?u5gjV-%&wcLSC-4+y@<1 zr(qlzmA4%t!0q##dVVq_`8%wUn3DB=Zv5sY+@8g)vP1NQ{8D$HxoaJ)8$| z{~Yx7d*i;tg9P&>8f09HmPoWhQz{EwK%?DC3911cQH{B*(e#3|fI zHx$4ObHSuxHt%Gn+f>uo0I#Kui6`o;4Sv0?-heV~c-Fkd(&Z4jZ8@m>Hg?0dPp4!0n(2V9*M#j^6JhN= z7qCfbw8fa^fWCjDA=@4`?tVqKbzFYRvQK9;ZHZ(phiEOAq~RQ?;hZ^~sXUyyNV1Ym zw31EMaDvis!t$rZ4bl3VtYL-Ds3zyo6Rsbohkk46`;8AyKPG(#zVIBM2GrmSU_(#9 zxx9=8tPx61fgsGT?1GN^;pre;)8iBZ zjbmR;j0xiC@LQRu)drbPW6Tn9L&IA8KqiTUA)dG4Rf)auA!0QiHXz~DFoQhpREW(& z#DN2LsmMi$PEV^)m-s`BSyvuYBH}RY^}+@l@~UbC^1h3(4*xcWd?2uL!SR;ht(R)nu9 zK7rC3i$yXRdAHJWUK5udePjI~DWn+Z1MXMg^|jB*;F_LCJ;)AU@E@Y&hV40Jutmc6+i=)aJ*RkU$#DgWr^nOr zIh@5I+2?Gm2a}R)-(qMyBOmC8SXzf+yA66KeTFuLfF5FO085kH1tKT7$RKN42jrv7 z$=~VOH3m~i_tB%(feMX*G}Bamc&KQOHsRChjVE4Yj9AwP z{D@Aa*x#lXQX`FhuC*gG2Q!(0U1?S--b*Kr70attBzQ;zIbvfgVoFYo#y~v6_fVG# zx3|;McqxeBW{n&zrB_F{F)$DI`!loAJ*lV3p)@9U8(%O}24VwayPUYsMc65vBSVUp zxQ`$Me?<3}p9D9awBs*X#B!=Dp*aKdoZNv?7Lwbe03-cg&rZ;XK{J9F3&OAmGj~Vk zEJO^-wuec?0;4CoY4X6{c}!*qwm3Oxjp8-C^BIl&?N|da$q;4PUNk4L@{0w$Y?#r# ztKxx;^r~uGnT!&g`TZ)g*M8}Xp3UlJw=1Bh*G+ZtW>^q<4FdC=QIZ0oANtj31}Okn zlobyG!3tja%j`b^er`T^4QhW!n4wl4+|n$|vJz`3cHw1>F>N8Lv%;Vg&}f<)2{u8j zLv+B-TE`^#vn{j`HZMV`2!>VUtg;rWwDv{29TF&Wa2zY*Eq}lY)vAPQ?*@`t_WhIl zcVY*2+n3qy)$YvY#jbs`$1sjdwBpr!a8u~bj=f2QeJBbuZwP{@bc3+icY5#>3t#mS zC+xZ1{XMEm4<@>X?D9}T*ZoU`sz_ zfQXEek!V*JK?}iy%-WuRaUU19O`Y?2ujlWe_qxBx<2v$_ zsfieXuO{i$qqaycS_8V|X;fNyE!P5;sN`o?wbr}41KEm)cRTpq2i|ENoD;nFAX z{^XBM)Q?Tky=+tcEOvi0XGlde^=4=7UuSBTIB#|8KZn8n`0H#z)u5fWte;GKqf*OK zI~k6~E$eI9&=%?VzqIFT_LCo1>hy_j%GlSXlPE$vvW$kSQie7tsqPfs>_(g5xK^)V zRaFp{W!XB~a2u2Q>~@o5Hky%4r&pO7&xW~^nQ1XNK!&CMk@mD2@x(EzRX*&xbA}~`{4opHAWzTAV3VPQAa=OD+zf8mO}yw^R4q>3M<~n zumtF>n*g};0JzP7wGTqGr`>bJwgIuFBxneH(GB&eH3&%&?JjOg(ds^hj~9Vuca+-d z<#B0`c;oIHiUqqOgfOp4->jrPg%Jn}ii}5A07wqA(ASxc7c~Z9qKo_z5QI}(SasMy z?qi{X%a*uP(+XW8uCs$v-f0tq&#E2wTMH;Jcm!9A93k`6J9S41N({CXfRqUD1{Gr8 zy$bruB*0?=8y{xb0~TpsjM7pisTPrv1{1k}j)Yj5k{FATQ)2>7^Ba&34#sbsxKW;4Jophb|Xk1uIk$&!TrMmpcughbifWlE^q@aR^gpV0mM z?H*Q!oo^+x6}+w-x3f!@0JPx&U27O=A2)hke38R%dr+s4%w4|1Y!pfp_0_{3c+EZ;GKQb;L)5j2ud_?Fq+JHD~ zb38MbA`pG*s0sAx%6@88$_9sAS#VzLUV?=?ZsE&Y>EC_W*zWR?3++@6=!yyUw(D1E zD7LaD$mw#jC{LxGeByvM5P z&{IN#jA2hK^ipSY);z0?#kTLcw^S8J>tqI>1$|g6bB^xFvMV0AJwpx*=&{}V1~m%} z?N|Rrn+))I0{Toq|tP2kj?d}l$3lmR8JI{$F0A7;kt5myi;=0`kHY{f82CQ2! z4Q})1e*X|wNz1S~!03(Vje;LDYuBB6`WfpNo7b0PQjCPzWd(WX=JMz!P#j$*UHOe4 zYc~VeAmYBo=j36`|0a_WyF^x68DLpoHwO8_-mf1$z4E_4oMWoIbC25pTZ# z7KmuGbN$*55olS9zYA5XZA(?^Kuu4zqM#w5*{#Ns8k?HI^qF}jpj~C)f~O^{5NLRV zBLX!Ni3jCL04+(4vLY-9Xl5g`!{VxzH}6W#T0z%3xv1lB(Kc0lO$_lS?RKczVw+b0 z^mx^;TX8ry&=MC%`F4mWd~KPXIJ`|(JqD82*n1l>LQOC+R+Yn_^11Ws@HSF(kM0@L znQb>4m&C7T1M1@V($1;16mqjBxY!hVLKuw!#2Qs#HtB@1%^QeK$0Hh>)H9DVLsQA> z5c|sgqD733C|3e{YzL8JL|1p%JNmKQ)b1CJv0K}HceuyO{H}*>*T#FI4DuVUWz(}B zUA#rOmzi`M^rPw`Y0gTpD2dT8O>)rnism#WYmWxv?zMp)k0Ct?*4hcRn=!eOxX-!{ z7q~VVRh?34pWY5r)Xd(5lJjd8Lt9oJ5cy$X}c z*2`(GP7@l_Lz8K~>e&e+y1VcX2l=r^y=XYZ<&{j8~#%zq`yV7xT?#>4ZPE$`3Nh~}>jE`X_bG~F~dt7u> zqM@rZEAkp?b~9mJ+2?0ZGf`Ct+rg2`mYYbOrl`|Q9(uFNRW~2?Jf|PQW2YQT*GG&z zchQygktVqWN_@)zzTfJjzcDrl%c*p^f{l^y#$>ci?yT#D;!*w0TrGWyKI-U-^5<5q z7L8O`I)RL~w7M2oR!CIt=VHx~VHLzyM7q;rVx=>nnjU`&p>~&#h@W@~^%@M##S}X= zXmvt1A;j3y&FXbyQ0=kmuIBF+pMl!9b&s`+s=PPqJLT1rl{!7d?orGbMUtriSRh4? zL81#d+zy&d;boD3KFL4P7nM;IIyuZ1WlLO4MRav;tsJ=YM=5lqcr${!yXWk9l0u=? zFnUc+DRl`2b7&)}b#X}C+06=xL+}WOXk?W#0sAQ$)CH><`5=6*4&Er-XbV3s8t%rP zP&wAV?^#1``ut%F$O-CS-D?P+e!i_CcmsWTr?G{_3lTO;@&x1kr4{EWgUP_CRX zl7c3_IFRHl82g%OLPe0j*7@n>^>qYV5;N45Wr?Oy7pCnlZH{@ln$4Dw43gqD)fJHM z{d1@B0j@@G@Y?duKHJ{Sd~s=#=*GAK7+~mJ?-&Al`(t3{#nUHPPd?a5+2dpOq{8wi z=$tISI$T(jl+)kk@fG{n>U^M@itfZj$q(;i zM<}!MmDS>z+Ph(=z0g~kAryq@ne~={Idm@d+8W^ecfaRH*BI37+41jWOwU&@L4sA3 zg1+`8{IDKo#CdY0jcBzXtdc}2>LAIh@b=yf^xehb-bhw7yqywp^BE~~Vdw3K#xZF5 zv$Y-0SeL2(Yom6J9c6z_T(CAKQf8aWhnCBxs|_Z?@~RV7ySjj0pIk~RFW9>0)~dRB zN#-MSL!6RsfPsD!GR>_p`jO_1*Y%Oz>a%B>4XvOKavZeJmG#}cd(yDS9=3UkHvFfS z$Cj$U;7Dsw<(k+Hdi?qrA#)qC|GSt~02l?iU}BBh&R|iXkUT7JbC|sqBDYJdeOjQv zh9GWn4*|5g)r&M4A}gytriW zlYotqH?b9nJ>0#1Z-bb7S7Lj#Z>7(Iiv`U2lgq)xDx_V7i8rB!ox4v7&HYQ0+^sH}3Hk=sV^2c&`hJ41wVj&A zP!SsnoVp`Rwslq(!o8TjGWyz3zM|zz=^%w>Dl>G9jwBm#a5l+QCi@7pM=ffh-C)7V zrfRW2431xv^|-6r`s;rMowX&bi(QY0;gQEE87*@jbitf@tn-t7X0RG+Qey}PnW)Kq z(#2Kz>Cc41wvb@^uX`qvSI?*mwcoKMiJhs){n9y3V&1GeO9vGr1kp>O6jLTGiLa@_ zz0yBY`lXD0CUsPeG$j_Q6I8x`&FN|qVAVk7UBSJe?7y|_LJ~9cxz~{Mmeh7!!pC^V zV$9D|RRxWv2_v6q_tjj-qQ@rN9xxVhD=dE4D^)?GS<41epozNfi#Sddf$PoQ!$>Q2 zLGx(7oZ(&IL*5pKNO;!*JIOoVRD`uXFTVdClnFj3#2`BzI`SPWEtBJtZ(lh&xB(jb zE;TeBCzd6Pl&edbU}=sRsu;DIyw^KNbBsoyW85PV>lqGPM|%V#l4IPX5$_ldQ;Kzu zMZjY?sv$L`C)+CLSaZ(O9{znZT2QW*@wBl5;i-tLP6e+P+lj6vnZK5}JaG9VnhU+i zo;C#xmS!S2J4Pc<1uPOnlvm43Gf_s#N2LCMzD;RdNxSS!d&=p0jt+fa^)mlSPBs}n zGgzbLNb7Z{?N_|nYjQFFCF&uy>m{jlHPO$zUKfq+YqO<*Jce-(M672tOdahJgJ{oi z07ATDG|U~%F%t2LaSup5BSpk!H@>5qVa@sYW_B1x8fPC9V6^H7(PSi1-yI<5-zJ7I z`FhK51v;qmCl^IP{@m4<>u~}ok4{wNUA&$r@s8fOfKiuo==$gi1v&JxMJBx!`{(v0f^?L_iu#7d)0mh=XY1X@*CtNleZK+ zR-UKp%miCvS14thIfk8kC-jaC1R{q`N>&TFFlBOR9A!(^@DJQ{!5K< z(h>Bt9h6Rh(?8NvwK9k{Hjx1c|4%m^+$)C!Ik)BA;0yjpeuk)@4_wA+^>WT$t{#)S zL?+{lE=@K#qVYe%3SU%o>EY+DwU94V0xo>jw-gC#4V8ge!WJPFv-;SSJ&`cd8QsB5 zzmiutBKCrn2iq{hpn&&Dh69HDzu&1id@v}vZH9dBAS;Zy`;^cS3K^x&ljJm{t-{Xm zQPbxpa8^DYf^f^3icrgKWEO@RVm*Ul>1dBo#5%?U zSg~w_VeM#-aKtiS$ zWP}<5@x1xW-Dl%Bw=lD&t99H%*z3-#w6(1D^c|TEpG=Ar#3Aeq1 z2&xiKh~SAE-iecOD7X+*luDdAx||1##-C0gqD0|-JnckbW{RVpGF#{$EvvkesUg1~ z;P2#JUwKUS_eMU?LB7-`-B;G#s3*a7w>J|U`ArDrY~Dw;6Ft~<=Ux3z$g22qf0aK5 z)w9d`-s4!J%lSr~(}k@5{uJ+~5i<4wo>d`$f&BpE)kkluXR7<{eh4y!TxPMvgqfQ| z5^Su<%AKR2SWtH&bA{&Jf6x?5Hy#n`n79;;WY}hIGkY}>X*(8=Jq3sf+rRIVu0Z`TuthL_ppU(hU#*;2ZLPdLSlFhVGVj=Fas0SNIQAId$GHm;fbAf8-7z zxbmDUm_&Lyb=$@lRHz{lBAwWFdlSAAz0*{Bm9`YU=YSt)mL8`sTO!UDP_fK<@ub|T zc7nl9l$6!})`mD{HW`h@oi7A;2Z*1lX^}M+QuCk{aH7qYw1oNt#%KwvBh~fWLc}z1 z9;w<)Wi1miatP^3TNBPu0p%)zHWekD6-3xe0p%61(K+GFDLI~lG$dc5`;E3HiptzM&D}VfL8mERDj!rAYDlZ4^jrVK0m|E}?W;U$t zxo7GPbbC<;lckZW{cs*{2~>?}YsmZ0RdJZ`pQs!#V2-i=)Don|dZW4$#~$eMOm0(I z?TS)SM3aKcyGCADEO|Sg*q&TJ5k=}-Ogw1UyzvjT=I|;&+T0+tU4bmfW)HMEzg!DR zFFK2RE72b?EhbRfjzBhKiwRVjW)e>C!tFRg?D9`ki*uCbC$J5f{E}ZtEVw@3E8zc* zReez>eEvT~z=(hN_Qd}o1pZH~^qov?{ySoH|C$+D;D-8#fgiA6g@KDMdx9D{bWzFuyQKVpT3ja`xP4N5>I3wAi+*|=%y zGC*K&oZes5c_^Y_vW_{}OStK^i}Jm=$S=ws+f-Pk3@@DOA0lW8Ln9hzNMuJ+J!Ssf zb5vGCABcAB^ zZ+~zCyIy%GMx<*+#58@ulYzA?`fwqQHwoLJj35L9__oxqxLAku1_H9_Pz(50s{6ZUmzld@v@^VCHg~_^!Rpxl{|61$ z?wdF0e?7Ccp-7UL__ao&+GsP@dq@&{ z&12U)fI@PgNyO^2cE9xVX3O&y50XzgDOXv_)L3qZCeI#p!H{(Nd9xTt=gDC%H}MGl=gkT+4CMTaa#E@Xk|wykHsraMQl;r*%QGLE@FW-a+G(#p=7|P|*d-;ANsq?j$z^8v^=3A^PTkuMXZ9HF z57?)-fZ1iZetN75)73XZ#kY%YOe7434Ch_vHP;8zQyJ4=rfz5BhyYWhQj#Z(gXu6z{#^l ztl8advS{;H2mu=w{uSc6X)jQB0DkvsdqfkB{tZ4q9CLcF$`a{!nkX4 zgGy1W!}CYUcbi&vz;Kx#-Iot}2MBw2J~@!M7c9x<#|*w+ZY}x5&<&SAm)Z0baP@S| zkm`pt?x791{!d<6fEXljkSM~$?;`#rzbuFj>0T`)N33AKGSE(^z%Id@I?#7%JeZWh zoQgp?NSG|>OG^JwroitUfkQqBTxP37IS5=96i3gXb5CimgOqulch_x(2$VZF_77gB z2vj)tCEhKzC{!AEjPDJKocl`8&5I0C=w^;nM3d5 z+Na&Vulx3AZ3X>5Lfg9rJ-D~=ZCB{)HtcN|S;FAwP3NnwGReOtMvZr9yKif~chAt< z?s_->V>$E*{x2;%<6H00*B;n^J^a=?rso!Q=XIrL7PbhTlKj*4HcOkb`_|TDcTH;F zx31x}XYg}pbd9}L$z#|0%D3*WchzI(^&h*-omUy*YJHEsKE}s?E%a*IN%#nypp!ip z-Rqk(97nR>2k!e7JgyMJbA%!|?A)D26IcZ}Zfak*4m>-=cT8hm*M(_uwCnyY^pS+( z4ttRI(BDTM-?Lp-wV>Ot8009;P&?OZKj)S-PXdf=;+#0GncyzumI^Y(|E7*Op-fgQ z`^Z4z@3?dnOI~@Dpzj;$jKs)BIOjla0#8GtEU~I2R0LV9;YXmP%pc42LhM~~T_>`} zPQX)e{zX?hF}$E%cU42~0t?gGD+CAa3#l~NWQim~a)fD^XTJb0xiZ~rGsS41H;kbmE<+8?mVChY)3g)gQ zRip?*AITP6Kl3!aG0)@@tPba{t<`sAd~~b<=&n6*42dH$V`34{E^?$^kH7Zh> zS@ne|=yTHPbBF>&t}cKe5|o?r={z#C^3^l*)zkCMnFlxvKT0v&l1S3ctZ2xLsFpx+ z3$G86POSM<%o)td5oO-9OOVDPQkBdl4UtDX;QTW0G_&Z^7&hY$AwOLz^18!UB6z<6 zxA!hFMYykPhp+uG+dd_f`iEYq3@tOsH#qHf`Nr0P)36Jn^pH$!?!7m?9Wk@MV2g$eEycvnKHh{_7gbk~Tqytsf_V6>Z!<23}3j%PFc@xd&?wBEG})z(2P ztCNlv7AC^!k7FZ(826gLb1l<(C)&qT=x?`BfjZLa`1C*{|JQeU=eQLct zHvPAK%V%A{PcmkF&YuAC&c!t&T`Ola~b7aSNg@7Rz z3rqxwIJU}pGesb{rbY8HWI!x3gu!sc38ixx96%eT8vv&YDLBftgiae`vW2g7oEtS5 zBn6m7XOF~pog1CZ;XTqbDAzp=pR1N=&u*aS-s&;)htY{5TSX)pmkcw7fm&p!S8@rf zz&l+<{<&*w&L*`2#=)MHtAS`qOXwy???>B1?Sv50z45PB!T3~sXpre2zn$T?S*y%k za=cy(P;@Ce(wN8qG<|}LZ2A3}1zvUhRi9Ro9*G1g(orbltW)KpA^C(z+W18*xB@gv z{B;~jL@7*kmYD@}RS;}Jx9kqu3$$!7DAJ-e^g*XXbru8rC}u6-d8E{zhUf@2g`+eI z0tdpkT45-cf-twZ9>xG;gl}{AWGG0en;uPuGG-q&q7-sDY18VUWUQicM&x&x8sY&b zrI6+_&Hjg~X{}yaz0gpWQiN$gkgCQd(a97x$pPhqNQWRysIOJX0QA0_##pz(B(XN$ z7)io6vfi)09_btaf;>I0E@qb`Fx4?8wZn#md;%Qx2#TA^Q~rh2dk8Jo`b<%FAT}l! zn}z~&$2c3H^zs@MvD%8JF`s2!*0!PI_yJ&I6`_Z|&u-YRgshzTra^5Zp1by8 zv`2LmIi|xM=g1aTyf?wr)&UU{a|j{fF|f*T*|g~@*w@-IT|?WvA!*BMOHioT6pC2b z6|&-g+jH@36LP8c_jn_t3P`vXln0|wOM}DzJ*Bc(p(W*%TF?2qn@lZcsgTM@He@SP zv&o2Yb;hVo5-#|I3JzF5ORWPU+}Ds{nm>U#7h?lJHTq}+Qxd4r8;!77ThYE&grQ6h z!&%|_&P8fEnaMnKkOUxCmjQ|d$K>m;BwR|A$p&}niVXn_Z^qKa_86}S7dLd@|D<#YD(E;6rG;4DDVwWzH$L^vKNnWo8GVH^vvL`Y__ymsY{M`@$>@ri@@0YecLMua zyIDP&5XUA^6-zt^)>5=zN{ltDA(ry_)r;=ngjzlPD)3}F*3|AQ-B*SwMDAm(41~K= zAYe;wK!zvqG_y!pl^IS&+yGrFyOr#y_g-!X+h?$WPI{Zf$$qSJ+N4Q(BW<}k_RHfD z?=E&2cpTY8I7+>QN9Sirj^fSf6W!=6}WqFMN{;A&+*E z8yHk5Z5VGpQ8{0(k2HX5Q+u2H5$(Elc3ZSXmANO3%G$9qr}lC~N6_#t!Ex%su=U>(sQFWnu(YUDLYE;&X6*YVbc3^ z%}GaWTDzrzD+mmtmt8>j0*0R6ip1%AHHQ=2#Zgj#RUhpP3nyWd%*z=7Ya+l@^bS7F5F? zZ9uYeldFPWkQParjDv&2LP+Z8(pjc96r*CpP+?))wEXoPbf;jN_%yyB@WORYdvgsUF;TsE8BN1JGs8-IT=nJ$&^@`zG8 zb}N_r>gfY_tjBe$NDuz!6aT&rmYjTQIjI;G7?#v`ZANTWP6K2kiK`4YIav-6eBvAK zQc)e8pNcmb$A}9rBnMh>ctkF{wa$(6aGO;h;~8=ZJ&Et4770mzj0$!8FfUhJ+~ub*`$g ziVe>dwy&2>2V1KScY_W$ZEeQE5nDP>&6;pF3QDWSiMs*1XBT{5aA+|!R#*srdSK(9 z$QW(P;x_p{&-`Q)e=ZS;&g(#tP|LY3^Pw2X9;1nZVz$K|rLW@hVG8F(8a=l+TU_yr z`Z9>hW{x@XSl`MzrSyS!G0HZ7sj}*%5nM;CRmvA3ORO4~EAr19sU4uda7#{cIvX*i;%jdlGFlfFnW+td$O_MdOZ{)@M zT(gb=@U--+82S~^L`Y9@S9YMDF<>~e&)5DauqS*5Q1b_~T5V6}G_fIZnP84YrjwN_Wp`1u@uiNy7x}MUm>9 z3zh;CQgvNg4TTk|1{CU6hXhgP>trsWj%pPnv5*HXSj6YwN#Kr-0_D(!tw=CzisUOb z)|{h1p3Y7o3woq>Lm^6gRAiTl+YqKh8z0f2$WjrBsfWWJms1eOqJ);ffk;J54wx2? z4Tw@vg(o zT#Lw{H_@*Xxdw%Nx-^s|+8ZYBqH5Zxd4{~c>NJSe+k6T;5Aot7p60r$&v1*sO4f*{ z8bb$r>WQ+43=x0moz2$SKqwl`sv0f3ty^q9B79;ONS}*9#3(x)+H&!JGaMVeb?qTCi-3wr$(Cjn%eo+qP}nwrz8@ z&DFN;?$`U=_df29IPtz_eN;rvs98BPYvjn0!t(bIO|3sO7;;!UpI7fW{_+wAHc)r*YNHZ?DfD@YW`XBQ?*hw zL=C0a2bAl#dmR!h&$NAWzdO2uTt?X7iJZ>kD#RUDOF!Tfdr|l-Z<;B4E?k9$$r_YK zoX+RIK&y>}uXk{9^T;IENARJyV<^wk+OK?E;{up`Slq3GI-h*gzzAfqhWmDsy47<9 z=&Md)+}!`#K)PuIb4OM|e=F>^fH~8nCG^=D2wnzUwSncpY6<2ROu~lNb*W@UL|s^k zpXV6|c{2tdkEqV&s-PNZ4fEMRW6RXmFj&2auVL)7it3Q~*BsCR=c2f5pjFgs9)&gS z!Lam1`^gdLt(t?n)(dZ*I+W*7;@3G2A>-saH7aIaThx!6prb{#NThT{iuBVWETV@_ z^c=n7N}`JIqh!;3^Ox6gwpqf~({bwelmDAv-=Cm45X`bzl(_~vlN69%Q1{ENm7Elu z)1d}w(2X?~Ks%v~2EgEmc5}j1n@!6<1QbQyS!m?55KIkem&vnXe#Wt~dXYr1+EY^r z#HiI%g)}U%t^mPyZ*n0GKNF=I0Go5I0AYOMFG3o|F{=RCjM8OixNK4l#86fuZTA7_ z{zJNk^qGd+f1?c9I{Z-s_^&lZUrKz(jbV@OchFAE(&W)0SxNGN zVim^PB61MfPJ`9+RET(1#(;p&_3#w(KCg(t8WLNkShtbDI^x%G9s@xQq?XKQ9+;s8i{W9R2GOS}M9l{uwm=F0<*NeOkeq;W6uM9l^=9L%2UE8XSC5Erz6JU<1JGP9W)K*XNJ5hT)Y(e}}TJjcz1 zeNgwQscjWWslD_#IiH>OzQlf0>cal3!Sem^{071KYoqj24f0x*GPH)S07YtWM|SkH zYge8Na>i6F*HYJU4h#F$8MZg`8`rtLl-C3*qjv}E(9U)wXBx&uDr>r(&My?3GweI#R9Cxs0o%nB zfe?3)3I5l)&i;kan+uA}?m00k;^F?vN8Mu1=MC%)&1XIL1$o2C^6JS?(95=_Cji6l ziE(rX=R22-`P;W4UdCYVMfXa`nfyM2=RS@`Hxj*n=RZ*1@EB(ia_TL9|C0rd*$93& zU@rp^Sx(yz{QnIT6TNhHj{HKzC&2$dF!BGutN#NNFE36&4Kg73@2OFCY&!6VqiwiIRo9KZ^>>Bb+zjg<<;k{-u#C_fVcmRL*T&F_)qyGkSyuKth5o+wy3( zQ0mZkmo_RNaB?_e9dzf&7IL?%H+=gyHNzg)hoYlG8Nf}B6~yKX86;hjpVHHKIVBWx zmr=4*qmn#LiarD2aKH+OH3&fdX#3I0*U2RCY%{FiVY*(R-C$242J=n^CbC2@P#(nh zTkf?;nENQ(eT^XZBg^9zzIRX;#r=Qp!cpdX+Mi#286vFz6<%if54>EWvFZ9NGV_HB z+q5zzh0X9{3}Hn|XmMRK;e4!-4!jcin|sB{*W(xK1?6UvJQGsVTKLC>Zig!oy&~9K z4)7;wIx_6M8POa!hb3zgUSDK6A)H`1Hzc0A@=k>=iz@NY38eW*)|G12jR2j2U_$w8WvK>xOwtx5SI%Z^_#jF{0IsV7g@C{&M8x6{mdzpN)G=_g(}ounm^I zvvAri%)1v$%IgZv>xngJfguqI5?Wad^UWcpfgIT9kbaG8ZUofudzA5mSGGE-(iei^ z)1?yJ>v4ssrk6j1`3cyk5~>VYm&{&hE)Ph;g|Y3^!|k1 z?j3@q)l1aUa1NWP;1$D^*U((c$_5+45qJpXt^i;-QNKcC7R3@FS|7@!jEY|NEOJ%? z*3&8B*FGBU7^2M4w(S!hdo_tcMj7Tx0H-(ltc%@dM(cP^8uO{ABy~NZ)XLnw2T-*M zy++xwX9hCg>bY!~XtZke^lv$KjYu~D-9E6n8GtLQd==nRV}DuH-DQAI%zQ0SXG?${ zn7JyTPF8H8GAqHR=ekhI^fH9T+d^(339;cc(uodb=ooUxLx@O&6 z+Z&x;E3*mYYafmS-CW1I%m>*kw=DAQD$^b(ZSaZ3Yf=xpQX&Zywt~!9F~#Z#mV<;@ z9ug**TM8Pq%$9o%sY{da#e<4?PeKmlLr3I2AZW*>rEx3IEZ@<)WXEPJj^2?eKf-p5 z-g2h)h*1=@7U-xA$j$uFt1h5I;8Jl-k!FI#Q2I3xlF67aVHCc^^;BU+8jP@6XBkq2 zqayG;2-p*2I?NLgwP6)qa0qBvOyPazFtvVJ?U|*7>7AuP+n5mK%D{|#$KJ6`**zPx zy0%pgoSH}}**uhM8Ksx;CWmO6bmjLXNRf0x|JQUEx>OMUV0Tn1p;CfEB)e6CsYKz}5UF6Tpv86UY;t#2(t9l!#>)sf_PAN4 zRRMHJCP0?t8v`NSjLvz=)SJRY6pK^RMd$Ng1LnAqbtmxZWPIrF!GNE4s632!E$H{rfLsPt z$dTwhw8t81Aqwou7@SgNaI`>f@B!fEhGs3_8-FsrlsIVEH$h_P?|~5TKHGCK@JCJa z=*(7=_o|BrB*ckbw8y0iid32vGhdm(T+a{mXbuu|K-jeUI*g|%mx8?1*1cSpy{T3P zTkSE@;_byPIs%Ch&a{!9f z0F`Z0<987izOp*Fdv1RS+CzVQFvt+FCK~_~ExEf;+EaXp3BAWxYVJEaXHNVCV8mL8_*&4CihhZUouvo!O6Hc?c@H}6R}m!sRCqW6D}5G)%82I#DJSsO4X>& zqR`oBZ^X^ox@$tZl$u>RZkKFv1BPXFeg`@#QLufzHuuM?wU zptR3`@I{^R37`c9!POtVUollaH16&Tchx$b&elVMdbhemMvL0$s)=y7vp>zXv> zs@QXe(jOluedsBxWE3eiyJ!G~xoFntkE3Q-!DMP*i6n;(rG6-$aSOD=|H3rt)S1q? zsYz=ZYLliYE~4C+qqNh97Zdgk`h>=;fi>WyPF?ty#>mnSR`B}R`44=kS#I$t7J^Pa z2%ElcWXoX2>Zuq{khW6>GU#2lE-alIag>|?4vy=)xwJEtn_Hw9{HZ#(TAre5Ry<^X z20vdW|2j`d%X{)#&${HBsfa4#v4D**XZ%+w0*(=mf}!ypK!Zl$pA}TehPhiebz*DT zwgrrgb(g6bhM-dQ3Au5dY65_UbfG)=cBBfCtCi1+hvI3rwfxwzuxLA-5_`WkX<)Ry z6fv@#MM_e{;cAp)jqB@ze+LcA&?R%%X_r)&7>f{6G4o5t(F6w`PqTdI8#suixUc!6 z;QYhzR-d;Ze)9qN%dhj0z6_@X(N=@6Wx)@b_P&xBt_WnT29A>H&IqNf2A+Ztojlr0 zAa2>+mF~6o>{In4(i6A}Xfc+qyBlMqfuJWHyx!PF_9?`(G^!ee0Px7aRo^3C7R~`X zQ_K{$gu3DQk!+I!MK~Ns`dfrwBobgWCmu*?fwwoY3mb?APz-V<_9B;eaPo}Mgj^qT z079OI{cQEyJdg0)E01o-=i?zKPezA`VyCga4+V9BR(gb z!iTBUF_QPV8<~^bT-=!D!`q#i!HrWg%a<`v7Yz>RyA{0c+8t3dABh#Z^aH-y(2{1BVyW5Bn1ut8EEDws7$WbVbo|j3h{Vfd z@b|@|wnx^3MhpRUZZQ2&xdlny6NW3=F)xd!Qilp4TuBD@dH;$-5hETzrrxI5g%KTq zgl$kngb|Nrz#&U74qUaQ@;+=@MXfQ#Ioybbp-8QvHmrYR=S@`7*7Iu z7y?IX`kL;?RSsm`zAi@ccMWYj3>l|iXAZL)+VB%cPK26N9F}lqZg)!SWmf^yJfJ4^ zntzQRj=kb{#QFwghUQ(B8%<0D7z63$Od5S5M>Vf5o&lhAWQ*>hBJT@B82=+63CY!M z%&0;z227&y3?6aF8(|azlD+q5;pPw%#SRRcj8rNa2!x^mL}7ScF43}?ge)K0z?k-E zP~r$Rx-X>w&XNqJ`uK#(RF57_zI!0BpX*absG|#W3Y>xjamJ{_^h2(=*rV_hlm_jc zegnM|8G?8mG@mjCP(W~T-|w?XJ2y0-?UVr{1+0h}*zKReZVK4Hj)C$aeQm7hS=drs zu%rcjN84Rz3~4Fg9K)eNn(0U2)Ys?CCfm>iX z_~26jZXKpaIXqiPLsI`2UWjh205?XUE8e9fvU&xfYNsu@G9cN)@YBbzs|{#d?I7%z zpbwCBUr-mR@NDEqT5?W-L|~Q>GSI`yVqBE$-ZQc%XJl-2D&a&)XSK_lG$Aa4Y?C{{ zlHgz<6Y23P!T9=Q!6laM%C{ZDf%q*%6y|a(rq2(#v?Pq$2Kt>|b7PBwsHHBQD5O3XEMXKbz8gQ+;ttju&;9}gp%2Y?bl!087TR?Sv zP*!3F5ls}VdKADX#fUgzWy_XR@vT!4@}@!t?*Ey-p^kAfV(_iOWc5JQBe zC|*J3fQMYdJlJsNvZM*pF>?us-I*55>N>zYmHp`OA|VX%>6%e0fcR8Wo9_}A{L+A2 zv*~=q;LPqt4a|*wAqOL3gT{?cU>SB!Yw))lf6H-6Vd&h;qm{@fVH`g^@;B~CBKPKaQK5? zg;$=`Frvk{a#lW&{(s&M*XtwkG#mebxQ!HZ9sYT~{HNPfRp%$?`W^p*J1XKOxX4QieBndIY#EVZz>o zSsVH3)6CMQdQVd;YrZ|DFe%k|BXLSI(L<_{BduJdjkfn>t$mJte;Hmp@bz=LbUZ)_ zz0Bfw0g-ip1J@D)78mHD;k2_mnZRU50vL;B@5nPBa4uaXnzuqP|D>u`L^Ct7 z?2omsjMy^u9YpSqOyU$7=QM^llFJ(VhJT})lDR+CeyqY=~3|KhA_ z{&B$cJ;W|RQ7NZUqjHs38C4SbZfMkscI&0}T}LP1|F>+}ZnvfVQ^KJ6@hR!4W6LG2 z_X0}{2g4znm_a{LF7` z;3c7Fe>FpFs%?(HAYHh>_`w$pokf?#@=l~tn!gym&*n6aJ5Xpa1t?l9dg44PGyhxQ z{8{h+zW?vzqVBo;A|R>I|7#@1{vS7#qiXY?NbH+B!(F9AE zk5*{EQ>FYNhL%jnU$La+FJOED`_-vP4azNT(i-@W9^i$SIU@}B5cMqnqj0IllmSh| zWMc5-G%Q2IwO2r!PWtfQ6gFt{oCQ*80sbfa;MO zj1@~e=_SeP8xtJf-I>YjCpuxK93?Q0D%O`{xlsjERVzHku>ZODe@4$C&Wi8;`Vr3;^6HL_Q-w$Sx*e zHG8PDUvfIp7ru&X!`oS}8U)T&0Ck7<+ZV5U*Zl=AXv{|+g{#HnaU2(Kr$LpT)2f{| z$=+FKQ7S3>%LyVpzVmuf)0)6flh?vReBAZ%gGv280n71$EJ^)E0nKrM0+IeS0kFUW z#vuKv0%(QMztxH()zCU>lGmd3+jxI2P$s$db0}7FX)JEuITD=syHBFs~PrGC%Oxm@%PzU*teD4EiKi>8Q9M4--Zkg^S#T)8-SC$%9#E( zl;H~ebO7RP5c9&YMe}q6$^@qoK73#MjSS}GZc8H`GGLmF%-Fcj+I&2zfQpW4yG$yu zN;(XQZGg}>d8!F)xEEY4jvdMgPB{W)TPpSH2#R3DCG5QkdK`<@PAZ@*yA)NbR#*pQ z4TCC4CVIi@ z4gYZ0kN53)FJlLdE=pUPZ|-CHZlv%lv`4iOLt(L7L(^<{kTd#V-$1y9K1NS`a&T)I zwgj+%KYI}b?Z{1mS0mxS|BJZmVhX3c{%fiU|GTMj{2x>OjTkv#zEERx+vZ0avW;zK zi!FL4q}vW6Uhb#F>xUsl%1KaHzurM9HC%DE{+$Wo=-S)c|3TPy4tifs21xa(D`slS zZ*J{{7D`HycW??}rP$CYs%WVUjMSfTgBWX2^SQDank$JXn zf+nocoL+o(LXa)j(4a`6ZfTlXx$pUbNMdU$fOCnKE25y;_Gg8aULW-N#A2!vP4O(|jvwDkfqG@Yk zLGu7!o=-LYPb*2Guh|yYS$5}^_eC(651zJs*g?*I2tSqNEj0U|vfH|G8%}6jpwyvE z_65F!W5iC9xST$ilDj_Z#f?}AwH1uWQeY*J6!|N^?;h@K;QlMjkK!h|*vqqeSzu9I zePw!3nFizxa8 zI}G(SWV!C zcq2Fn3VE?!2fkhEsk%cT&1F7VW$Ym%61#9n8QvoZBvY@ z$hI*!DOsXrBB%RU<^NJCDT{O`&DAF-=cSw#%fT5#vUbkGAgqi@*oGB=I3wIVm*~C?o{di zTlf6XY2L8X+ZncFbC-(#@ml9_EC%aRaxsPr*TtxQ8>uKmx^)I zrIig6vLWEiEz?;HjLgmGiR$HM(F~C!-Bs<>s8F89etip;^(jvVUj_@j@1)YSB9de z^Xl^|7%$`-aGvk%v%Z)m&=st?Pqeu!g7{Q#@8Rdal;Nq@uO=dXHUA6k{#Vb<`JdlG z&;Jm^QGbcytW8}R4MumAV^&_HjkKgSN$y9+ZX5Kt>47A*l!2fU+}CyVe-ynTK?nlR z!Z?sbw714O2xdsdv-|Y#QS1;T`(JDjM$wC85{1pk$s5`Pv@rUH5TVZKsij*P3iKx4 zNn#-a|5nelaWIYCH-~ECJVqX z^a9#poA1S^zz6}1~ke%kBoX>P77qvxQ*T$ni(`@LMu;TMwZ$pcAtlK%nz=m{$l`Ma*Wt4r~L6|-g{|%3pTFy38A~5z(cH& zfVcv`Q6#KEUm1l+zg~b^wqnqHB9=75t$n)uMMtQX;LwF5XzOOlRVxBJ{JK6E#xqB! zbXQCGEo#|7OnX~Lp0_wY=aub)Ypax;j*f5kHXWKCTAy$B*ZbIZ8vW0!>(52j8TLnb z$#S2@sz>VQNFDbx^F%O_l;oLZ-saMF2Fn(kQCo=QH=cB3l;_ z{9CY+|D#02W5k@4UM^yQ007=vNF?|hrK&6y zvD+1wJSp1+bxy=xeX-H9gPHqwn zC~|g>w)g@N(+J|6#8GSO9UVM-lJSW1ltl2>RHXXrlqx)#hn>M>7CmBd8sDzu7q zW6PM@=1%S7^la>sdSUQ7j7?^8B`L%iQ)d#>b@~?5Ojzfx)vhef#J@`tYYzk?yXi6C zO76NDZLH+H4BjLoI+#W>V0p!6lBt$x;SifobkDpc+7~l36RjX~ zq4S8&0kJ?a^O%?N*xn@Ss8hl6$L*f!Eq_HqYNx4?8xu^14y>cH(y(5}#hKys)To}y zEPaI!Y?=*>c9|k0NPkXoBwx@C3Ik_>3lv6E5~H~t&Mv`f)ii)+k4PUqjN7M#2z`Te_5?*VGfZC}9u^+!e38K)t zG&-b3l^GMBGi*Jx+Cd-m1Oy_{`wDk_p-xG?RMr4xNNOabLdZn^!QisVkV5Cb2D*R? zQi`mSPUTz%ut->=WYcSc>!ocoQsikUU&0$@jN&CUAR>|6CVJF*(xwF>#IIeq0Pwm=F%I>B$uapxB@&*tQwOUnke!J7n7m5eIZbJQ zGt=p)dO6G%$mPSedS9_DyRGuiPVq4+_lp#&rx(+jm04Y*9V1dz1-5x~-^G1eJi=0b zQBYaVy7flt6XFlsjT%g#V8l-?`?yzRJ$_>srWTYR9zY9@+4|QQ!^a%sROMu2YP;q- zAdc>yx#bxO{q{3ZVLF*$`zPV61s&u0vI2Va@W1XDUX1?Qj*4wm9xSF zsj3#~0yjIP?o^ZA4ANRjCbEy{acT}g=;YU8tAwGgg$jAinyTV+CWk7Aqa-@yw#vyO z6KL{xwP9f9+ub_Kyj{AlhT*Cy$+igpil*@?OFcYI2tsa9hKhot^kha52h(gkO*xS! z4jojIhHA<5)b_&G_MXl+=fCZ${W>3Z5*L0s7cVi10a0q5v&K}{+AeY8mt&AwpN@n@ zO}kU)Z|QNQJ~L&Q>6J7V5@@jv;q@)$`UCj`F)_{6tC-kIoNV`+y4-Ao%_|k>>sQOV zI-ID>$(RI5R}G3}RWDQn;ws3^!=#l&9!;#SdJg9{6v&@0ka`Dg+U<|No|cA`Ln4I? zQ2Hpu_B|4ieyUYU3QaM-oYvT3NA@a+O~&wNGzpH*?X0vVr)!h*h*g{6u?$fz=XS1L zY;uvdJ=Iz@!ZxZWDIijYI?FdS4rgb;(E}>4lH`Gafs8+z8y}3h5-L1D(cDGUs`WUP zW*{S3v1K^N-nc44R!`D@F7iQ|t0YrtYlpW6E@favr2Ch#AerWlRgIGe4=PRbg?GL% zA{OH7>Mg4`F8Vs@tf~}K2M*Zj z7AqYQM6?`%Nu>94Eu(ko_?$_W+SI~MG-DEl>6GB`Q2< zEh*Aqwg?eR)8}9%)@TY5b%>7L$rceRO4qnL>#ri!C$ko1)Tqa65S)IIKN0*Qj5buh9zU%XSPY(7MHkasl_xDp0%QEYy*JB~gJjLJ9WFW+nHF zaWU`m>2bEXL_*5W8U{M4GY;_8(4;ju^&Sa+o*}rD$t=Ct%d44dP_lpk$uI(WJ<&uA ze^4PYk?GugV}(_Di-55Mad~f?O_b#fy*4Y|pJfmqlzIOZ!Ekm~uOv39a0%&FEHHX! z91Z9T4vL9DI_C1nOQgV5Nj5faaPSzc0%;IY-v#ryYBND0Tp)~*m0LK)5yir7V$u^G z0y&0Gs1zE@X2Z48!F995p=V|d{bQUIcJ@f_;Nv2+mB3gYdne%SwKcz|C@V*Igfm)# z)8!Z#T_v7FAY1@v<*-p*;-ruDY})2T)o+-mOFB^A9!Y#aHCvD4>xS%JyXjIMxtLVR z5vG7zR!9{aU1>jsRwx@*(QZ?Uw8v4K;fL#ZQ@Q#vR9!V zP3*A^K43LCxw)*UU@Pwo5xq&ku+zw{QS_;Snix6-tXxIj3=&Vm*FtYV?>v(&*t%;H zbh=JrCFnYPamZ&(U#AKu9s>hg8$g1A+Tb`mT|O$ zlxBo{9Ox@Gs?!wW?ed1iu39~g*i=Z5Xb7J%htnDMnOMQR2^{a6UNhq0NL70#rTYFi-HO=@bsE0P%IMUh z`og|;u@biq{SfE&hX*(W$i56<#1dm4goo%>ty5dcYmwm&7(m2cbmxmBLd8hsV1!>C zUm}@`?j*89+f`{{)9b_!5wC{z5!O=Y*=cmHJw)PLbiv)N-OhDM{b5f>JX@VnP;Cl= z|LT3ePtEe$vWC>IZ@9488n)>EOPzOn)w?1j(>P+4is>YBLi>A*xQ8NCip@{(6WzaE zlV0!CJ+{c*e4e`N`T>XJWdJt9IO2v1?lh8fH}|HUzSiEQJa@t`)Bs`i4o`FLLA!-u z{c0mISO%eq5opUd4oKYZ=wFO;lnr60Ezr+G;@w|4wQllNTdt>cqh|zaE4d?kJzP4K zf=tEhVP|v3B=dpw`(poC>5%ta%8#6r0nQ4WttJuU9GiXN4ER#?PH*m%d-D#D<(;Ol zrnJ^$)!2bW z*q=zI*rpA@_(K#jd#Wq>ewjdh3vn-p*7r2}5z-KtSDsn@T(ua9lzc(K&yIRnb{@5#_i1zNv!(9 z;V&K;v`TdFr^T$y8}x1B;@5sL@V(y3>UK%+cmMqgTO^TGOr^vBhwt3gqw!yaHI zF{Rk+?q|Qi{q4+x1bfKt3;(9H@|tB*b$CVud$M}__cnYR_*pHn`UZ%9|5oVh_(X1B zfVh1lqzWiIjO2|fSbJJTs6cUQ{b8F7N?>9D@Nd#ItKMN5PoOIK5b!a$$LqM=uGI}Z zULud&%03^D?)8biMFN@Mo%;DCG2Bi_*jo3iBc(7T>e^=o-edl#0LAiWm*>9Ix(dK; zP@cnS2>l+9UJrjdUOlJYt4Q(=nOvH70F3~2B1O_qW7&OI(fqG6IZU%cj6jeJM%vFy zU&V}r#he=KyB4e`uvAchC4>D}NP#7TvkikHtf&@jY3fbf^2->~I}$bIV@BQw{=bq5 zWT}xhf%I3Q=TvLh*U$!r=PsU*F2d%&{O&vM^5MNEZY3Rk+*1P8?H(8uh{i%JXSEFJ1QZ@2@s^#=0GBgXe3&x0|pY4rs&+NcO3aK7bpA<|M>XSH{#<_3n z=Y)5QoP|62D|Q4XF*J?7e>wiDWs5M-siVzs0_%~~^_R;!wO`MA{Pv=Qjjkv0G4kfl2=71p z*0KvKmg}d^|05rXtu?H3agtR+sF#j{g#=}T&if zTnF<$B?;M6Da<@HWHLw4|7a) zca$%#g!jvA{o3*X+Q}5OE7gnPWg7&fGIZ^{KOh|gTWSY0j|OtivtEjz~8EC*(zkEYe+agWkx zQZ`2wJgW&Ly{(~IjI>4&pn!0~K-K>}lwM)W2vqLe%FDdBtjQs3i9=2iyP`{}kiAQh zO94Cy1eky^>GYg;y=mL`!FuaM-GYE&r>^$ZE` zJmyl(@4Na*&mMzw?ub+Ghx(%pC)AQbWOfk2GH5XOtlYPh_%Wlm`cwPqVCzv>jIPKa zH+1*w?|gjfcZ(wgb2~wxvO59(ckmei84QH(Z`-@{qkF=Ju~V0);cZ%#h7QQ9H#)`J ziPEqN;pC(Yh=>cXvgFsKG14yN6-xx~P>5%WffjTG`;5^APNJ{CL|@V|co?#vT`A#P zRMJ;fSmC0>IMa!%TAN{GDvBmh0cIn!=lB^CkVuKYYjLg_x>}{}FRukJ*S8JJO3%;e zrO(^0A5z6%DV?h~>zjToZFWPo#Iw5iF0dy@&aQQ(O@B#d*(7W)Bl)gL`AA{HNg1l$ z;hr0LP>Gj7pskAIC-r^dJFGzb*R#Y+o|$t;@dA5AhtsUQ*weuMqWDZaf5}2g;K|JL z$zQmaw#@vI%!8?^i%iQ88S0+)0BdTU$@GX~){pl&Y_3wdr?5!bmm|CB`<9$oXP)XH zsVGBUN@*e2GCOVQ7Pn!kCx4GFLi2!t(Cz%)G396ae9|tQdoX##DH{_i#*+O6=XZhk z&o!o1thuL3eEsj~ig|o+`z!*;-#H)3?27QPfZZbtB*+D|uqh|J@aXZy$RRbQgy&m! zY={rJB+j2Fte9k0hYQ3*snH`*D>`hrPTD4nm$sUW_`2!AQv}>*W|!v(S& zi_y|`XS>dw`dk&*&1(yetyUqy-VVLlN>kA|%RaZ*t*$@UIz%tE+5}7q8@a^;lEaA-EN1W(_@hKlU8W9+*iO8w$vhC&zinJYFdvFYj;q6o^J8~k2ZiJH zas!ql;z3%dbLLO?C}Xs~<%9FNL;=E^!G;$tC`Hn}QI*_QylEBJSO8Binnn69ifObD z?wG_ZQjv~IUB>hdd9DD&PEv3CY8v3`KVIKQXM9lop0R~qY>ZiLtC2VT_C&suO}Kk(-?@t8-Zm&(?Ynu3>(Y6>;lI~|5tKpx zcwJb~NO*@wbPI`BHwS_^k=%tt*vFF8v<99#?i}QxXc9+Y;1A_{IQbSm%w(8i!8|+o zEA9p!_cGdF<7AS z->U~i&L`NTsZ4p^q1~VuqJP7b-f4+T$2V*M_c@dc&cCs=mKh~KOv@$}{Q;g9dFnfL zHw0?kIb3K`-zsJxTKo%iZI=#Dm%RF>V8}%_*J$46)atJ6G&FF35|`l=uND@(*ON zBbGc}F9we6nm7J4uP33SHfzr2{P}_(+V6U84gC4UpURM1R+mYWrV`2&dL~gdV6B36 zatx1Mmv&?&;pf12d!c2RF!qe9_2K&Yl;Z$;f*-WG56Lanh``BY#32Z478!ay`#}N` zRh0Lah8189LSFO`FB;Q|hK`d0@)k)56X1NqIy6YGnxzUC8FKC_&h_k6bM{=0RT*55 zWcD;}(50(@S{D9_?ql=b4mENHsfe|=h5oT13ZhFk#^)?R=i0J5{H)>1kPZ8CRvnl0 zisOH3`^_y+s3%Po4p}3xcBhV0-FWy@oT7+#AGu6{wQsSsBgX7UU3fGipT*~6+3QtJ z0SIG;{&a%fqR%&_H|x(J<<%i8yd^Wwxfk_>hQlxzvtncKYM&SZHllW4A4?}S@etf(6*kEQ+;AYA;(Gh+8VM^;5U@*=J_J+Rq&9=9>Zs#`Lu2DZV16L~t?O zDl;}9ieeijscJ-(UnC4wvq?WsIV}ZQUbEU0FpRHdz?ugh@dcxJw@bFE@B|2}Jg4~9 z|2WeU_ljz}XgN@@R4!Co{AnP=!0Jy_0Vp18Li`g*uQOElQ}xlh`PGJ4wYoTrz1E&6 z6XGh+NyaY}`PshqV|^;<>52%1r(D-0tLK?mbo6E&(-IYPL#XeA^sNw z@U1rQCA2m4dB+C0U}6FR{y|E{euz+g{Hv1Y!iocHps=5Nc4z!EA`@Uz8Z{~jfg+8f zV3q(6b<;l5yjFY_SPhj%-^%hGRU_ElqP6qJhsDmEnBgbH%+gKY$Pa!7f3obc7u4Hm zlaYx;L#CS9U>D4hu(2s&Wx}0Qqd2`0348;;{Zw1#a5T2T0k5gnC3Zk!jBO$F0mcDO zz>*g`5#;0}MGfGflFg80X>%hyE~{-B$1I!~jNQdlC~#r7AifHYD#COG#DHE4dcbAO zrdd2SL`tE9ludj&%g~>W<`ZD&ka=m?Ec_wNv$|=s(|-ekyaQ#qb=0%i4J%~5YmG$2 zi^vaH_ug5hc$AdN>Z~dHadI@kyc@hd^A?8ERe`_LC+x~vya|su(=x6TJ3E%;6sK@k z1txnbyrKnQ-F7-ka`(Hnx?%x=oWcZRc;+=|J$PcIxD_(ZN!1K)-?dRYQ$)hpm-3>@ zR%AL6(FQw6a88v~%LI3+*FTQs4GVFL?7qP0uMyN>pSRXH1JQ&U_UoVUt6`Z2ZcOe1 zmu=w9BlA*S41=hiR9$(CM_JXBj;n3t%(fVae`H>TER;s*2;NszGm#@iFoJvP!v;X~ zA42P?cyrv*kb)ngaV)Ac(c1<(`-7cDErQ*4dgfdlj(bLCJh#(20(9OPqCtXwbj8@yPS6BO4I712?+u#>5=$Xf7OKK*81ODOUbntHE(BIoJxyl`Jr1 zk>-OGQ`4@Z^&O7dXL~pgM!e+)!(%SAQ6JeM7c~W}xMqd%+dwAURbP~sYEl2W6IAvu>e|5ErpYH$C(BXl>@{tk8edG9yYA7$JCiC8E0g$PES*4k^dNh z%bEy=zxtGQ8ryyHa*J<_n};%watZ=xT-;KF>zUVKrN>MhQ9^UI!yWG%z)(cjE|m;& zVTwo zffSXX}j)LakB<70eI7QLNMxV6{^PpKkZeq3ac@2Vg!q)oXesnfK_;S=4 zB1Nas|KFOg;*3?<&&IeF8q2?m)NARbaI6M$_qmmsqQ*asgdIw%dDlyT?Z>qh0(Q~$ zxxYKGKpQ9ctkAuu1@!V|I zvPdN7j!Zvj=0z?Fadgyj2Y3$a+WE~U47+T3!`t!Ev7O@NFN~d^=d<*!5rkBlIw2L- z)2!7uaj_Ff-M8Ir>rquRjxQ;v)FegQ(@tQ!n zRwmBVjvUHdDkFvIE)GGCv{fou%MIWQM=*Y-&q+zYS6}BRE8(#pgLh<|n5YYKI&+Nrvf51YE%wi&*;@`ldLR>Msu;I2yDUg-P`TF4O0E z{fu@G)?q6CH{8n-0)IW4a5ij!9&p%vwq@-Lc;DfwCpGw`MaAoo0M}4 z#@2$_((_yaYvGsz!+cSTqlXimj*9b2-jnRzkKhI_-#IiKeozM<_r{_Lg$Bk{OIZjs zFhVlO6_B!GhqnI@U+)y0OVq7x$9Q5pS+Q+n#kOtRwrz98wrwXX&WdfDfA(ATAM9QA zepP+aU9-BX59S!N?=kLc#49mo*e1>~Swq9CbT1WgnF}wf^tts!MzBv0hG3?&0~8jT z`D*S=RC;;Vw_(XeApOL17qeD5F}Ws6Gu34rdJ1Rr*#!BEUzJl!4c#0%x_`|)?k>|& z?~qOfH}KQxoylyX6x;k^MatqrAIC#3URUz8ORatp=t?XZ>28+X(T&RY46IOdmM!vB zGDfnQ{jlhSVFCVGJc%@kqV#4RrB?H$mcM_-eW1`ysd(P12GR`IY-*xp*$hK}lP9AS z+ql|1qt`Ev+j*VH`dEVLeT`z>lps?b28H zuoooHH+}^1rTNAtV~SGItIg!mFIDmB3`7R9RJl9PDCXx?N`q?jk7_$8VZj_F1Ks7! zPTtM9?wxAb^sj{g$SnVHX5MPnHl?tAgx2?BN*`UR?IJTMuJyiix=;x}lbX@Yb&Ats zcL%+Dfh-0LDaCA;@3c?a?IBYxw;s5TqpAfRc%dP+KP3;);S?t_MUs0o<#LMuT036E zl?I8kZI(&}^2h}ZqM2f$Jl&BG==CE0E{iUd5*ND4Q3R+U;vzMb>-GMTJv#VppMNi( z9`Db5f*rtuA^*su*#KRCX0^d z;F1kj(HeUYr!6bn=TA=bD&`?ABDSaXKKcEW0TAQb;TtGg)@Vx(EA`n5ud+kZ>N-b4 za=_7zol_MT%NP4GHdu&1@4qgMA! zO<>4B$ITvgX1CVlJ#~!kk%rJ;yW1acxF0vIaR1ogy*!S=uBK?*1k!IkpWRJgeddQ2 zk3iP7vHxicWJwuiQJde-uO0!`y;;tAIC@fR8~GM7{oGqUA=GFUbEkVJA@(jO6p+V| zAnxrSnGU~^YEyH=*2wPiaMD5!Y=DDG{PQyHNWRKxi#;Yu%-cxIe3NcqI3Mwn(iOC# zeH+hPFnz>8mcb;tV7@T;bs~)fh9~p437oehNh_MX{j^>Q<=E~v{~dNN9_CTME_2_4 zxAlrAcD?0q)9YEQCq}-=TVTH4^1yt+g+Unj=AF0=rR1Hn2gBeEH+18Q5quH+?>=@T z%+T3!Fd(3=pN_cyCMW*~K^&w0&#{Q($4^B|f6s(wZL}}7RwJ3s;XvA$^3xtmV`QL= z6rLiCD>prAC#4S}9NNY4>yh(p*@CrtDo(p=A{;Sf%P4g$1cfqXMq3R6DWbk>k5WRP z?0{$lpgY{3QvS=`PJqz~vOD*BB%N%=(RL(v*sKt1nBxw9 zuWWNKqZDYTUnTECB zxUo+ZgeN{(OqSllrF#wszlImckt@&)1nl>@p&%oB63hf>vhma+N6Fa2l?}j+3U+$M z4L``D{TYXnu&weZWN4i@lXOq-tm|d31g_?qw|2iHFC8Z~7wc8>W^r2C0)wQvX`szt z={GCQccpQg$O&iCJ$FYT6~$TqdIOvN{U|iD?=Q)hl!8_9PtGFb1!SX1Mdsw4g(3M7ezRt`^=a!2Fg7B-jr;bJCI zjP3hpA`kRg5hWa)3^AkbfJuO$+6xyr&asesDM9xT3zB|};9AB_>|H~Vdnsvwa1foq zHAZW%70!O*>E1k}PnwU`ueJ_drPO;})|(9kKS4lxgevy`o)~-WE8K=6;ZuW|!h|(e zv_lQqnI;!-V5qm&YxiQjnOn49W}C%sUBP~anb$4M!x|TtIvI32i5rCHvcFHIkk){~ z$=1}V>)Lu1PA09|*iFzF=}fNj#FMIH$E!OQin8eguisI_d+DV>LSMCkw1#<&(%rGD z?)7dd@>mhP0p+`hB;kOD@(g%rm9OIV8IubK_uK|26(lR;(#S{9iNz>g1le@97!Cn& z7U5QxH;_J+@uD<>RTE|7ifeJ+PX^!L?{Qd2v{`A5ptY6vpI)8YtaWBeA6;p&)>^9O ztwn*DNzrnDH_iB&HCAL*b;?{_TEU&EBB)m0mf1GfJH5J8iuI}tcDjx6Y;qUaY$dl) zaMGpV9&eB8MkTVdkve6sRC-*n7wRol@im5N7*cVYvN2vtxx+EqsKPP+=XI=L?sb|m zp>T|ssss|cN`{J5jHi4`)LF=~aYY{%g?imH&Uozr(Ih z&8Hu8K=O|{;J?Mc|M0G3RR1Ne|4;lIruUFAFajM^6j-vCa4k)&9cAW8jFk^Un*V0*;#L@r0XZ-@6~ zVz1n6S7_+)L8S43hN0?OzAZ$O74O)m;HQrBZF6_Paqa=nxNaTd&Pw7Zk{)J6BpHy+ zhGoVk>PW|*ARKi;eer%9fHYU6@S;YUrc`d>Sm~!1{B8{sYqG8gu0EMZ^Y?ZNi<=}6 zZ@S$VX_UW!W@+vwB#`=DDmLUAkrmo0WH(tq`j><(=@mgq6QTRIlFKJNuU)&Myk! zez^Q?J78GJz8&m^?^J<+cwB|ZsSeL&Xupqiay4ES>SD@zW3zQ+`!Xs;CV)+Kjtu+ z@jNjCd$}^ij?o&JNp%2KBr4!h3#jtcw#p*8;<#XGih+8iUpORr;=qv3{88HLzp?hV zh#)7Nezob2DOfa#b(29y=0nm7)|N%K22Pay_RmNDb%Ls&Ar-L}FCB@u&(MDHg6}~e z1M({!3fPkrW=$%=3?Q;2nxq)b4xX-R3?umu{WmH+juSkWlW#!KsqMDYSOM{6Kj~#@ zKVFA)Jev80J0y;+x6=XWwIf3XnS42S(Yz(hDsktma?g-R@#o9hc$|?!p9w&)a>I*^6U92bC`_mP8p-SB$KxLb9}w`t_Gj} z+;_p7LE|6HluuEf+`bb;VwS4jI~`Doh$E6>RK%&}DJam1P0>j~Fr z2jdNl_~K8#OOZ}ZnV+N5WIAF9A9CtM1{!sWjI~xMqeNZTA(n)J$*4#mns;P3EwiA# zvOlt^S1igZbV)gD9=cPlA)ktS=T0;X$}auZEbVp;dz__rR52S{GQJ^K(qnJdwl%)?grdC(=$-{duGu5gwch!NyAgFB}kx_*eOOK@?iO*k9?M zAn*^;dh!}eGn)JvICs^~Ea}F%zu&CIOYAR|twYjP2wqE*E={ajeH<66pa9x^p-YY; zT+$DLUv6lDegUWlx7XssBqB^h<@l$@Xn;GeeQ^sZmLg#-9kO3*@g!h)MzLj!5{X75 zvf*SIJCK=INXgmab2)*x)#DF}Yl2}7QZ)OtqeLBsZF)FYdaNI%B>M2?8mcQrEw@8X z&O`d%mvJ~8*asKMcxZ|$@bma>1_uJ_3kZq9JTcKNuWB}4#E?3G-eVGSwJ99$%x9jH zf}j_gh=F7sgCOk%labn_Ryv+$jId!g-xZ5s*k2Gv1fKfO_8mJ{0$K4eD8BPSD@PKb zwrfHEhFB)WjRk5vDh2L>nM&i<+*Rt-{ESM;w_k}&VN8fvi>g`~ zZsh(%VmGx5Z0AjEp5G!NuL^2C)bD4^b84nd(s~0~@R9^Is&mT5Z+-Og8-JM4%B9}1 zP1{!Fy4m)(%*Dv-3Tmt-B5&LH7}7Lzw18I5SI+v&RDK?(m`$nF{;s_Lyma{e z0m0FHC98%AN>z0&iWzL*i%X_F@tQF8<Ie8=nc;r?zjF*{FTlh6R(f_IR zuxogdzP~co=|P`)xVP}02-ojuwThPVzly;`sP75Ruk&dU>OHk(E@U!#SxjG^vH|Ip zxT#*V_wF>dpvwq{pe^iJdKplvO*aosV>x~=mT}T$oCm{T(E}JpT}*l+1(j?+7Cp() zJh7yN_gf)srL+>ysU)*je)yZ2%xZNEUwQAalMe$Fpzs?Irc#!4$nZ>+8#g3U`-g#{F5DLsE_R; zjnS#|6)8#0?-LmTlChrRcNYOP2f+*iI&of5v!p)ca=%>Hybcxbgu5Z{Nm3b_5I^`6 zQ#+7F1<<3%;Df0XGnHSDyll*CZ-W#q-=D*VTMrcjg7h3@_0f9f)oUbGj2imDlV-hr z6)CfG}75nfBh7&QhfKhmrMk zpn61wBtWy?6h`DCLeWagC3`U_cWA-0yFBR>Su}Q?CGMhnz=T*g@>X_60T)<(erV2L zp}%Ukp89;|3KfQ}ly4iqv6;|r48Zi4MF(^AWK+kC+lcGe_;5h zbKja)0^kohmr#6eBb`y4^HDLPF{?F(HhM>@o3ZR?@)x3&>TtMr)9w(N;P06h2if<1 z%;w82vNd*YYr>ToekU-+Yvy{)G1*Rhn3ya$7iK~Kd`~ua6<+l}tS|2%#C}9aLq2u; zBkww(xQVcz&)zMM!ohEE!)}iq#%s=uk(CLbPk=5+I2R9ZIqKL~vKo77!!AT)UP7E* zn}w`}lbgMq3hSk`zFb#@c}ytaUq5`l@YwYzJq&?+CXY(^tC@z)RwW4s>S{UorSLqf zV{0K*;wC)4C>jpeM)CKq55QavN^{~Z(ilCY`A$1$YWDBY-}U+w?qa->mYOYp7#RH_ z(^PYxwk}S_JMD5Xh{n3rOm{9L1ToDz$o6ddUfL$N(-aUl)^js-(YTXrtJ$k%zpbj{ z1zSt|wuL03N5GE0GYSDW97t#E15Y|Zj8-j(-eGB065H+Su{56XC%S+r1R|*MIjAUC zXL9siVW0alA!PxJbyj#278i-3#|i;+o0nGKx~;d|xMTW!2(V$SgBQKcHuF^;(}*_) zH6!6NH(bWGSfx|LIyUeWz`FpxS!44hDBl#aM6fCeZ7I|pw+;&SGND##ql1DF2bH`V z5n$NgJy%>%@-KcRaEGpFo#_H{Q!06%#OR=EEaC(QCME`q*@eB8lbF)iBvig$o(67| zuhX@ex698G!47nWF#2Spjt1Sjh8O7{>+X*BpxwEF-#H&Cp`nKE@S*uklya(8WA*MC z{GAmhZ!$Zd*M45m3ENz>p4a@;LbP0xkTi7JY%o$i0!ZD*YMy!zNI##ZJg~&1B8Dm>By4iFE}El4lwR zPp0m-lYMT7nCnfC^H$5?BH9#zIt}GTKcpcC_iiX=oHi26Ew? zRxYE*nnVf}--9QUtVHY~7ClrDJ2jnS)s8}yR|6s#xhTb~XOOSo#w4Rj&e~!$Z^WAN z?qRl>_OE(fUDvnIac_4QuZ7d;k}hQ|lLLug8b_Sy|Ev;kr%lMuE`D+`mx?ElDTccY zy6~qe548K4$_w-~bW$=i$=F$g6Pk~EI9-!}#w|A~j>db8@dP^oxJ=K$M808f(AQ5V z?GOiXojgkgFTbS-Gv?(WjZHS`F+KKyQX%+bDyHB+kpzWq2}G5y7fDr1*#_xr;|)O$ z)rSfJlpvtw3>?Uq+AL78Iej-+u)>K}lKj)DwA1k|Ho5{a6yuc|IcH#`SEOaV z06P!*^sa>ns?Kx2-mE0{F~A(|97#5Uc$IOmelE-=3D9*=Q^Y>#$jwk|u#;Y`2qyU3 z<>6w<_Iw6-YcWcs16Uuaa$z>g{fdiO+s_)?62KsIo7eX)EFK|D39|ZDp*Xy2;oPx7GdCm z_7b{8cacAV5_W*Yk0k~ys1G4=gKcWM7B=rLZTt{kWhNFmMy(|I;5cf8m>^Y8vTdpE zHL_)$xWVOeb7~qy5*QAAr=sH-YY+}nRL%Yf3Lk(UyxpzBzk1vA5TcOT1X?X{w45a* z<=^4A)ATo`=n)ND1`p}*p}F$@p)QG>9LEBOMp zhZl{-H2XfmbFKB1*>1RQR`9%=vqy8ULEg28l2&0={@jNJ4k1v!%d9lH7gxeDe^IG5 zIT9{K=1IyOuSV^m-bQ!;ex%MclD?FV$>gxOjgk6^0xz=7=zd9(liGpfog=caWwn`0 zdqSpkEwh$hhLFa^sg!4XfMy?I*I_a*I#Z^a7zSgdgZX-io}=H&;F^-&n^F}J7*+}P zD>-0}aYDQtEZtthP+PL0wgO8noI$rn32c)GjA`+5(Gh;CSSp1y726O@yAW=1 z0@JMOWTvc}b8KYUVlM6wt2`ef_iNm-lSuIshS8Qnr?_V%3|aNwoIQt#VoE#DJ$YRH7|Fpw#B4 z&BVxekc~JZPC_$=vAHtJ(jL(9pJnx_x(fX+tj!Gl+`JTXd2K4Kw$ThNcsM1sirOHj zjQeLz%wdP}F#?1AF73BKh814@k8MrN_F~(6YO9&BZQ*huM()ih>meqeTCdn`n+#KO zJg+EKwi8TpwPx1{`n8D?p^0UkHN82=L1*kaaiHBe3(;G9ZxpLv=onb%th45FGk5pe z8Pe=uI-MDVTpDyS)aZMUSFE<(y7TW658h|wPLUfqrv*n9vJUk(m}WhS`EhhU@X;@eP{tUSEL8}2^WYV!uu`8Fp zPj&lU{z%%lkPY0SU8lKq1*5>6`L4KWeS?>Ctr5sn^S12N0=+?E&{IRf*VdG}t-FVr zMd7>YC|+AsVBxgxDM&d{u!Yv>6O05vMFSdbZQ6G zysavrmuz*&a`+4G;%eCMuO3N00}WGGHJsIfk-q`n&heYg%WN3MqZ(iSJ#qfo-YaDG z*-x><8LF`tk2iF!_qIP8LH|dG;|6)(?Yn;c^hbSU{C}vA|3P2IsL43( z{gf)GHT8}XBN(?OfK{*(8L}p16Y4she$>Z`u|%~*!l~NrRFml6#*7$s#lEw(oyDqF z4H$Pa#lhwexr{X>f)y^lIH6Rs5}`}YW6)t4G4WW-H&m?!6QunT&=cybm(HOEp_B-w zNsiW(W+*W$PW{2cj-9y>IWy*4onCDS18c&lnF_M0$mK+nbv)k0(if$IsJM{2r)*26 zKvhm%q|}Aq<7voS1DX5>Aq<1*M9)_eK*5_<#!mD)t5kq$QXb{WqtX01>5gi zuasPf{A~+hXKI0GSO(krYn7*N=6CZ|kP|ikFRY!CVPE+*1m6W;^)&>)g#ZN;ekv3b zVy%)xd@G(T@p`ep>Yy1O6i!-&ggD7r)AfImO(}OCtO;F(9jA-}j{>cros;B2>oef@ zBM-(CowdYu0oc8S>YsLIJBW*mi5<;5Vn${ez<`dmg!uyH}?3^+<0% z0p3B5t#p*YQbr2b6=e**RBlgOV~396vOZwVB!Qgv6`<$WKhHDlE#*DwsD4iH_Lw$| zs+vm~LdPEJ%g$g#hY_lafxji8oh}rk`t)$e!Bl~V<$>2;`4lu6marXG+%&m(!4{Y3 zP;GpnatF%xN2vCoQtt06eFRKge3s@|jM~_FJ^sd}e*HcxF&!zp3~33$+H|2ro0B*D zS@wk8==Q zUoESnJaP6qZ4JMzRA~z`>wMut2KHKG#XofWq_TEqB@BOrjSI*Vc;ve~?~5D#@lztVlG?&fi=}|1 zAZ8x|e^)P;nj+io!3vV*37bFrfl^u(3x=1{VQHHqeAdodZF74GOfm_tA9XCMJYbduDA0YJq|S1`4jh%mp1J8@0UTF5ffW$r>| z${n9#t(CqqK~A@2QSa-i+fu59_salmZB~fqsB8|K=1t z;^>b+A89?F{!g9t>m)s}0tpCcO8&q9+588X*v(_*w9l642Yy`Hd9fU0-F@j|S~4-4 zalnHz`ee%Y82O$)h{n+|Ik`v!qLeOfrMB^nX~{!k+D&P09%?(fx21pTsl<O!Uz&;g>#O}-P^7&Ie@C99xWLf!`TBBkG*m#*X&HZ?~p_qPj(_*fc6kN6$g@Vd$9 zxi|(KVfkId*~3}^0xaiFC;+p4(4_6n!NqN;#JI1b$yc^ywj0bNDjda68BG3HXHD|EmWG6p~>TL;nOQ^c^G`x6fS9zaA75XHClhOG58H z(a*bfDbnHtyKWbuhz=AEBo#~Z-Kc!G8m#SZzdKc9{L16* z6={+ggzAU3HAo&15*+DgXkt<E6I~DHGapvrZj9R(e$9xYNi2i*Ug(CyBl8y&38)4lOhY{}33qVB ztu9efY@ny&7=r_MGr-%}=aQPyP=QjVGwyGrJA~E7<&aA)vnG2))`d!?vhSzaoy?x} zfWTKeWesW-d4=B&Dq377`_*v6Be!yqM8mI^Q3w?r(N zXGVq2@&)LK`_Gc>0%v2T+eM(ad%Qu_Kbs=*^Ww8#*c}4RgF^VQ&8WgG0ItO^TOr{SuvRDo4mH}U5^Y2c4PBF zq!BaM&g6fU)%QkTlXjwtjN?lsgrSNHezhWcOctyWx#yfD4PTO5`Gd$;ioK zFcz;y4XmwTqpqbmmt8Mg;W!1Duuhwq^J8fuM}jVaF+R7qAmA9pqzs`hpT8ZnNRf)b z=r)jxTcUamV1CPl%ZGYN5ZS|zzD=|YN+^PtM9k9rQ3yP!Ck7f82*~6rL0{~4afeEP zxWa!mXmj8?jx1L&AsgcAs1}M)s^>Z~_{I+iPnoP1C9-5vuA#HBGE2Y;6r*so`A#!6 zzaf2zow{&uM^Kfk1jrAMCWV58<#3?C2n(Tg!dpfR05MC?EaMdsJmr1+E?+J#5}hWwC}r;r^5aSmJZNRicX&;CVrfR%hC1iU=3##2QR zIR%r1XP81dk?%{{eUJsxBx?XT(&|_{B*XY?(G~Sfi|Z?dIvCz|Y7!_a9^+mc*2rSwW{0g(Dz9r+P$|PMO=H;wI%w&BV-HPG& zQ%I1)SskrnzFT^pR!aUL13r+quEAfL{9cKqdX!eiVveKi^Z|h<8fS91_8bYm1}X&V zNTR_ums+CrN+l?$+MeDkZ7lgi?$YpU=!dex_YT>Ky?}I(@2CI{3J=Sw%Joq`6)aXx z*MU@sp_1#+!*a20{&v-m1Ml}e{4=tQ;{AzRadW$SXLI`0&r60fOfEF7Byz{fM^yP1KM zMAEm#Sb0C2L7CZueE>S_pC=0Xv`xEUrzEK`6{%bOGLOVUCuoy?=1vfHYGAFpM*(6& zCE{4Fb7|PCKO@~vPcM?aVyz-JpKr!zEBWgb^7+ebS30*i$r#`tYw3T43HCbS_yv7( zN|4WH^wVxl39LPWWLoMxP^d7NtO|!kv(33T+DDw>E49_8xtsGf48UA^;JpKnfN-na z*j;wdpYT=249)w!$qQisiygHcIw7cO{$pq0Oq0Pz-B}QO2%gP##bPjzseN`Tir_HZ z$e>vK`9mWY3m&z?m4zqyLkdZ6!-xJmwWXrPr054^*LyRA5>XBCbn5xn*~C3O*9niD z?vVD2>zOfWtvf*m6sMC>B-zYX}$qCEjk}fqZR@6YL4a z?kW|$u%z?s2l)ILlZo0fBKfQjH?(2-*=+cN4 zYMZmu!}xlc&!-dX5>NPd%nUFC8QO_ZL=zLd6RqcA_=skU#FFKt7F5*4^%q)Joo_XZ zfJlH%^WbNjEX>aDUp6gg4#mHf8GCTAm4=Uk#693`Pb?KqY047BGb-@x1N-cdJpY(3 zpMj@WuCxXYY!%rbu@=TKRq7u<^#Lf#eD>dG0|<;}*?1A00I)a-_mBPIYM zVrj+zAw(0BFsHlTFMtX;lW&}Z#&bzAu2hmlL~@&^1&GVtu9t>F0u5y=IL{E$m1NkV z1Q6m0slWM`eR5?m#g*IeM^ogdK2#o`#j>yEUC)VNE-tpwKzT7w<*VdpUWK99H;}FWWh88`<=!p__LD-;-iax1K z`9z(kZN4ZM5|j3mDZvkylQEvfy1Y^Ihe7ZDk*;oC6l?S?1t=uc$jdgMoTB~+KA>C= z0sfbkebX?!SrYEVxey{s!|l24TSW$ZHw89z%uPCizyl6Pl38Tl&3U%E|~=E715(Xg>~u1{(cpjw7k z%sV#axdpW$KPfNFLAW?<6tjQz$S#k##mD>fVJps$B-(O=31(9Ewt5_JRxUlr}eM_Q|%ARxxx)QP#f zJSP4yL6;S(xxI#g<=1z3g98!}yojlsyAAz)w7^2-451XgDblg9IZJ;-LdkNRntR_xs0m2qBo*b5C;k_dJh zcP!eV#e|5P89}_ka1;p3MEq-S1BK@VX=H`ZjUmzWHHC!-D4=5rp_w#UUQ!3(Gs^i` zV#?NyiA zbWftcanKhY1ujBzg#nisXpN#3n~G&XBs93-eNER57=ri;IsuZZCgbL5b3m}K$9_h4 zIs3i{!lO<-@aJaXeA@Dsrk}wRZ`7C`1c1begQ>{HwntfCzm6Wj&(PY8W?r@E4t;JEg>4Z&Eg)@}Mp)5VF=ImsyR=7$8E-b0ry2{`m zq>u82M?YKF=@`Xvh;xPj-G?~`Jx!ZRjJD(;5cayD#%@5eAGWW_q1BE`xNpR(6q&Og z!51t;7BF@XH4fDeQp|ZhMN-9jwshzH1qiFKRPPJA9N2ciB`{P#)CYd z_}FJ~J|);ni*_s{#$nAyg#fg;Lw1-CrgBmXXpAEc1NAq*_5CuPgj#O#3ho!fe!pOG zi+0r~@Hfr$LU!?rRheY&-S(~aFDMb*$)3iiRaVCLiHGli@}6LNcAIk?5@Vc-MynY}ne2 zK1*q!ruQiYZFFfEwtgQQf0}&0cU`c!Y9A4m`P~`ET43vcK|iX^0Sb)>L1C1xYR^Aw zNNaeURB1SKVHAF$yN^VfwJ=rE9bppF4W#FI8ASc^f_3cJLi8??R9FR_S{jN~zRqsl z-xoEsUpB2R1qJ*Y)gtwLrzg9k*NU2rlQVkO2(Av{VQpH_9J_+ewd~KKc`A$Bq_TpC z${5V6hO>Jt&#$wH4@(5|E2pmzXLP7-Kz*NRPj%l90D~hjeHTzRPtUgFyM4Vnb$^y2 z{k(qzYw8y54~|;FNnsB&*DQXZD=9t5ec|GUx?Hj!F){d=?X$IvC5G)VK6&%yjXbm{bK5jqT3Y&0zL(Kw-X+U{2Q?8CCooKgelvdYP7u9(n<t?(O^>L_U# zQ|hth6`lGA1z`im-()B9YJej3t^zf052N4&yhzP6orRb=PloNMFv5oYO%`n06>zj< z!l^Z;+s)2pK8a^{_CD~4i=b6(2w{1N{~OkLU6;k|n?l8wPPCDIGb0bi2?xU$=-Lc$ zhw~iP`&m1IHKY@M9J`LXXOM8SA^!TOz3*oK8{~hh(-Wn#sG&cN^qsK(UEui-W0Z==_=9Fog3| zZ9^62BV$I~A41~DisLS5zj7HYxbr&LGsa>DElsMRfvfcD394-kse5t>8)x0TJmSAa zsnd^gvVE$&H$lHouMQhwNJNO73VO}eg&jrsejmyt64NGANj zQi^Mj29feeuS6k6ZJUPaXez{$^(zS+eJ_KSR6sXRamGH$CeA!zYfv%HpZKg}ABk(l z8dS*{$DO&LIeglOMouZFq!`sMezh9}@?n_hFT#vRJW<*1k)A@C+MPa|O81ruPm3a9 z|Ig%0m6u6$Pu?3(e2uyz9KsuA&vMGnJsg_(9 zQuU;N-HlkB42Byh{-lu}Rq$87J3_< zPP_te6;2DQlU{F>h*^%&klPY#O~-*eLQ>aFXS92zhzG_nuYUE5Ve_c&RYIxh;BgR+m$vd-tTNU0t;=SoC` zW%nlT@Nik}ts^-Mg@Aw=L6TEv8d8%@($r5VY>@;IZ-LTezPRN_ddAifK)hceuIek) z4)`hWe|OJffY}4P0Vo8{GJHRy!D`a=miy3d{GsSpYf6lmlrx=QZW+y&OrSPr`(=t? z;df*qBCh?sMS9f=7ODb?jmw29l?AIcGT9tGjw4;gK_IKjj?+QrbpuZJgXU_e5!(rZ zO~G;dimJ>0RrwPiV4&FxbN}%NeTqf{3I}&XbKP<4>$uw@i7a>@4fm<=A zZ7gxyL06sf`fo)G4gFW+(4UVMjRY45|^H{d>PO7Hy@WYmn?>Ts~OTYJA3CVm9? znm%N%GekoEOAqS{@_%pMjCnc*jGxWB`~TRy|AFG?r2Vt~8D|r!H#{NfwI;xk>F|xFd=B;DZcQBQ8Oe&!7b0rkhUE#z zWF18yo+Wq^slYlkCQXps$DABYXGnnSDsjtpFL)Qvf)1Cx$*qd`N~t1={!sLjG8#Zb z!f&wo4F`0N0?T-+E&qII^eu0hHN3aR$@6jU^JPSPzxqnxQJ4nC7v zBhubdIFF41LGE}s%0rJVW;18u;I|ZQqFKWN%7B1At~*p%W={edBB&j46MFq7&V{lO zoD(-CA5^Ocis&!Qr=(T$_=(@tSBH|O#glGPE_Yye!JxnV8FVM-->!Yw2s)6~D3qL%<9t?(IHwm0w7D zJp6#60KYgO>8j_b{FgcBx`CQt@_pc&=zwxSPBs9}F!^3qlF#7we&>{rfP6PANd)j4 z{muBa*=65IR{W>pvG}I>l9B2Wh2knM9=L*tx|u*I3KVH2+uZBsRQs&JLj0b1;Rhc$ ztMqyT^wre>8DU(d7*%yEB9D;1Awq^>$dKjaFtBPxG!+VIJOF>l2<%}*8Nl~w!$Z7H zw7Sjm+X<3K7AGzi*s`J;bl;P zq#Ag!2S_E#LruDw@*zIt^P?2KImC8_wNh60GMQQPxQC6SLYB5K(KN#QzqF?iHa%WIA{r|14ia;RAK@4k-G^; zsQYuZI~XI91D8whjEE|}YFj*s&4#Q6v;wkOoh;Ar;KE-VPtehXMlPnpK0GnO>O_n7;Im$mTRJf@d*V*CRC8NFHT>Qn=_3*E|j z9)41!`?@$$)ZlqX=+llUo(3)}%$T2swpk2mo}ItI*+tNXa{b|Vs?00=!%_!f=`a3; zYZ`-$ve^n^K!y=!(W(Z!c8GLiXNh~K@o~5#MxR8+oDKzH?v*AO>uv)Iay&My{^{9j zLR-O!=ag=L2&M0kUedwvV`IS1r}Lu0ezO?y9yoyOGy>;O-f&|(3~B7AFo>qsJ8h^y zVEM5X9bnuUbtZ(hF}P8L7q?dkEB{S1MVnHMB5sL*%cdL?T*0jSFoBGC*yEuQ~QjI zv%9LZE5}E>8ihT#01}bxk~1*&Cke40MNO_^qP>m6e9-7kM|w0&_1f*2@22tYRBF;+ zb!(-2G7{{r;%nEVO+|a!fA^FJ8Xsh(jI;kNVS1f_o@`@xYg40@WZvJRak8Tl8*gKu z+@Nl)PjRqIX=hhKF*P~RGP$Egqg55{Y5v_~*{%Mnphu>6*!{EM(!Q4H??hXxYn$5o z|J+)8AL5!FXmKAgk#Kp^Lh3oMJA#qd^?kjlE&#Z96EdDg$&BIYf}P<$|)> zf+y^K;I7uq!VBXi@`EDf^Z!5Q-YTljW!o0U-60U%-6goYySux)yGw8h?!n!i;1=B7 z9fCXDne21_|EzWQ+U-2thx;(wq%kM0QB|Y*H%9NhM%6v#mj#MNmjDWgUTS?cEOiXo zLy9Dz>MuQ9x4rz)DgNCSJwiv5#1tVLN3SHnt|kzOUwZH~=omqXhaZJsP{5npN+SjB zdr|F(G7h=mTM!os)ATn*^wC0KBSK#!@5i|DE!=X#+^gt=c+GRw7{DmC1MyBF@Yvs0 zfzud#KN5P#Im-rITY9qRu7@P`VN%7l?@3^?ovm)W$OU*#Lpv`wgSuM!>Keh`^8;cB zx6r3KK>WmeHmNI+_Lvz$Usou4Kc*@b(ERZtyqBLIl-RT$U1A858TXI!LG|z*bLn`a zDSQtfY%rBEi0HW4Q@@r*A^V`Up+W8#(gmIF2xCkh8k*cwW{&-8W4NkQ4;lhTNOl;U zhJe|l>%sL9%XSXoTnR^3un2Z`M()$-GMsNX1{n;_X|oFDe%I!-X)Bp72&Ydfg)57~ zMty}1kYih)WU8Svc&F=VC z+jPIkGm=3(wt_X^tQsrJ3;f(eM3b ziDkUoq*dK!&&2YZWo<_@g>t9{%~buz169bJr8!51y@=FOPF zCISdw;Hof_2(|O&j>?#h@|ce57@T=gUh_D&I&+>X&~)p7nXLLw8$7G_t3tK+3Jj0w zDDTCn*OK#r$rbUT_$8CH)liOg&JGTqw|m#;bej`@fA_S_&F=&}Vf_3fe8VPTGs+@H zM@cR5!{i39$UCTf#YKejZfTt4`cku)YDt+++$lGMY8EI3dcZ$bz`vcsFl|x|uPNu6 zsSCtD_fr=_d@`P?FRARX35`+%Id+zNZN7fABOQ}0lJ5VgqIv($u9fUGvf~$dY%O*_ zgLfiTR8gS#Dpv@n@?J~+z9_0&oPt}L@4h#*d6r8q1+4fB&#*c<#U{UF@Nvk+pX}Nj{8HxU2@5tK$ta_fBMng4^TXSQ)TVwn~V|>BNFeJPp-ubCNnHGUZL-qM!qV7|@ z?w$z!wGRDtK@$d_6)~=uVX6+oy^Fb%Cl;E_Mhk8W>|WPZ_)i4k#?V`v5K}%beJ3K5 z5g>JgCLrb=4`Y`e^d#XM@LyBWz@qLYDTgrgH0TVVg--## z6YOfAjH{@Jy~_!l3iz6{48VC#nCs&3mE$Dj=v~D9F!q@dkt3(F(ekpsL)pAhgJ`r| zlCf)roQ^35H=SK?+NLUkl_pJ77D1h_R6|)3)1w-THO{E9$L&MdsMvOoz$cN}ID*E^ zpRfUqZZ~fN1rNuRyw2a(+()l3h;Gb_ZY+v^wIs%85%(~Zhh$j>89@zNvE@Ea<~tS9 zy(QYbBjU64x~gZLaUgNU-0#mtu#uGux*iFDirzLQ#+!PiNIif^=Q#(8>}z(>hV$@$ z1I@-8r-bQyqlaffFLux(0V(E2o}xI)K{M=bbx>|7{O0c)|Cb>b{TZ@QZ5%XU$g$-< zsa{iJaE5krMEZvj{+$nFeS63E3z#2qB6o1^zMNcc*^owuj=xIHvTs+slgInPl6Kmq zyX>-WKVAPE-ncZ|3)%pA<{CiI@^y9O6U*v6fx!3Hh(yt5kciAMk<18D#QMzW7{C*H zR9yE&SE+RUoqc2~ac0f^qY%9F3J$u!baz;YUwd*AOR1_B)*{GGS$d}vS#75J5ulOI! zaP2}0>}Z27LLV9NuZsGY$I-Cm>BsiqMj129^U|Ij<5bdZPkvdq3q7@vdY=-ju7$*T zg%IU-)yfI&2M%9?gU+kY!9QXAe4vDWHr|J2-i2KBMXJ@p1Kz^fM}$m5(e#EI=&U^z z_@J$V+wC>PtPvX*9(jA?%J0DM2Upj?kG*r~{G1L#@q7pshsmHxK!1;j*b9~i1`dHA z0QuxvK(N6ZW+=MXMZ*0?r*|D#k-)6>TGC^If0zrMIJu$##T!E5kH!RMs-5Cg3&-6b zHwpRb4b}E)%LTsXNygjrG6MNXFDRKr3NE3M5PnA2eRg@(W|i&im$N8Dawc8|%gW2O zHJjsf|FB&9He@y>gDpn8aa07ab$dG-N{WTiv0d9eu=$ivM>Bsj3%-dmhpJZ!>qp+L z%8{qyTP@fh5%_#O6tV|Njph;Y4vz3c)N|q5UPSKKZG}Mf_p8BGxKya{#bZ2oqe z*Yl@t;r&sxFmHh>*x2STuLwbvfxX3Z`sL=o^afsD^;T6e+I_pX&jYtp=6<=3{NjFF zs^z+jKdEiLv;N_wFPFw4jnD=O8}!FgwJrqGzx zf&rypi~dPQPSGIh@oRxYu9ZI~A&pfy@HM_u)(6I4>%9bm8}SxE^KehVUGgOVM-y>9 zM-yu&dM9%e6X$>BsdT@8F)`B#^Me7Y=Sq!o`P>2=ayn2?2r_jBBmDRa^aO?k%-wlR zcrL+Q?XJU6?1z0j)~A@6bb>Kqt zbZlFE@QN3_6BVsouVM{4p(-01-;-(DDhqow|hL+ZY4ev;<#4(hG$YUJ^sJpsg zoCjvSUu=DyYo>!(=5C}-zkm+R8dX_tG~b2M;J56z5N8YWjqH5_C!heM}hhna^GYEs^&PLgHY2lAI#a_L7q;<&A87P&-&I^cq(jp_vxRUybB0fOJ_R#VHBUAa4 zRxi5MwcA?n5?29cH;aq|J`D}6uHqx=uy{}mXy+Ir7@pu2s)Zdm9Lt{zO}BD9#Dz9G zP43ghx4QO-2?T9hQ*Y@nnGPB&sL%Rnm6AWcJt>lC=`RYJVWUxf^9&U~Pr#VPk8g}N z82ijQIQ;}Yif=9~+e&IU!C!)s01aEJ57TIhoOKH05?c`N#}Lh4UlhKQ**suD8k1Q_ zaTaymDHW!Luys+X?7C}s=zm8#7v%CUpk=)B(S@#<=3OI+8{;rJ+V}X@B4A znGUIRd8~d0FbLHocZjxihXzW9U!;v{;1f)gX@CrGWeac2Su74=^v<5 zLe@);Tbf|++r>{`tfrjO+fbN;oxV3;4uXj_ceY;mkb6#3?%>wY$t|TEcDDB^AqDqc zq-0(E@LPW(UlW0Jo33eB`QC26l;w6CiJse3)oPBuTV=hGzTi2Ru}Eq#Fhi%Ry!eWQ&7)Mc?y5IC3_pRjPDXEtw znNi!QqkgF6Jw+i7c2&-Wj9Mm=EP=DTP3DAP<+A8W@2_~$Pkc;94h#g;3&4}l|H2bv zM*}wtTQev6|N7xi6P2t48QVSrq>$=Bc7BPOvKX3ZFglb(MJy-IrO}ejxYb1u zHSrj2U^6&-DalOse}qq`iQIfS2|Fa<)1UiV=buiYm4aulwK;Fb@kIsf%TGWN&kKZr z>)VN~``19B1uHy?0gT}W@cPdWo0>|wn<@|I@n3X^CmODrX@T$RA*$x> ze|9AJaPnVcfvm(KJizOoQ-T&gME$`1-axVVRg>w!Z~ipr>RcrykYj|=c{8mq&}n(zFKzi@D7E$ zk!$eR*8G}eqCPC<>gdr6ME;3FYQ5*?z&2Fkq9S#^U9CwM#(QZhiK$;UEP2;Mx8au_ z$dC@b1*Kv_AGJ`&IMX<^@-A01hTWbs`bo$w-7n~Sf_Ez2Z{CipkI*9ohrtKo zy$<`_FFD=Mu;3-!?_~D-ZkzFz*Zjxro{zNg;H8>`A?hVa>b~0gpcZ9BBb@Ixft)t7 z;2j^nQC;Qc@e?=WNJsuXAZaZA5fEwPH2xN#X}p><6~N1U040hRs+*pv}#AIX9|Sxt+ZHYld_8|NqH*QI zfdAVyzb3XTTi`m1>f~xb5tPBE?^!q;~YuUlq{c&kYM z@Y3n(mC*Q;wo$fS(}uaf%-4^zWIV=nv8YwWRjD$*Xkl4SFw<>*5;Eiw9#$Xhd+ZUt zH^1LD{fQme!&?D^lpR=eSd_J#_vd7`l*Dkf(8r^nkbX!040dMNfdOq$g4g|9M3;Pn z#f`m}r>jG{GBDTA!Fw^xzH$+-*v~08B@-fx2RnY$y`fu3sg?%WJC>W6tJ=3=lX6tG z0~>6$3IeSZ`^yQSBsd0y1kJb>7whXJpsr=Mr8ol(;~DT9T{d<<+MhR8S{E0O?9#Ht ze=5L;K_@GzjHb;Cmg0lamU+ztz)`1W-a+@F`N+B2o#w;qEe?k^sQ2MK?Y-*$RoIpR+Hb!fX4t=So*Ze zuL>e=$`1~^!;lFEo>$bJ_N~^dHjT1Q*Ksg}yy>(RKlE^H@8nOHTx&Ss@?TbWjc^ zhTGhW>2QKvpq?w5My8@W6Qewdp+^@D@3#9mgb4@UK{=}a;8h{fd&Hj5Gp2_?g_EVX z8{0-@TM-v#2bZfecBmVz+tmbt~UpCmd^`=}7=vPTnWOiYLXN zg->_sZ);#TQdXtz(}9dZfhjM3*K;uLK;fc1{w?7BV*V|NaSi@^pQlo1O2DJPDn)t% z?V>aALP&c8C89Ghu3Qc~tL z@mCCImjdGEJObDSvs^JwY9_GK-VZPQ><|a`9-EhdxXyQE zaUBRN!Br-^sp(W`d(b_eS+6NWznnX5Qyn-sPrBuK+GbNi|P4uMF zJ-WgC&^jnwTPbXF6}8)M(znxIn$#YF!H2zH2pMqddUGBQu#C}_L$gL$h)MYvE%URk zoJG{BZQ$g3WOK2YAsy%9SuT^3vx|daDnCM~3N2x=vv4Gk-gkY&WpR)~)_}M7m)nrp zrRX|C@5?~r>lV`Oz#Ck0_N;C2j9+rQxLtx1^Jg<f<^TQsB}#MoEw)FB-H7SVJ`q5BQC zFP)nETpE>{5j2l{>jnPsq^Q6Sd41mf3h}R75YMzrzYdU}0t1fE{X>^Oravuil9kRa z0b9`LQyyf=+E?3xrO-K@lwJrzjpofrADgI?@&ue}yKZU@M%>Tiz8Vj^I9b#=8L@+% zk9Y)ee3F)WQ@mg=J!#cm@@t!)VX>$y9U>v&bcQ-ydNRNi6V^?Z#fn>|8pf4uFGttl z1YqF3#9njJ-0WfrCe)|2JY{f%7sJx@O>8|N#h@l#FBuG(rHIkY>7&UIRswBp@m)*# zzPzF^JiD2pkaJ+(paj{;2-H(Rk<1Y?*}rDyflv}7kGgl-&peGndHZ$M+0CA@k41Qu zM8DFePhs3LlfpN6$8GBm;%XnX=795F^^C23i*I3Zr|}!6D22q2P6sZj`-&@p=DMa3 zXpy)3f*aIV$4{77(Nd@Foc`)vA6M@$X%sMz@wyB1&czp?-J?R?GU0FO;n~-DWneFr z%2yeOvxVa~4Xg{fovWe$ST`D%n{8d;axk7Mx?JTrCz@A;WiB29;4zZC-w;zO5(9P|U$?4IS5Tp86;0T3E+`!m{fY@bXK=eR0ep|fY-!{ilIKOwzjTDg#`Ip2*bONrO;xo;_TH zM7^t3B!NV;)j%;WVO@#DZAaG|#UUi^R!?Ug<+V4N4Sq50v(6Go+@l&c_MoHGo^1lj zo>qxU3qNEEGwHJ?a#)vS;7x9%ta8SlCChWdoTS#bqV?q;W|XYP4Iv>Id8JnSdY3)= zTq&v7?lp7sDLVoQMY1Y2Af67elM0UcXl)SKESlSSIAg108HZI})Q?4Z@OBp>nZ`ja zQN2ctDFsVNpNAE#B@+QI zvV^0p_3`iHUi=R6JyJQv(>ml5BKCNanDUwoX@MNr?b}df6=hXRLSSrT%%z=3_G~(K zo^`(EcW0A<=Xrs2BsVNn3E!zr_@kUT2ZwTXz7 z5*I}3aGL4y3Dw$K54#?C7^jl#Rz94RojdC3oiVy8Ssht!A;|qRKMi;AlsnRc$q1hr z;4>=t zM{Sdso(+?rEAzgHooZy(i@PvOFKidZ93L+$5C*x%b4NR;jcC4hn?C$UoKXNL&5Bp^ zO(YmTEV~}j3}g7|L4$Ms$6s+_l@DGi3sAGl{0BDZUq@ zDN|DAHQi$@v@En0WgH6&*St#jUmc_>OgJLbsWm%-;1X*WHqt1k5JmDejN_~-0~4pX z;y!8Mi@mFZK}*R;tUpMqo)GYW{pPWS%4?bvqF|CfX)=Ni(6n@B7o&#R0e6GroGtqu z*w)QIFVoI=qYKj!#Kq;+_Z*ucI>pUk<}7Qn(Xe3E(f-cTCFQZv_&|85SUpH(BJdOf+MgW8 zzF3CDQDRN8bje#y|AiECZ(L*oogf}jUBho-G!dxp;tr3(BJ3jJ8SH>g;ptU_Z;j6T4DVx0Het+uaq*yV^ zH2#v%+h1HdfWNNQL*z3)cT3U@?wB>2Ic2;$WyGJ^721$Mj6IGC=(LjLDuXQc!uqCa z-hfjU3)|gSgkP5qXx}ch;45}4BK}>(eF0R*ulvxHykuOGA{19wZw@0+^yZh)RLEZ@+cn(lg4?WWpo{$ z<<@=0(OODDE7F zZXw?|e&P5TVA6DIaZ0>BZZU&~?}bPklD_YrQ0x>+ocPje#FA87;4PILbkdczrOt|q zFG;H5uA^y_)beY5n6R9}lDlX_znnM6wJ_>@!2Kob3=*Qh?Fi0V4_dKE5hAa-FsDqU z$76^tNO~nS(~{qccI%kKF07HV_SAs#ZsSDpxm|VgLo*uAAzMKe3;U-cJW}*6d=?tS ztz&3I13%(kIccnRu8Si^+nY)32olEI-NbwBgi^H~N2HjVmLTgicy%<{xEQZ`dzV_- z*7zZrTFhL6!6qNB32x?N@>Ob^yXhOHjHb;5e&H`C*P~$YO`LP0M&W9*k09gjzfNz| z1uWnHW@G*{gYgGA{)@rjfeGUOO~=qU0f{LULY1pvt!{ynowi8c$F3ufpA(aW1fWrF zdj0C1WpgEwf-})oRLF44YhZ{fgf(Pj_M%b&Fc>D0%ZX=r=8~Z8 zm=X{tzuW))Q(pAvRBp1$s^csJp!;#mM(HdQc=4_~8HS)x1}i%}H}yRyaxy7#WyZm! z1_#Dybl^l{XF1Q1ncB5N$CvwM8=$z(6v=kpO#)Rmg}plXq#rtIFf5g5gDD`C4X48@ z=)xQRlAm<$Jn{1t#U~P5MkZ`fGO&{87@EiDO(@T7p+>D=UK8+9OSSE$$n#06`mxac z$1H6rBV}n?X#}_|SnB0(pSG?|m*?2PH%YD6Gu#fiG%#<@f-E);dFY|gjE^wEcy#r_ zBt3`{u1QE3wMc?8$Y@c6I%{b8VRnyYXX>p!gd7*J&(Il)V zQkIJyx?j77G*r1*_M!QynDwT^^CPK$QqVT$Y=Y3zN}&Xf;%dNo)4Wb(GK zTAO19O=b;5$WQ%_MAUg9*ie*9H_VBG*5O!Scv#(K{nUb ziv=4E>R!)srpi(@)LP>ZI8x++mUHZC?gt}k8yWJ;!p~V6Et|4dt#?sT<6beXO|QCc zJJTOkMXu5U0?M6Hv5T3@ourqbEGkB;)Ir9JUXb6v1>J!+=zb0w>d_wwm|JV5P zkk(~90$>r;e@Msvn1Vx+4D413kU~FTb|B|0zPl>zt7~SuTBOP<%v9z?_%tc_-)yNb z`0>>wmL#HFjo`Rl?s82@b&0h*;R4lmYhtqP<0|;&m{gtc!@7m=q{UfGSqcy~*c^Dm z=Hm%#ny@8~=oE*rbPR`eCeu3J78V91oBXt*J$r#eyZHW^j?cDGcTQnzEV2=W&dSgC zk_@llnm?x)1z0&xiJ!P~(QbKqFfxvNo_)ntd%{4TYwR22JGs&JQgq zA`jqz0!HMzqkqJn62Cd5@r>7fLXcFpt1Gr0?Y37HBJRlla)Du=c6dLxr5#7%80BRe z)@$@U8(criCFp|^OjoYX$nuHGmK}C=rvGL&4&DM2D-VzoV$^*(yXy?&E|{{AHl7#Y zlR8Q@gguF_l0MSyj4w99M%i1(eB;j36AIy6GolUkN|SK-dL5U`{n8eao_qwK70*Yu zM{iD&XTtZxM%&O^iUGak#2uvw#9&Ets#Qy!gusa!+t7-@j-DwyfgDT5L*gw{u|QEv z;e070x2#?GDLc1SizEy^9;n|8-dN>!c_v?PM>COTVDX-@%cZ5#~<5i zjPmN&jNkAxcBzwC(Nswk*pR_;B3X%M;^pD054C_LJtQ>q>NCW@R6owdq<)18E+%$Xk=Y^ewAAZ%6#1X0D$MFR2>Yc_C1;{6OJWH+e;wDMD)# zJ#p!au?)BtS{J2M%prNrMMDy^hr`);UhbB>g!UEJsCann?SU^Y;NYKF~vZ}rffgxtMr!0pyrvKt0>`QTF zmesNqBDI-cdURybD}@L|t1Zp>+A;I(9XA}vV!AU*0T;A2EaLWycx1!X-Y9Sn)ok2! zjc+vtma3r2;0NE3=22V zp{dydXSR$LWS^g*u}|M+_OxQ#lV0dZxu=YnqUNvKzI{j^KNnXGa&XUAV<8q_{}B9{ zc68AfgtjE(WENMx8nMZ>BXJp;!v>)*zU6*_qXXwlTlj$9gf$X1_eJG{0>Z924gHa? zd}O~>!r*)+lnv6Q9lH0#H3de=OSO%m1LqgVsqXvgzBSw!!_(h-)z+t6K_UPmhUecW zH-ETxn|K}DAO@u1YQra>FNL&-$Y0S22~{M^sYbxzXnGSqjOis?eRQB$EIe+{*xI>H zaYTyzheK!KNkz@K(5O|Q&VxJB_$7#glnfu$DLu?N*1xYZX>uXKKNfVNH?a*{NRFhc zlG(2iw$U2pUGPW!GR93)x2RkM*`3u>x94pWg7nv{l}Rv`hP61N!{Av_qyqEfi$1@0 zIR8gJ=y=gxl*}YM>oYom9j)Zvp%%* z=aR4R53IzAapX)~XxE%)Q}*rLt%-(vh#ZV7T&(5O&(zNMnv(eTj*jWlD*~^HJ0Dq7 zQjiAR>#;1zQR%OAbuSQq1>|Ym7{&it_VQ=n{h!&(koy0H>?Na(7ofjP9T${_{?=dE zWumsNSjvBkNoZ|c5MSh*XlS<%Hs;MN%5=cyV`=w%xq<&(_Cj?pclZVfhSPs$b(sJ7 zY-5xaVlx=v-l-LQ`GvgNY|1ER8api>7)sk_n-0;WBd`op(i~qNoN`T)2m7iP zernL>t2Xq;|FzDKaq*K#)lryRY`17>m;?p{mO}($A_w-YXGOf9$yb+SKaC0Ga+2+S z(&t=zOaXE!@67@iuZDqh;ZS9cImHM&qOwwTqrxmybko&xW8v45)nE zNSHp7SXHrRwPmTB?b_Q$9m*v0QB$fc+(fi`w0i3t?(q{=rvLeY{z?|P{>!p8r}U_I zHt+@E-Uf>wMrlio5xttxm@3aY(-WjlNzK?(j?5Qp2rTS-mib!X2ZpVkalJZ|GP;NL zZ+QpIZHX-rsI9Iclq|i5Wk$@#T2LfgI*TzO1W;a@0m=aw@C05MN?FQos91WNYUgr; z;0AenEF(L+1!%sXr+Nvjp9y)1u6`lhj7tG|!)?8w#M?sf0nLcPLY`BG<7l~M-Ar?x zr8j=$*aVqaI4&7&Tr=ewth?86B1n`-qpBaT{PKFBANZB_L1JdKX18qj*A0M0wo(uL z`;qhS0pt%4Z=;|k3lJPTBKJYJNaT6TNKmMh1wnWf>9)wQ4YyM}u#-3N5?Leyyggk9 znd>tWxh?g}C?9FfRIw=7aqoUwz<;4Mi?0{WTfBa4;)I(*e8NV6)WRnZV$O~MTV1XwpsL`RU*QYp9lioyRulSE#_Y_bOu^t0rzNz7~ zX=7+b-@jolKofP11{9LN_2>Us@%(GE{Tl(As^yOWouaER{au35kA!$`RclHF9E0w6 z#bX8WyW$z3D=nFCm)EQzIu2BCFp(>YjOc3`XY@*-H4Tcm&4Sylt(r`GfN-AJP~K&} z;xo)V{Qm@Kv^EZiFN&-H%s2sH28T)pR9TMZ@S8Kx8P==kV&~rsK#YJJwPyf}PYE#S z|3k^c{HI3FN?CVYVL$>fgu9U8Pvj=iW>9ewbTbA&8amPMv8;%ssz`*c?{${90?Tt{ zt7-~)uBV4AJEs-O*s?%BU+dcE9SYb=bHEB^?a9mgkV_%8BuJ>p2MIMIx|I4CH|&cWtF9#oKcr~$tzSfjuR zIj5tf<~Jt;SBRSk67g%wUU}r)A`dF)awoed;iB9;+v3QA zX7$avhg(t8+}^+Oco=#*-2;Oi00+Wh~#dt-X!~_G6)v(LJF@nckH~%e9 zsQuQwIYN1Bs*<}6<5`w>wu)y(j7*X2{#g@?XfS0zSA@0X;pD-VK&vIq!x^GM0Fllx z#&LtAZ^kWMxMJfj1=911V&OV?C4P!=m7G3$WCp|IHAWb z+&BGnhWO$9J$>8t90@6to$qzd3Ri%$=*fl$eIX`0KbSr{*RbcesdM8skt3?hgKgke zL96h?6yNblc!Qg*{P^aJ{8h|t7f(jV`guLcLD*&4oyI%05Qu6@MD^;K*CJs=vXG8$ zd*EUHo{nDm{M%HpP-w=(MR8hA*;5A_DDhYu_>x3W&U-O-4?0W|e9xV@dA@v!7oocn_-h`8rW9_5T zE}Ip^?&%vdO9b0B+j+7H9dr(MD36V|CceD?@cX#~VY$A{%i8oVe-zHbNh&9LuJacE zY)46X0>rMpM-$UuLAEJy{Wr$MpKiMyLw_{Mg z+&SfZF`ZKMUfB8}?*qx&X3zDiq{>YX9RmjN-+gV#0uWPdvQZEs2M3KFIj75xK#iDz z^XtMf3n)ffW+d0DVjh}}5^7KhGwt&F=4zm#nq0mwvS46Zi4bPdPk0)ca|2 zwy;tlCMQYI@vfVT3~l4X587(S@zl`_I;iah01tpgsD*p8?$pW3v3~rmlAh#6=zs)l zWbc2jq?!M9Gf~p|?@BsE5Bv$(@VYq$P)U!JS<+F7M6BqFBEa=(?&dW~G}&!3l5ALu zNLA|(It^|T9FVB7R5yXyPiqx5=+w@%dXBVCNR|ZS8o;N^!muRUqop%9Hv-2u=SyBm z;P72ZicicGPMk}p>+dGb)iB4~lu4%PS;@QW)H1e{-(PEU=4@FgMls{`_>{Ya65+M& z)q&WMo(%KX8cy!+n_ir*24136-EZ?;CuSn)`P59P(cJUr5;%1Q7?fc#B$1_hSZV;_|C9m4fzH6W97VTajiGZKKUIbd`0#3Fg~M<5Q`EidFE$<7oIi9 zcfp@_PAmCNg2yBC9AO$@&MMt-Oq>pndY9B+uw0R2ju(FLLB@$^#ZtvjdgXpboPn5l zmo(L!{vj}kuR6Het7h<1aaCMEpw9g^VkOPisIA9f-F6-t*G8#Xe@{~18#oIi`~q)E zl+!`626b?mqEB=ao!*%1Ml1cJmX8MJTQ96Bd~4$A>!d%*hN(5Bl~kdW1cY&u$06Ni zsuB_$+uPr0I>{eqX?K9^ZU_Jc|3)(SBbeI6{kN)`#1fwc#*mFY)!urt(O! zKqJz_wsJ^s;vR>YnHi5{Rm5`)(vrD7OpYKTuS^?KR{m|YSb&eT?Htfvg}TXdl>Ml? zF1lrI&6gB{4SG})MvuNdjV&ZR`M$0dT_m z@#kf=$$TQHJgzfUDW*7Hm_)$QpC3H)PTJqRgo8dIA-RX%90M5P4}MBq{+eF|B6(Mz zeNVPPJO}5J07C)Y%GDIyOZiXuR%)cPa=J3i`C&|Vn1+j@x-|u4V49bPp zRj;~zj2C^XwC1czYy}Y|lOA~n2<;NS5~dJca&vG2tDE34K`3N85QDe7pk7?^ z4;xGfQmhJ{CWNc&*A%?Mwd?s;avAj_nixQ|YxdwdzP~WHgn_TgD)4~5v;nQQkI<(}YTUSt1*$PAU;+@!7Fb&u);*Efhs3ZcpWd_^) zkOM(8tej>}^vamMY7j0c7sYh={BWZe7(Vn^hqbF6mbFe*;k+9Xkbt>cF4wHM#lBD= zP=zb{aTG4*y9VOR2_ytEBz1UX82lv@ui)%&X$&t){n{pA@t6L?;{VGhp?q$e@!JqH zhA40T-Bt-)+^UU6gAJPW_5}{nu$i%(!eF(4HMP zs|qQTzO{9ccxo*3^nm>B~blk@#-81j^^a@kG^Dlhg)&%AzSCUvxctx4zrLNB26# z(4uCBoQZ>+BUDSP^n2}dw|a74cfnQlr3tQ?e6!g1_mhDipS?}>VmCTd3mj_%ZzBP)PI1jv5V}jWjD{oygm7tdI5np-9n5?hpnM$N(smdVE4_GeE}ASBfyC#fE{VcF?4GTq!(h@Wta%kafNZo@IsRnmS)!lJ#y6V zWQmTULV1-^N2^wJH;5Dg-awCySz0d@#{*luP2RLa+sGMLJA#M$VjXUKH=&hs(=I+f zwwFUwiB9mKo4Tygi;1N!|k8v^DlOCeH`mY<9_(_rQt9`SS zx4*e(gpx1lvH+rMEpa-MM=x{wNqk&X zFvU8WmzZf_LM{?%Ei+z>sjQ&7rJbtCX3$cFdzE3z45Yybw?z1(n~agK`fAnN{MGP% zJQMCu)8u#_pZpUJFQm48WmS-rDP^W?&A?Erm(k9()@)=nyH|r-0_@3@Z==|Um&Fbk z73c90;e&H(gJ9Eq_|8(hOX@QYuRK_d)H$L{-tTo?)MVAt1#x` z*XlgieY8BX=9=K{LTJksV0`NNX|0&|qD}jUidTgwM-)CcqR2_UM%G$w8AT9Vi71|F z$NX~#@uuGU6u7w-T<;35F~eO}!T#1!!`a?+6uIpJ&V1knr9==Mx$mJKv>1@NYlNfN zdEHe<<8#x$%IO)Z_+tSboXml4KM7+^kA$04n_3-+dd6y4&;L?xK4Gu9h(s$Kc36oSY<1vbf7e#( zKp6j;%Mv&6!5(ZqYXRhd#j?KBP{L08 zb1(QvRze5X-ofR;5b)n%pp3yP_<~*i{=Bimopy3BG|5Rxb{2X7}xu z{(T3%dtBbaoShwRr_X?|^n}$C3bK4_)z7+gQS$4~fnX*{(c?%yke1x=R9%C<>zZYs z&!CR-BD$wZR+Sd2WQ0UpMcL2mvZl!X1o^>MbsNy#0XkJ033C&OhsdF(2QMaO5$HuA zC^2^E;n{&*;yDJJF6A)#2_8}CU>5u0(6l_&jU{k!pmwcLx|F!nxOWBJO~3!2)61TK~uLH(IoN5GLa4y^6pqfshkr2ODoO{|=7xg&#K%~39p>@ViG@v;!V z$7r^>&_duLGiMzPB?7M+0=embYDX2Ts^Hfzhm3W$o(Dl-)lU_PVvy|Wol%zJT?`Mr zA&t7~9NzIz+(=hrnECA&whslGT*%j{N3LC<3bHLlD`<5&eqHxq(j5n)4TT_Lk(GAR z3k%=UMpc96{&84$(Km2*5){8NU0Mzo2wm;{>c=6PF2Pc*)kT;_J~J%P7}=2m1+Ef5 z#qQ=zc{Zd_{C06-#`0;qxbwfUB+wecJ^v%Yg!v!r9z%sSP?pJqtnL9LfJ59_=X1XT20W)<>5B99S{CS1wCqKl^?9=C|FW5Z@Sc(q&yAAec0ZDaHK%r*Gz+ z;_w+@)^UTdD78`$?42%8>RIOL0Yd_$|V=vI5?n};qr0jgDoZ%|Bh58_~ z#CjJoJrDw~@`fuXU7`hMLT^<;(zk-j-YE$K9nyF~H>56Cf*W*Y3&xmyx%`CDUn~|* z*r{Yq0+n#qI5#pX5^fs)O@|ygzqAa?5lBOW#S=9F_5Nf1279FNCaKz|&(#$M2$38g zoZl*Ul_ZPe(6(rqOY+=o%rmM73g|nRJ^oeG!CTtF~*JC*S z7bL)(hK;RAj;CgpyVuD{%WyvWf2JGD?5^?*LonU!Y&8wd;Ttg9Z??9U1`+8G+-e58TSJ%`yj={n|m@NTxg zk}r>0VZAWL+HbqbImHxxAf@7E$f?xuYt3oHroKB>X^Q^w_HR3e=sF7%9RN6A{ypIQ ziLVfVL<{hr{oxf|{AVP?h0F4ZRH%FiT6+Xp`vDTI9Zai_jG*EQ(cSc}9Sc{xRbZze zS$PtllPSN^s6}-X{}E|P2e4CrmP(mRK)ocy_uQ99$Q$+VuO>~NI`#_$%13VZNvjL; zqh^^|jZB35@bOyE$O!P3P>2h85qynzSQNZ(3Sfr?TrA;*$!X*xiBkmdlM7P`>*Akg z?fQh9E>8DU8&|+wKNF?ChHa!~#hADqozWX1j*ICZ4UYcY=CNgTNUibe-xass9*232 z#xA(PYr*LSX^0Y|BrWAtT5D>1hB-m&`nICWvrl4Mn^5`nCTuX9bp{eElTr@i9QR%P ziWl7DnBlg(RUDMDbmW0x`EO^m`Jf>7{%6(ZpDFz})n=Rg{|(ti?tdn`sQqWzCAMrD zH4hLGTmS5|W&Yy?ib+wh13=Gjrt#rR5;`j(zh;2B&rz^urB}4HBXIfGtZe!k-@ ztVm(Q?C|rCH>ZcFf%RMcUlSKV6pv~YHfGyjOEQJyW!&VUyo@BLyc4i#z^+i5<7ttF zRUto7VIe^5mLMsH-B@%s4?fK)7Z!$ofoP(F3BX6p9XCMV2+hHsbZjSXMxOXywDbdZ zD#tOVBT_R}8a=m?g_D2SY5YUY)RANU4w0szi!^57Tj*SqKyu++eQ z@5loreVrDrF6>|dO${ay>>iC`Sq1WeNQ2M6n&!R&JRkT{vcU&({1mem!kPK25i>?x zLFB(ez*O!9w|<~LQYnLD?4)G3Y^nfL3~z-jC6l{Cub?Tq2@iECX0*HDVP27&clXr{ z@KjXVLgK1Id3Aw6e-oa=ppZze{UrD!Stsy%>nd?Y)q_q6I=!pb4T7_Cum0$k|y^Hy~Y!%L-k(tV#)rO>nll_UU;H% zJC!;NNj&`a5)ZiQ;)P?U{Dahr*Mt@|M^T$KMeGNR(wGMPktRb`Z5?u|*s=K%P9NEl z*Mwv}lm|&H<>}O>GtsZ)0a|n<@^Mb%TL)abgT>TruuLZFt!$w!Mr<;f$sOOq#r;dqay zLm%8a>NW_izw-T6PgX>bo&O9#JNbW)c7HTDyop-2^;$}pmr>_qvO`NwD%N|-csu$ zDHM5^Z@0YVII5fNI5eq~6ImirIn&?QH1yh&nG!t{*m#p+9k>z}(PNYRVrvqaeVbcA zwtsNGoN2CddVz?S81uj(PvFOl|Bkd&m2B#~*k_!5Z;+x2$;3+)79a6g{GecFGzVX& zw2x>NJ1$nJzqR!}ZWY-B6xTko1v|nfH?NHH#J5n@oQCoSBUM`!MtJKhxu~ufuNDli zr8iR}&u%q_Lr^lzoXAZKPet<0|6=Yfqw7ezWKpp!W@ct)W@ct)wwNtu$zo<^mc?u_ zGfNg(j22pWkKH}SlpIwbTTlBM-P@%UXjOR7b}6{GDX{W0}hHH;vCM zePE-n+}_|)+Ol(Yo}P?pIyz@?VP?D0OC0 zIbsRnE^2Szuudgb(u}(KOR$R{ezKyLI!&A7OB*s?)pHe2^ZR@Cn=6+mM|uQp^31AT z#>&sW?QcPpN-A1r_sRmk8kJC8uve1Wo~;hIDyAtcwE|n4SfY+<+FhC)9}A;xqQ2*4 z4Gs(KZ^_@R1(?`u4431C^YJ!YBjFL8BUIy)sJ8)TZAg?~Ieed&$+bjgEDP@`sreS47iPsgsJzJKcKG|pXIa9m!`>dJ zsp;k~nquuT7443~e4FgN?%IRuf|@6r^-l@Z#O3EE7CW+^@82Z{Ua~_l%-2!rHq<`G zJT@O|*VS%2UE4XgEbBpKr*g}n6qN0(mpEm2g}kotw1Bq5bTqh+Jw$5qxu#oZOsnrS zm@MCHaT#hz>-%2;@ILHc5=qPLaL?jTZY;SR60k_?gxr7E^< zm#>@Okv$(}(zf3NC*QDX%oJWb<1c%=AK<|zFMkp1m(Oo#ab(LZp954RIVnjVn&m<# zr*xHVaKD#DL=zOySecJ?9H<^F=4cs~gC#4~7mVa=PQ?(Ye<{)kkxtRC1jEo(w3?y8 z%g_G&AfK4`BQu`Z(b4Hl5i+Ge@O&cqg%^II{$)fdp<_AG))&gc3`ppFTHU!KGMYgduE_6daSz zUvOUIkr-s8bjXcAc|*sB5!{Ex(k0dgKWYxj70JkQe^IJYRTdZLD>)f;|Auufue!!M zuCC0SvG`Mt{`5Shj8pH^sZl`*y{Lp+O~H=`pbYs!&4UX*8yJGWfMQnpJZsiZ++yHIq%HqjJ-3~Y_Co(cULQ)_}B(y ze^jHy^}_fF&;xe=dK{25H_ulnH)WNGWalK5sXIq*vbG<|-c}-KZ+W>jNA2D;%CNSd zgAW5bC5q0Es`Ky!lzAn!-2Mu&5{&R=$(PCSVrRa{H5Iy!3)r^*ti>J(m>nns)-VzH zBeTD}8}K96b|SDpv%ew);g~%T4v?}NJo)l9E1-u)C# zDQ;OK?eMUuDA{6l0C)vvIF^i;Oz5>{RCP}zX@9vwPrFs;yyo<1>?MVG32VVGa#c8< z&7LJcY#I$`Z_AUTw@PHPa}vwcohRpLa(A#w=2_dvuyay~4FR@5h9Quy_CloCx(o{6~OA6#)<8KLRX>`78YYaq9PRM7iIw z{}to^2=KuF6XV~p2OPitBlfeC$CX}J^X>RAqL*y|arDKnK6iw(HE-FCYUArJ-34)$ zdhfPt?l2GIr7e(q7vge~lCjav)Xhp<3Q@vjv%<^Y;49F(Bje(XE2-;dY6NX6x{stZ zw2=8I)mYt04xgxMPC55pFq4;#d=9E%BWh~q_J6ABrFCc}jc3%Ak&j=TD%?Che4fnH zhPmp9Z;>x*8HpG^&U7Va^6|@-Jk6OaO85e{J803jf*k|MpnKI7(|z z2BuHBuUWbd1Ib0RC7Yu3%n~$0YQ;&l$*n7*ul-{0Zq}Wz=f%?{%UDpR=OxgrG$!Su zD~nGUco{Mp#xK^>PCS$u>>hPfL>s)Mu7ye1Svrg%{ctwfT%h^58w^QE&@n_q)>tW1dVRN z_mW3Ym;Rj&wHE+J{n@+;1OI@aKSJD3`4@Eg{Zs-hf4>xeqRa0P6XyICUH*zXk@oVL zyACT}`}VKAJ1SP@HJuU6Y_4{0TkqpmX$KJ69ust<$Az zXkwKZBB@v7QYGSZni`%*)Gd(XkPkKA>~eBCE#eL-PLEk*7UMrxKH=-#0GSnLP$(@u zTuO7yb+K|`rtKAZa$n0FUJO1(OoqMxtxT530X0Pyu$=ma@h^)g{@}4_uG;T$BEFyr zT{iOXJ0n6eW=+c1jmj>u*G)Gqq(mqdr4%Jxe`EMA(!C-lAYM-Gicx7558%p!iSlL+ z>~SVk`AgYq>}o(|XcfPg=LJ%jYvG!0Bn8^}AtS<_O7Wii1%{*M_E_zJpX>78z(&J9e}nR}l$f3Zca+N2f6d z=@3|_m@H3}p`ou?>N_Ck9GahjLaCC6F;Zypg~V~MScjTF?2Q(v*P|73-4+mX7^QTrr)0A&u%lI>pr2($ zFAtS%iWaNf=?-GwSlP@-JU6krp#~6nMsH3Ln+=6-p?A>9G)WH$HLZH(l#9z{DKsf- z!LHPidD9M|MG^XJ`E3|+poZe2vcR0Z=7?aSAns*DK9Z$vCc+xYF}5hgFM(XWYpUs**3iK*x7<2> zV!+(R;p(s9VgF{s)ZbuO{Bu7mcBsRqfBwB zbR!zZ1xmWCgg}~~Dmq6U0WP>M>O+Iyur6UmaJ9SaaNCirR3X^3uz}mFcenCKz5Wm$ za|jIb=-%N&;#2GMZo<|H1Rd6NI-k#!QvIqv8InR9lfe9HNyPShK)I!rYFY&H=+1Sz zK|BV^0xFtuc1r5hUaDT{F43HexihjVJ=OuNan#mg z5~gP6!sJ-LZ8R*p^UWGm6>Z?Nm#-Vli$+z;o~lj1G8{c`i(bn~qO0Wu@kp7?Mx&8A z`+8r0)p_ZuLC~zfCDCTi4*IqlUrWDGVjfazMzujT9YN6T(eL z?XW<5)4_bdo)fB(^f)8R$A^I5Xt5v=Gxn*x!0gNV==G){t00%Cnn-kT%2L%0f;+87 zMyagm9U~NnRDey;Ea%9e3|@}OhQWn@pA2J1)Wy>*{w%LuF0|*% z-Dj-Hh^jur$rIaEqgIU#zLO(K$rZXiLN4j;b>XT`pKxIn)*j5 z9XVM*iM{|pMsknyM0^^>op-!CGn}F@!Tck_ef@?t?jW5^KTKRGjTCFqp5+?e7QC(x z-c{n)*{oMUscp8hH^&O;UfCWp2=D|qM5F*@S`gyr5A%<{yU}ZOcvmm)EYB4+cs8p_ zpw48Ut_KeGj+{l2C9TNLvbnc<%X3cI`@p}rFwdPxy6Cm)T(}eWQ=6#Gf-uS)5T6t= z7GNM{9n58a>soA`U_#<)3sR0Tj)H1;oRF{60=mzmMKd+YXT-nd_0NGCypQvUivs$g zWIZnp zzHP*$wk?q$C|vSo#voyUvPV6rOWnFF61HwnUmL<3fY#l8LL(*v zOizHccU@V?s?`IN;3)E$`yRrt!A6)MVHXFeg~ye7%@m)^Q#neh-!2QBRW}MZOl&o!mSW=UZPa(4`H-?L>Nw5AtFlw z%-L=Agyp8)6i?(?2jq2qs*SjlP)fu^JTV>lLNnm;V}Z3+-yn{Ox}WO$wto({@04MwtEhUNl-Igti&^Z$ zhhGEV_Nu7+JP*_rU(5rnQ$c5*Pwm+tcy4PV686L=u3AiGQKwkdk8X)W5lH~->N~UF z$(nW?SBSQdS#<6B&OR(;<4fW9H$h1RkibeYK+gIOkh4bn7YY%--z?t*oBv#*lgmru z7mcGtL-wVa0ZlU%san$?-wHpthYLnr(|$d^=E%T1mzT6fWlX2=L3B0`4h^0c@6!4h zI8$uMBvwp)$~9ixBE3-iE({+TJPqLv}?9MTRiSAoixNd`p~)FC7fxy)?O+d<4?dWV^UX~?*ytKM@41r>48+;sj$=CH6`R$4rj!ozg;;LYDb=_xaY3yS$H|aYak5^gp&zvz1+C zNw_TSxr}W~5=cOBG7rQfeU5fC4J1*)P2U;8l|big7>LJ=5T0skhWx5V9inv4u=4QS zt06^CeA(}-6ZVXb@KDIG5q@FP>We?C6|2(fSQJYFii@>7@hr`$)6XO@ zxLUiC(V{ynJ41iotP%DMkKn!!!%^^zX`lP+TcFzG9`B6+NrZAT_s27Rmi=fNNy37g zzBd9Qk-~{gqVy=+daafaHA1wplW9Nd8tD8iJQhrj%Uo%t>(_-4&dn+l77#DCs90T8 zAG46((f~(A3Au8b-sIps9AGyDtLGSA&YV%yfI6I0nZtM6MR%7zrD2XGlTR@}*Hwn zR7a0{$}I4aM$qWY^y?Wy4qYx-ej$9f$sBN9vgknfZ<3~;za^gqKy_wh&PRH*fLATr zbUAlxXw@$E&&gp4?k}b$4D6PAB4Itu?!9I}2VKgxm7L;w;MQ$Sh9(1~h?j&eu&waD z6)kw}mg$+jw5D+16)PxRamxCo6N(iRLNVRl7v89hzCt_1Qx!^VLEet?#7+@Jkq?(wM?o;=($Sw{X zbdFq%Nu|gYIQ6Q{H}&ORbNcE+U-PMXUt6NL;1{r-_+-4+%`;mOZ{z5a;i!r3zjeN| zSiTJZUMKKZ0@+_Wf&YK?gIE{k15bw0odnqZvxoloP5|?kbzc%NjEIH!=T6`^fhv(nl?qH9M`t$ zQI^dDROsf=Re&P8ryo%HbfYDzFRA{(PB=Z%q1IP~I?$IbTR5@nUgb#a-|}gTv>CA_ z)8&>XE6pqU7Hxt2d#$@&QSj?NDt>UGJn4 zjm}t(AJ|bLN+Y~6`G3O`oA-#X1aexeuwQSx^hZ^yxg3^b&P_A^?}fDddbthV zrb#cwb{R#9nfv3Dly})|2!2jHSbp~Px2l`I^q#OVdLc4P`doX@(`pI<5#Rcr?m0Hz ze&&+B!VhZD@8bTz;egDiO;ki8Z+qqboOUc%grLZgJ$uHM(07|7A`Ul%Hse*y_6f{X zdE^1Pc_Ys(#2(;B6l(j9FFX0(`Juf+6j(;D$#i8!01ATCU1MgBthvaAdL(hO>e>XkXgj4x`K>+2=tP#NwhFV`(3L9~-jA;Qw zbIpopbgO~q`;Yq?K^W_wZ5G`u%Xo>JQihtOK8*XaFyK(7$uF#*rAcNx^CJbNGpU;w^Phn*kVfJvKp%s)+jp38)B9AZ?KcDG=>7<Wx2xNv{G`1N{dG;D+ZS!GP z-s&&Q?NL~SW*~K21lu7fs13F3bs0S8(ZFnYWimmaBKdzblQm*jpIeC2u{gNMTQ`V*KDtO>U~ymw+V*xR+hwA^R}EVS5!AFUY#(K^0i!fiT7nU63{-vm3MLZ zR8`1Tm>nEKKRNrb7;&j+SlBP*W5@37k^?^#JPdg*_mbG(GCqq5xQ#?Qw5 z^KZ1MsFP>me-F`qKaT%>SSvxN9K1*!V|N9T=&DZkJbVH6Ulh?a+(>O;&9qd0DWbX5 zg%`0HGr|0!h&DKMCUu`?A!~ZU%F^uW+YeAgTmFv{*|o(hvW(vX^?&FCn&V?Zten>Be}Xw#XAT ztzJ%QPIwnndF_)<(U)Rko5e-wu=j3vvvEx4Vv=#Dp9zLq4`-{3)|ac^ahy5U&Z!X6 zTGy_~gU3=db?jUxF3JpwDCrkRqJy`Sl9>@rx3keaR>n!UH+fPEtKT+#=hH_R?X&R@ zhanDbH7(eoP1qQTC&^K)@V%(#<`b9nD>(rq-2hie?$Y51+)5g=9#T+|Ty7Xtfvhr4 zI9FPL(PdM+x5Vp3KFrAUBcJNL%dy2yyHn*|_VZPrfYmv-IJI()D`LW1hlVej7<`1s z3k#$j-I`0lxB$k{q32;aOAE7_FWzQwH=Mk-gHFE&NxGO@S?T3sr${XZ*mO~H>9Dv$ z$f);4H~)$q6oX844lPJ{@!`~n)GXFBolw}<6}atWwp&+8(X(SkvZq#)h`i^G>jNV` z#CtQ3KG8d&g^=iBEIoAcTiD>7@&y*7U5IRe!H%e3yN0-UeCv;<9c=-~YXalSXlXmD zULK&UDaqU@Z-m_%5wo;91i~tc*LvynUIU?RPtsxC4F|%{2bV7?+XW1Qx5+=4QPv-Sth1(pEb?OTjwu&* zd7IEUMOYzYB7Gf`C7lnujS*`Q1LX$6 zkS|S@ndp0#`;Obx@=ueiWH@Yu!}DFeLSpytj$J@T0shV_!qc z`e1w~hGZmw{OpH8R$S}>*cF!+d!z`ADPbhg?-zG#*yC*jDP~|(#}bPPS$Ix*{V|<^<#-zk&7&8^eN!S1v1{y#a3qUbsDIU=XvTvVmxiz zYCB~cpSXrASTT3Iq)WtP&{24PLq1j48s%xdpxT5Yx-JmBr4g)3rE#o|L^~yx6Q^3I zqA_lTBzbv(XExS-e}42MSY9NQbVO86c47vMadHC(xODimQUz!Jeyd=IDvI1YoLa@o z&)_){7}Y^ovN7;&#Z7Y~QS9CXRLpgMP?6OJ)T&6Lv0RzFxn~NP?1AlNh$LRmB5Hfe zY<_U=@#s!Ck_1;=bm?j{O|%y;kHePe)#Yo-TN(9e{IO0mO|=(AcKtR)FVR!PVmQYV z-cgW(TU{v4LDbUoge{GOFnsAY(0mxuxo?l}RH+wqqfS zHt7?0p}w066Qh^y<6V2$k52~LSXS~MZxtKflPE>-3bmNy&f1qnw6>DrbukJ);-*f5 zwRX97Xe(gn!icZFBs3XxXBTb4W5hN*$mK;NFRztLs&MToV!ty=75J=8l}In@7l$!> zLZO#FdsF778djeHbBilrgtWYh`PvB#Z>?9C)w*&i6HcMY&KJsC;I0vNY+m0MB}xxB zW*3jSj2S)yxm_88vJ2$|^wvnapq2#u5W^0Z5`L!;f3N24_`0}fZVAc4sxi_FFY{ImloBxOUBM6M9&Yt<@wSaCqC7`?x* zoJv1gB!QdzThH?zjblmInWIvEp@YHvteE38-pYG?Wnex(uNbAx5fxsIZ0JSh2o^I! zpp&EH@Va7p?qK+u3^9ZAI)tl2?uO&HU=p{GN4ywwNx5}Fs6t{f z6oY{Ub?%^P`%UR2Kb#H_ZEnXezK7^a6@c}k$)MIyhi$lwOztUsYHLSgS*UoYIt7!f zyp^{XU_(C@YOQ0L?xc^d+!Kss?DYy(nqW7kA&;*iLUxGQJ?w@UX5H0#ee`45QNYwS zMG`UG0Tmx>6+!f(=bvUM2k%)-vQ$~II)Yxo&5u?or+zd^nr1{=(HC59Y&e_fnIi3G z%wT?xB9ghoZMq}tj=D=Kj+kSE+qP6!ZMrEaXwSX0vEDG(OIoE#%U{q(ifnxHVNLd2 z>KHB{xtq?^+dC2}O2?8?_-V@!k4ve9q*nxaNW}hztXR?ow&6i!4^L6BcOL$EGr~8a{tXtmJwz>C(V+ zQ}ta|&j@F`e#xgKB=Lgcz`ArbzI7|5JKaoHbb4N^B3WuF293NW^XL%R>DEwn&mj+h z;g2SPUaB)fc?R-S7j{NbLSqZ%<(K1ORR(Bln+G5o%x*}@oc;0D#Gi_)itC^Bh4eD1 zlv&MWoJ)X zMCcYen=v}VAda7+9P=ef)PsqWHIO2M^~ESttaMS4tJ;JYLgx04f?BcBp&{2H>y{BB+Q{sD7mJcgnrd5S%cf;EDnVOC2dQ5L)RpUb)|3$Pi1qUAv$How5NI z{NDHmA}U{e*BW_2=GV4Wg-K_roAhJ;#S?7G4!AFMM`NiL+rKq4f!-Iwv51W7&`Dm# zYP)bAq%IXNj>93x3$Hf&fhkKP>-c6zXUQZ$W{SD@20|V4@HCE%#K%S z#YfsI0}!m1Y-59(76$v^&VvgvFZ#r!UA`FhVqXAsB&> z_9P5NTr5dJm7Q_eEa#bCM3ei%7-XlZ*TUEdVcLc|`jR5ulH#_zA*@BJ^sL*6_JB{O zQK+N$opGVT@r0{27;|x~bA&p#!r06;`O?jYA*_2FmHA@&V=z`LprkU*+kopM7enQiDF ze25xfVRisO-~8f;jJSeEE_;dp!`h7}dVTcex@Ig)8orJCX=f+$xG(2Ri?WR$!SOkAHBM*PcSZsK{rSEN~wO`-H zNCXLlK$nF^%ydyCWSq(Y2-3!MuBc6P11gDPo1%IWG;*xYjRyn@%#9yFwqpS7$CI#g}Zw` zzES|tW=QAIP?DOA)@p&LJx z?^~2ets6fzmwB;i^TJS!73P>Bfa*B6w)ykeRVHmU>cWDcN?v|r{L10W7q5hOOv+=L zJ^8##3GMY=kuYp`wKZTf+Kk)_aA%62&p$9EEc}|bM;3lIf_t$-^Qm^0fDHM$N%mVf^n7koE92D}(BtsaB_*Hi1?bD(66S*JDb zU$W5OyqVb3icpvndy6M!C9x9ab3?Rj<;+Ht_lsV9&C1Xy^rO5D`bGIAXwJE`tLJj$dYl zgk`l7l9@?2PBv0DY_*Ddz6XhPl5b8|J&Kl!@G)27nF|4gVzjRIYOf8 zYJbQ0d5jccP7$mr^so^Y%2DPs3_RniPTfkjGv!h^~okP6Yep}Op8G`*MOe84*e zZB=p-)*HA%^}beko*+bT2xb44_$$>jSPz_)t!VemSW6hCmqeQbKxqsPFPaixI5CM` zAgM4jmVC3?Cs|x$E{+L0+j!InxW8hu6EuCqLwUmN z)=d0-o28Cjb^k>;kv&4O%>BN#r6#$n4jLHy%ZMp+^utj4y@w5D@vD>&XvH+?wQ}d| zlf9&o28(@VeZ3eLVB&Ggvr96G^W`!U)$+d5TuzPPi0Y}^WB7V7(=BVZnAS$jJ$n5V z&P*&-b1RK$N?+2^@R{gAf#TPnDp_60kltRl`9v}!l=5#B1SlRF zbJxo--);SBBC8!|#942ZeP)plYY4#E_QR^qnK=0nN3zLr$eh^}NstfgLVRsLM(Be@ zu*|iLxy_f%8jD;zr*l5DzPdC5O*t_oT@I{%U$8b;Jy%L=99r87D>a{C7o&8#Pk~yW zOte_t$RDdz+ZFYrr1_L^pXKF{ny71Fn2$G1+u6(QN>F%Fd3s5zCT3jzbIGPBEBlx`NbD0@`3({#%9p< zmT!(ATGE@G8rxsrV_!Xur_X5jm5PBfUM4+i4)iNrnczUsisO{NM}auuN(E1p4VCbM zRm2JINhe+B5rpm$7ScYTH&$GV(VG`6WPQIPj-YOg9&3@<-sOGp+WNAWjHhhJ9XME( z2e}gPrqwBF3mzjg!90S7!WADk(Pie)o}Kn{G1vfh>f}IxiDwnYku~Pf<08Zyun0Lf z6tFuDrQX}d)Nl6E=HVqLNz(c1=lV_Ed${YYJTQ5?N2_YS?O{6}6It8om3m6y(BGn5_;e*YXp39Ez)f0?7dP!)#;+kqgB%;$T5+{k z>@ci=1ssT3v6myn9$_NdhGZG>n?kW>w~?h~=SE8o_;Y$>WZL#>8I96KZ!`bfOp+sx zqUU5a2HSuyS@PcOQ+h@0Ghgf#PbW&9wDaDN(JQ`kqbo&dvMuKNe+mBZ8aDe(sk02h zK7RKAXB0_EC-%v5hs)9fp8NW2-NP+@%>$m_zS(bh-l$s0%B`m_qiB%#wr3;2Wkmq^ zJGUwaam~|nSi$&>I?Om~`mcp14z#U--?wojUm8b>?!Prw#3asb~kkHp=JyGmzn-WdO>@EKuqr-u}(J6+8U-!lIy zgw4SNX4>(q^I2%a6RA*#q#Z9HCF!c!a@CX;_UV#e2=7e*Y}Ee%lbFhLP%U0G$#Wyn zWsWf0Mc7(ymR=cWE`mo4Zwb0Unc1#Vf*t)~=JFf(3OC3ZJ@D1r#5LP)q#_iliL@{0 zXok&46_50SA3VvBDKz~=eL(pFeX+tzt{R&&1!dNaT{D`Ai)PqM&4iO+xC+5D%MeSh z85dlgiV+q#JFEI*EhR1V`K1jqNOTFoVs+iTC$4BQsg`%`l}TvO8r)`@Lt}@nHA?T0 z!{RE<41b3Kr)&fS6hP)&_8)3Me!n!nf0civLoA|>2#zEsf<}PC_?QV-Z|zO@UbYXA ze>8y><@I`rakF5*@nHxECoiq!k!ID1Q|U=X!}LLhZbB&oh=pQGNRed4cltf&Hq0E{ zI)0%dpgi{HFr?wNW3m*0&EHp%I(J(0bYPEe6M>BEz+ue`%SEr={p7KRa1f2RQ3HA< z-Qb!~Bc9TsqpvQAacO-C*~zDp6HskU;yFpM;#RyCvt=uWl(h%s9M>p}7rw~anee<&(VDL+ zR8=>LETyAG=Z^$dtvct`jN1Uh_nfFG+fV(XN09$o10eu=pZ@QG>F;>{3(g{%*upx#460pHS*Or z-{H8rRXyb=FqRyitok$@gC?$3xQf{4W4OeN8gC9YQ;Q?h588Y+&SR#W$QkuPMd+%|(UTu(DtNLb1K3~8!xQD*wxjk@A z$sQz>j(rwcy8VJH=(Fu%Ak2*be_52UY2A`m5c_v-5>~>t2OOQqHR5C8Jd|{~t<{P3 zVWy*Oj=!&%@XD|p{SuM|`3ETZ-DG^@{-PvH7ZCOfN~o!Ue?dtiT>VvUC(f5PKKr>) z5H$k6H*uCmtkG!6~a!nX3yiqBh1P`O_^Dix}bB?^mCqpk@wUtm*-_ z3a5hXh|(MNgIVsPpUA+L@Gv9Xr-EVxs$s;HeL@ui_(eI~fJ~b-$wvzr zm9_Lu8z@?oG6;1;BZzTQtFkX*#MBkysoskfc&1rmU*9n$47otN%yia!cd%XkN-EaC zTg8i5cFZ2<#y%&to_R8>v0ARIEoH+JG(JMaoXFV*XRkY`3T9++DUhG5y(R7r(m;=a zem04n6P>XBp;Gktw`DUZJ(sS34?BJb@Lyqv%l{ngP}scHPXi3Z@c!8ene`9pFikz@ zT>u4whPvllMy;tcRUS2wj4(SGq}xMI2$qSO={Uvc$Cu|s+g-5by2fORxQ$Khn4|cx z9sOgCL=eq;19E2;Xl0wIQ$|)tXe$;4nTaPkn8Zr2I^O6bX8iW?Y#ZRa%K`jx*DFZVk-E2g*l zb^v1QvQN;pIoM?wP|OTI)Ee}zGK{yOf)5-rK%wSCE5Xey0fdo&(s*fsp^OIfMrR+` zL2&Pe8XOGQw27gNkv>v{1vA8#*lfC026`FVyC{K4qoQcKS(Vr_J4%fb+jOD@j4^WQ zby2DO71b4$Pe;@eD*Rq@$wz8|n^O)I190l(A98lIh<0k{{NbmqWIx0l8LA|k3vls9E!*iBvfC^eN@(0+E-Z zdJOO*=)z{=z}wYpT_+_dE55ZK7<^QHriT)^b?G+9cJ4xJGeSm|xY1DUb=jO-1g(s$ zIM<;$UF&KGb-5hNrPGo z>TR`|XA{@yHSNwoI3(spryEvfk=g$0Yp?;A;RiPKcQR9~y8Fj?0H*&kO#N4d6~A9) z*Ti*uVkX$oUzKNPuzG73>afac5f#X1$|WbhX-v_JxZ?F9sVx9*=Mj;2xir{W=t@}Cgk>-AE)pv3BK^wOT!w})IWh+cj#v{aZbiDsWbZELJ||g{L4iU# zwFZ+5hseMT_~-(H8b}-m_9>jf>!TL%JAQE$$X;;_3^PwP%n)^X3hKJdeDf;;0-BOU zlP-68NE0d6O9lOL1q=$F(aHP+hIol>V&KNSFPxeaN&+Zs8g4iX>@YDXO}DKoS!VPo z&Zn91?lT8@MqqyK+iJ9x_F2;<9rF7@F>)Zg?}a_cUYC1iP6L;syhM+|*H3QcRdyUTRIh#MMQG#4o zxr}%b=zVHzb{QZ7$fYLGW&w})nU))I%N%;{v2rts@aGKKou!x@8hk@QJK4^_)96$wbwtH;?6;afE`Oi@;p?p*wQ>x8fL;njbU&UI+6J(q$4V zn*Ujsq5J=)F2n5epH6ibzntnejRDeSr-lD9)34l-Vg2h&|KF_3h+4La(*cYyK>yjQ zj`a`iGPOVDYS9f!lTvFoQIU$+itMP>A`|QZgHxm`?95e(hL`8nxEV|5eJRS1hu#+< zyu7LSMPAEnKndUAFuc$g!p~V@U6n*c?qY0((h{XBLJOD{=@+U&wD0pm!=z9*!{E$_ zN9ML#l(ndN_GNpekv7@j)P^Cqe=x%AZl7s3>cuP}nOn)Y*8#t5)g;yTGs%o%BW6em zp{fFGHhF!eYypNZL4867yeK@Q>SOLUwBuTctD*iP0qme`EqoIJ&Y2@k*QZG=m@?Yi z-*32{O$0j9&1Bdn$lgb#t1SAK{gV`DKksSd=j^afZ>|{1$D5ZYKo&gponPCb#udy{ zW+EB3)7pxDONx*LG2W0}d1w(b`LOe1X=5ZhRK(Q{zksXv1nfIBR zK+F-X^ESW=d|xgBms%12B?_{~67%gwA|y1B1R*irUMiRRb4}4)lNFb&>U6u*8S&;K zEWyGLRH=gfPsqMG1EV@wvV|kMxlaZdi!a~NMMlmMjlr#Q$*fv?NI#d7(74mDc^HD^ zEtIByCys%f0(gjuLSH;drvSXs2T>7@9v>{&>PR~k=_|)-RnOA^1`1|#q8tVnAO#RR z*sw`<4E8z^;tLSjEaSjQaEyn^NgnLcjKrHxno1!Vs0}C-uQ**_;WH}USA`oYG=bY_ zxf@A8YKlN}ezC5#S+br#PD7wiGZ$f8QCO}@|0F3-68pZF{=sRbl z3{W})+O9Np0#Z@DW=g^ei`)$t@Q0y2PcbKtm2W`v_6GG0*M3c(Y#Fs@R|(7(CT~oO zwdZ8XV>)P3vGGau@JPw2szf2&rcLZtRqS~c!98H|!`$qN=AuDlcCqnJTOU*8%xOfZ zj*j&dQr&{tnFnEegwZL0;%Rfmrlj4}f1C@kH6Tn-H^vo1$rl2Y<_e3s5uxSt^vF(> zl=2^_tF3vYG;4^ztc%Z^FPo_d=#UG{DOhim$5iV^+Ulhfxvkbyupap{;wWomYlH8Q zQcB&$bzE$80yRnqn3DS%fvLhJeEJMkGACoRGP{e|b*@k;_r%e0inTw|oI;jXh?B50 zs`FGv_T`djDs2A1woJX1waxBlGeQkxVlq7FRR|w#(anPC5U;gy?G+7b_iAVs?QAZD z4=h_jthhnQ1pnVsm}c)EZ~r}D`zK{I*L=eN3n@$jrhhAinN{)MrZ5Au<9aCpz~=Se z%)0+jMpNzk(}Vb7$iCfPY#UQE5&YapWTt6dtNvKDjMfV^yU9;rOnw8F@gUn+*-IhT z6n~y%uJRjbomXYm&5h->?)2`;p?6tRt|6SfymXOtV{lWHuUuXfy6UP&25Igdp!&ef zDpN-##rW$Ir)J_0IW;S<9>}O+PZzvw6b18^!?^IqrX`*gpq>Sr1j-97XqA8)h-_lY z!`bE2Rcq{v7K~5WoKH~>Xw<93-J#p{X%bS1VCYWpu-c#C>ws)P<41lm-JU2wuYNpF zbX(h`YB#Ta1vzI>x%z~^DOTaH%#o6N^$1kzW$zszGs!Ij6&tzM|Mgl9xxDi_S`7g) z*|T*vG682^QfjSrrUxz&7YC_-6=fl9h!#Wy_mE=c^~2d}T?p`oF<46gXxz>N@R1YP z6X=$v9p(w}Sqst`veUf$OCKkGZ|#ujDe?kK1zD1y-<}DUm_V%6w|grYkL;Ji^Qipp z*lqSWj(oog@oBgKCx8b{2A1xl2z*RYVdpVrP%gX{bK7&$P}ulIEN>?{Cm7F}BE(VC zxX|~bw3(-T&*(bv(jJ3|=UV>98W%kj{3g7N=?}SI^YaHVLZQaDJ4&)0^|dHN$kKh< zVo+T_9fJ(D-z}hPbuO&RB!Ps$IO!Ar;6fB=*wWUtF=ptp+!%H9ZPxK+dCL7B1~9zR zG~ODq-?e{6(!?`Ac__Ira4|Q1oiUj`Pl+8SJ6g88|C=+!?QHrb4gjTO{$Y0hyJ@+` z|MCMy75&2x*iMxwP&J@H-TEh?ZEqY@{eJ2h4t|FNAzZQD6pzwLz2fK#FWqG{Xhn3-XY!wEjo1yMnr&Y<*izPPxOlMbOonWT z1(1mCZ7{J2vcl{rk^xh5Z&)5AU(3yUh!IOB`2m(Fiumf|v{ugua7+m?feGA97)j`L$ zZQJamW81cEb!^+VZ71EajZX5Wd;f3MJ^P+McYiqb*8Q-uzC4vxwbuNNXJU*oO+pE4 z{I-LO558&WmgU+db&yL68o0qGqAsu2fKmi7l3SH|V?%S8wy%xeX;4RQ4D@)1 zQn5vT#KqE|O&OVf%Y`#lEPt{0-zZhQ03fZY1qqM>XOvfolY{NmMG3_W>u4OjqRSQ~Vs_rK#OV&@_)tAT0&y zJh?E!SmoXQJGx6TEeh&dG#~lF!8|A^ZZKSa#<55*Z0alKK0b%~q|bUd0$=na2EPx% zUibL+$6%vUZ3hDXM5WaArT$cHOa`JJ!mxyPX$!K zh#;Wd9>fSw^tABm$x3}YP_e)rx!Y=f@L_>_WI^P}g5%t$S+SRw%!l(tT-y6O!bO^@`fJq&s&VndHF@|oxf>4=Aa{18L z|8?`cU0?$PTWuyXmwz(2?tzzuYWBs3Roo@5!|8epeA=d9vZ6KhfTsrfO_U7QrbXb03+h&mQe51(9r;Md1y{erj^%h-XxK^%S(?msLW|Kud#NI>@g48(Pu ztVYCr^d;Z_tWstEt#__amHyS2e5It=3KfSSNCzs7s|JMQOqVcno($X2RW=x*9C10= zk{tt!hhLFa-sjU3f7PJwC`xkEFugHj1Q>doDyXd^v#)Fp)lWBwv3Dh#gKtE`_A(V_6%{cZeEMF?Ll4@7z zc73zO-uC0<$->g6SEOBsj}AhVlsIwN1fm=5*PQ3i84&KT)+Folo|@dQ?&e$n*`hwo ze&(~5H4S*d^r3+~ zl;G6drUlSOlvC={(IvP|3u|GAx`?HxC`_CXE{h6ZU3jYQOXQCN7av?e6M!O^)*)yj z2xV%P_rD?aV8#0e`<^n`*5rrZZY`l~jhIXzj-ZoPHV*$s>%wX}t;GyIy{)6?aQJg^gv^B~C<5S58c?l9sOHnG zX+4=wC?W@~Cr|`94kRIC@kk&$9bbS!no0Q`K1X}Zkx;H0NCzBNF)dp0c4FadV#YA! zn6)BjqOU`Q3nt2yR6eueHDyH0ZgT}%jY4`HwBThqokKpnW*~1z*>8n%TuY~yo5V9C z>P$T7opgyjC`&#lzh^uOfD$(2EWZjClkOo`a-?=aeY!sxgYS2CLnvzoPIWsl_q?)(^6fBY830_%vCT+Yq}=OhH@ zgLvnS!bJ~+A0BkTmbLlPD)l32>oAayBKm5hBvlG(LvYwQU#Yzm8=k^$X{{Os)JgRG zH-n9lx$X+dSJQ&#gteDDOoBl_tW5RvU(FJnu~%8!n^M7r$53>}pbr{F^QWcUidyPYz3(Br^dm=C1m zx0YhB=Qo%ENA@JA@RFet;xwAVtCZc`#fav>#g0|PHdw()Z>{a{0tJw0&_{($KM+`W zg9&evB=EV}3L|~$7&kDM-&7V(`g?%a+)0wZk{vWSipcvVOT5^4gF2o~mJjIga$B&A zSbrPUh>XvPKQ3~8&`s8KvHi|Ah|Y7it)C8z8@4LmZ9;bONTDY!t0}U-!uo=5IpF+U81M5LOn8eonkm$p~>Bw?Zt;vMVukseJ z7Iz-|Z=j+csXuu|PozI@&5?eCGh6?`Qz;nOBPzf=!pUXL;xmscB?{$>Y6eXIf)e3p zdl?8?4nPwq6;ENDOBU-?q95@lr3pdq*SH}#7Bgd%BUQJ{Kq3iK;cMwDKo}zcb9Jaz zuql0=O%z{Age)pIAh+&=j5V~ zI&T?nYH?{X^=PXL63L%>3M6w&#@kSmt)Pkm3dle*c~Wb|P>Fl`Ehwc_@FI}{1<m((5N42C#Qr2ObR-|ddm#6)iLdE0%;Gh+KYd&?qQZhE z-b-fgi86E{E$M{fv7G|-Omz?w!$+4kdlx!UJx>)uapHTdj)|3@wh~67!1n@hMk
  • 9dwZukqrBPZt;Y0e=z}ez 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 literal 0 HcmV?d00001 diff --git a/output/demo/operator-control-center-demo.json b/output/demo/operator-control-center-demo.json new file mode 100644 index 0000000..9d89856 --- /dev/null +++ b/output/demo/operator-control-center-demo.json @@ -0,0 +1,134 @@ +{ + "username": "sample-user", + "generated_at": "2026-04-12T12:00:00+00:00", + "report_reference": "", + "watch_state": {}, + "campaign_summary": { + "campaign_type": "security-review", + "label": "Security Review", + "action_count": 1, + "repo_count": 1 + }, + "writeback_preview": { + "sync_mode": "reconcile", + "repos": [ + { + "repo": "RepoC", + "topics": [ + "ghra-call-security-review" + ], + "issue_title": "[Repo Auditor] Security Review", + "notion_action_count": 1 + } + ] + }, + "writeback_results": { + "mode": "apply", + "target": "github", + "results": [ + { + "repo_full_name": "sample-user/RepoC", + "target": "github-issue", + "status": "created", + "url": "https://github.com/sample-user/RepoC/issues/1" + } + ] + }, + "managed_state_drift": [ + { + "repo_full_name": "sample-user/RepoC", + "target": "github-issue", + "drift_state": "managed-issue-edited" + } + ], + "operator_summary": { + "headline": "RepoC still needs security follow-through before the queue will calm down.", + "counts": { + "blocked": 1, + "urgent": 1, + "ready": 1, + "deferred": 1 + }, + "source_run_id": "sample-user:2026-04-12T12:00:00+00:00", + "next_recommended_run_mode": "incremental", + "watch_strategy": "adaptive", + "watch_decision_summary": "The current baseline is still compatible, so incremental watch remains safe for the next run.", + "what_changed": "RepoC drift needs review and RepoB reopened a release checklist item.", + "why_it_matters": "Live drift is still present, so security work should stay ahead of lower-pressure cleanup.", + "what_to_do_next": "Review RepoC first, then close RepoB's reopened checklist item.", + "trend_summary": "Queue pressure is stable but still sticky.", + "follow_through_summary": "One urgent item is still repeating in the recent window.", + "primary_target_reason": "RepoC remains the top target because live drift is still open.", + "closure_guidance": "Clear RepoC's security drift before moving to lower-pressure work.", + "primary_target_trust_policy": "verify-first", + "primary_target_trust_policy_reason": "The recommendation is sound, but recent reopen noise means it should still be reviewed before acting.", + "control_center_reference": "output/demo/operator-control-center-sample-user-2026-04-12.json" + }, + "operator_queue": [ + { + "repo": "RepoC", + "title": "Security drift needs review", + "lane": "blocked", + "lane_label": "Blocked", + "lane_reason": "Governed security drift is still unresolved.", + "kind": "campaign", + "priority": 1, + "summary": "RepoC still needs a governance decision before the security review can settle.", + "recommended_action": "Open the governed control preview and decide whether to apply CodeQL.", + "repo_url": "https://github.com/sample-user/RepoC", + "links": [ + { + "label": "GitHub Issue", + "url": "https://github.com/sample-user/RepoC/issues/1" + } + ] + }, + { + "repo": "RepoB", + "title": "Release checklist reopened", + "lane": "urgent", + "lane_label": "Needs Attention Now", + "lane_reason": "A previously quiet repo reopened a visible checklist item.", + "kind": "review", + "priority": 2, + "summary": "RepoB needs a small release follow-through pass.", + "recommended_action": "Re-run the release checklist and close the missing item.", + "repo_url": "https://github.com/sample-user/RepoB" + }, + { + "repo": "RepoA", + "title": "Protect shipped momentum", + "lane": "ready", + "lane_label": "Ready for Manual Action", + "lane_reason": "RepoA is healthy enough that a small polish task would keep it strong.", + "kind": "maintenance", + "priority": 3, + "summary": "A small polish pass would keep the showcase repo strong.", + "recommended_action": "Tidy the release notes and publish the next small maintenance release.", + "repo_url": "https://github.com/sample-user/RepoA" + }, + { + "repo": "RepoA", + "title": "Archive old brainstorm notes", + "lane": "deferred", + "lane_label": "Safe to Defer", + "lane_reason": "This is cleanup-only work with no current pressure.", + "kind": "cleanup", + "priority": 4, + "summary": "Backlog cleanup is optional this week.", + "recommended_action": "Leave this alone unless priorities change.", + "repo_url": "https://github.com/sample-user/RepoA" + } + ], + "portfolio_outcomes_summary": {}, + "operator_effectiveness_summary": {}, + "high_pressure_queue_history": [], + "operator_setup_health": {}, + "operator_recent_changes": [], + "review_summary": { + "review_id": "sample-review-1", + "status": "open", + "source_run_id": "sample-user:2026-04-12T12:00:00+00:00" + }, + "preflight_summary": {} +} \ No newline at end of file diff --git a/output/demo/operator-control-center-demo.md b/output/demo/operator-control-center-demo.md new file mode 100644 index 0000000..7389638 --- /dev/null +++ b/output/demo/operator-control-center-demo.md @@ -0,0 +1,43 @@ +# Operator Control Center: sample-user + +*Generated:* 2026-04-12 +*Headline:* RepoC still needs security follow-through before the queue will calm down. + +*Source Run:* `sample-user:2026-04-12T12:00:00+00:00` +*Next Recommended Run:* `incremental` +*Watch Strategy:* `adaptive` +*Watch Decision:* The current baseline is still compatible, so incremental watch remains safe for the next run. +*What Changed:* RepoC drift needs review and RepoB reopened a release checklist item. +*Why It Matters:* Live drift is still present, so security work should stay ahead of lower-pressure cleanup. +*What To Do Next:* Review RepoC first, then close RepoB's reopened checklist item. +*Trend:* Queue pressure is stable but still sticky. +*Follow-Through:* One urgent item is still repeating in the recent window. +*Why This Is The Top Target:* RepoC remains the top target because live drift is still open. +*Closure Guidance:* Clear RepoC's security drift before moving to lower-pressure work. +*Trust Policy:* verify-first — The recommendation is sound, but recent reopen noise means it should still be reviewed before acting. +*Control Center Artifact:* `output/demo/operator-control-center-sample-user-2026-04-12.json` +*Setup Health:* unknown | Errors: 0 | Warnings: 0 + +## Blocked + +- RepoC: Security drift needs review — RepoC still needs a governance decision before the security review can settle. + Why this lane: Governed security drift is still unresolved. + Action: Open the governed control preview and decide whether to apply CodeQL. + +## Needs Attention Now + +- RepoB: Release checklist reopened — RepoB needs a small release follow-through pass. + Why this lane: A previously quiet repo reopened a visible checklist item. + Action: Re-run the release checklist and close the missing item. + +## Ready for Manual Action + +- RepoA: Protect shipped momentum — A small polish pass would keep the showcase repo strong. + Why this lane: RepoA is healthy enough that a small polish task would keep it strong. + Action: Tidy the release notes and publish the next small maintenance release. + +## Safe to Defer + +- RepoA: Archive old brainstorm notes — Backlog cleanup is optional this week. + Why this lane: This is cleanup-only work with no current pressure. + Action: Leave this alone unless priorities change. diff --git a/output/demo/pending-proposals.json b/output/demo/pending-proposals.json new file mode 100644 index 0000000..a00df25 --- /dev/null +++ b/output/demo/pending-proposals.json @@ -0,0 +1,4 @@ +{ + "contract_version": "automation_proposals_v1", + "proposals": [] +} \ No newline at end of file diff --git a/output/demo/portfolio-truth-2026-04-05T120000Z.json b/output/demo/portfolio-truth-2026-04-05T120000Z.json new file mode 100644 index 0000000..17f99f4 --- /dev/null +++ b/output/demo/portfolio-truth-2026-04-05T120000Z.json @@ -0,0 +1,245 @@ +{ + "schema_version": "demo-pcc-v1", + "generated_at": "2026-04-05T12:00:00+00:00", + "workspace_root": "fixtures/demo", + "projects": [ + { + "identity": { + "project_key": "RepoA", + "display_name": "RepoA", + "path": "fixtures/demo/RepoA", + "section_marker": "fixture-demo", + "has_git": true, + "top_level_dir": "fixtures", + "group_key": "demo", + "group_label": "Demo Portfolio", + "section_label": "Fixture Demo" + }, + "declared": { + "operating_path": "fixtures/demo/RepoA", + "category": "demo-product", + "tool_provenance": "Codex", + "lifecycle_state": "shipped", + "purpose": "A polished shipped project.", + "criticality": "demo", + "review_cadence": "weekly", + "intended_disposition": "keep", + "maturity_program": "operator-os-fixture", + "target_maturity": "public-demo", + "automation_eligible": false + }, + "derived": { + "context_quality": "full", + "registry_status": "active", + "attention_state": "active-product", + "stack": [ + "Python" + ], + "context_files": [ + "README.md", + "docs/current-state.md" + ], + "context_file_count": 2, + "primary_context_file": "README.md", + "project_summary_present": true, + "current_state_present": true, + "stack_present": true, + "run_instructions_present": true, + "known_risks_present": false, + "next_recommended_move_present": true, + "last_meaningful_activity_at": "2026-04-05T12:00:00+00:00", + "activity_status": "current", + "has_tests": true, + "has_ci": true, + "has_license": true, + "readme_char_count": 2100, + "release_count": 2 + }, + "risk": { + "risk_tier": "baseline", + "risk_factors": [], + "risk_summary": "No elevated fixture risk.", + "security_risk": false, + "doctor_gap": false, + "context_risk": false, + "path_risk": false + }, + "security": { + "alerts_available": true, + "dependabot_critical": 0, + "dependabot_high": 0, + "dependabot_medium": 0, + "dependabot_low": 0, + "secret_scanning_open": 0, + "code_scanning_critical": 0, + "code_scanning_high": 0 + }, + "advisory": { + "legacy_status": "shipped", + "legacy_context_quality": "full", + "legacy_category": "fixture-demo", + "legacy_tool_provenance": "sample" + } + }, + { + "identity": { + "project_key": "RepoB", + "display_name": "RepoB", + "path": "fixtures/demo/RepoB", + "section_marker": "fixture-demo", + "has_git": true, + "top_level_dir": "fixtures", + "group_key": "demo", + "group_label": "Demo Portfolio", + "section_label": "Fixture Demo" + }, + "declared": { + "operating_path": "fixtures/demo/RepoB", + "category": "demo-support", + "tool_provenance": "Claude Code", + "lifecycle_state": "functional", + "purpose": "A functional project with follow-through left to do.", + "criticality": "demo", + "review_cadence": "weekly", + "intended_disposition": "keep", + "maturity_program": "operator-os-fixture", + "target_maturity": "public-demo", + "automation_eligible": false + }, + "derived": { + "context_quality": "minimum-viable", + "registry_status": "recent", + "attention_state": "decision-needed", + "stack": [ + "TypeScript" + ], + "context_files": [ + "README.md", + "docs/current-state.md" + ], + "context_file_count": 2, + "primary_context_file": "README.md", + "project_summary_present": true, + "current_state_present": true, + "stack_present": true, + "run_instructions_present": false, + "known_risks_present": false, + "next_recommended_move_present": true, + "last_meaningful_activity_at": "2026-04-05T12:00:00+00:00", + "activity_status": "current", + "has_tests": true, + "has_ci": false, + "has_license": true, + "readme_char_count": 1800, + "release_count": 0 + }, + "risk": { + "risk_tier": "moderate", + "risk_factors": [ + "open high/critical alerts" + ], + "risk_summary": "Security follow-through needs operator review.", + "security_risk": true, + "doctor_gap": false, + "context_risk": true, + "path_risk": false + }, + "security": { + "alerts_available": true, + "dependabot_critical": 0, + "dependabot_high": 1, + "dependabot_medium": 2, + "dependabot_low": 1, + "secret_scanning_open": 0, + "code_scanning_critical": 0, + "code_scanning_high": 0 + }, + "advisory": { + "legacy_status": "functional", + "legacy_context_quality": "minimum-viable", + "legacy_category": "fixture-demo", + "legacy_tool_provenance": "sample" + } + }, + { + "identity": { + "project_key": "RepoC", + "display_name": "RepoC", + "path": "fixtures/demo/RepoC", + "section_marker": "fixture-demo", + "has_git": true, + "top_level_dir": "fixtures", + "group_key": "demo", + "group_label": "Demo Portfolio", + "section_label": "Fixture Demo" + }, + "declared": { + "operating_path": "fixtures/demo/RepoC", + "category": "demo-support", + "tool_provenance": "Codex", + "lifecycle_state": "wip", + "purpose": "A risky work-in-progress project.", + "criticality": "demo", + "review_cadence": "weekly", + "intended_disposition": "keep", + "maturity_program": "operator-os-fixture", + "target_maturity": "public-demo", + "automation_eligible": true + }, + "derived": { + "context_quality": "minimum-viable", + "registry_status": "parked", + "attention_state": "decision-needed", + "stack": [ + "Python" + ], + "context_files": [ + "README.md", + "docs/current-state.md" + ], + "context_file_count": 2, + "primary_context_file": "README.md", + "project_summary_present": true, + "current_state_present": false, + "stack_present": true, + "run_instructions_present": true, + "known_risks_present": false, + "next_recommended_move_present": true, + "last_meaningful_activity_at": "2026-04-05T12:00:00+00:00", + "activity_status": "current", + "has_tests": false, + "has_ci": false, + "has_license": true, + "readme_char_count": 1500, + "release_count": 0 + }, + "risk": { + "risk_tier": "moderate", + "risk_factors": [ + "open high/critical alerts" + ], + "risk_summary": "Security follow-through needs operator review.", + "security_risk": true, + "doctor_gap": true, + "context_risk": true, + "path_risk": false + }, + "security": { + "alerts_available": true, + "dependabot_critical": 1, + "dependabot_high": 2, + "dependabot_medium": 1, + "dependabot_low": 0, + "secret_scanning_open": 0, + "code_scanning_critical": 0, + "code_scanning_high": 1 + }, + "advisory": { + "legacy_status": "wip", + "legacy_context_quality": "minimum-viable", + "legacy_category": "fixture-demo", + "legacy_tool_provenance": "sample" + } + } + ] +} \ No newline at end of file diff --git a/output/demo/portfolio-truth-2026-04-12T120000Z.json b/output/demo/portfolio-truth-2026-04-12T120000Z.json new file mode 100644 index 0000000..0ea81bf --- /dev/null +++ b/output/demo/portfolio-truth-2026-04-12T120000Z.json @@ -0,0 +1,245 @@ +{ + "schema_version": "demo-pcc-v1", + "generated_at": "2026-04-12T12:00:00+00:00", + "workspace_root": "fixtures/demo", + "projects": [ + { + "identity": { + "project_key": "RepoA", + "display_name": "RepoA", + "path": "fixtures/demo/RepoA", + "section_marker": "fixture-demo", + "has_git": true, + "top_level_dir": "fixtures", + "group_key": "demo", + "group_label": "Demo Portfolio", + "section_label": "Fixture Demo" + }, + "declared": { + "operating_path": "fixtures/demo/RepoA", + "category": "demo-product", + "tool_provenance": "Codex", + "lifecycle_state": "shipped", + "purpose": "A polished shipped project.", + "criticality": "demo", + "review_cadence": "weekly", + "intended_disposition": "keep", + "maturity_program": "operator-os-fixture", + "target_maturity": "public-demo", + "automation_eligible": false + }, + "derived": { + "context_quality": "full", + "registry_status": "active", + "attention_state": "active-product", + "stack": [ + "Python" + ], + "context_files": [ + "README.md", + "docs/current-state.md" + ], + "context_file_count": 2, + "primary_context_file": "README.md", + "project_summary_present": true, + "current_state_present": true, + "stack_present": true, + "run_instructions_present": true, + "known_risks_present": false, + "next_recommended_move_present": true, + "last_meaningful_activity_at": "2026-04-12T12:00:00+00:00", + "activity_status": "current", + "has_tests": true, + "has_ci": true, + "has_license": true, + "readme_char_count": 2100, + "release_count": 2 + }, + "risk": { + "risk_tier": "baseline", + "risk_factors": [], + "risk_summary": "No elevated fixture risk.", + "security_risk": false, + "doctor_gap": false, + "context_risk": false, + "path_risk": false + }, + "security": { + "alerts_available": true, + "dependabot_critical": 0, + "dependabot_high": 0, + "dependabot_medium": 0, + "dependabot_low": 0, + "secret_scanning_open": 0, + "code_scanning_critical": 0, + "code_scanning_high": 0 + }, + "advisory": { + "legacy_status": "shipped", + "legacy_context_quality": "full", + "legacy_category": "fixture-demo", + "legacy_tool_provenance": "sample" + } + }, + { + "identity": { + "project_key": "RepoB", + "display_name": "RepoB", + "path": "fixtures/demo/RepoB", + "section_marker": "fixture-demo", + "has_git": true, + "top_level_dir": "fixtures", + "group_key": "demo", + "group_label": "Demo Portfolio", + "section_label": "Fixture Demo" + }, + "declared": { + "operating_path": "fixtures/demo/RepoB", + "category": "demo-support", + "tool_provenance": "Claude Code", + "lifecycle_state": "functional", + "purpose": "A functional project with follow-through left to do.", + "criticality": "demo", + "review_cadence": "weekly", + "intended_disposition": "keep", + "maturity_program": "operator-os-fixture", + "target_maturity": "public-demo", + "automation_eligible": false + }, + "derived": { + "context_quality": "minimum-viable", + "registry_status": "recent", + "attention_state": "decision-needed", + "stack": [ + "TypeScript" + ], + "context_files": [ + "README.md", + "docs/current-state.md" + ], + "context_file_count": 2, + "primary_context_file": "README.md", + "project_summary_present": true, + "current_state_present": true, + "stack_present": true, + "run_instructions_present": false, + "known_risks_present": true, + "next_recommended_move_present": true, + "last_meaningful_activity_at": "2026-04-12T12:00:00+00:00", + "activity_status": "current", + "has_tests": true, + "has_ci": false, + "has_license": true, + "readme_char_count": 1800, + "release_count": 0 + }, + "risk": { + "risk_tier": "elevated", + "risk_factors": [ + "open high/critical alerts" + ], + "risk_summary": "Security follow-through needs operator review.", + "security_risk": true, + "doctor_gap": false, + "context_risk": true, + "path_risk": false + }, + "security": { + "alerts_available": true, + "dependabot_critical": 0, + "dependabot_high": 1, + "dependabot_medium": 2, + "dependabot_low": 1, + "secret_scanning_open": 0, + "code_scanning_critical": 0, + "code_scanning_high": 0 + }, + "advisory": { + "legacy_status": "functional", + "legacy_context_quality": "minimum-viable", + "legacy_category": "fixture-demo", + "legacy_tool_provenance": "sample" + } + }, + { + "identity": { + "project_key": "RepoC", + "display_name": "RepoC", + "path": "fixtures/demo/RepoC", + "section_marker": "fixture-demo", + "has_git": true, + "top_level_dir": "fixtures", + "group_key": "demo", + "group_label": "Demo Portfolio", + "section_label": "Fixture Demo" + }, + "declared": { + "operating_path": "fixtures/demo/RepoC", + "category": "demo-support", + "tool_provenance": "Codex", + "lifecycle_state": "wip", + "purpose": "A risky work-in-progress project.", + "criticality": "demo", + "review_cadence": "weekly", + "intended_disposition": "keep", + "maturity_program": "operator-os-fixture", + "target_maturity": "public-demo", + "automation_eligible": true + }, + "derived": { + "context_quality": "minimum-viable", + "registry_status": "parked", + "attention_state": "decision-needed", + "stack": [ + "Python" + ], + "context_files": [ + "README.md", + "docs/current-state.md" + ], + "context_file_count": 2, + "primary_context_file": "README.md", + "project_summary_present": true, + "current_state_present": false, + "stack_present": true, + "run_instructions_present": true, + "known_risks_present": true, + "next_recommended_move_present": true, + "last_meaningful_activity_at": "2026-04-12T12:00:00+00:00", + "activity_status": "current", + "has_tests": false, + "has_ci": false, + "has_license": true, + "readme_char_count": 1500, + "release_count": 0 + }, + "risk": { + "risk_tier": "elevated", + "risk_factors": [ + "open high/critical alerts" + ], + "risk_summary": "Security follow-through needs operator review.", + "security_risk": true, + "doctor_gap": true, + "context_risk": true, + "path_risk": false + }, + "security": { + "alerts_available": true, + "dependabot_critical": 1, + "dependabot_high": 2, + "dependabot_medium": 1, + "dependabot_low": 0, + "secret_scanning_open": 0, + "code_scanning_critical": 0, + "code_scanning_high": 1 + }, + "advisory": { + "legacy_status": "wip", + "legacy_context_quality": "minimum-viable", + "legacy_category": "fixture-demo", + "legacy_tool_provenance": "sample" + } + } + ] +} \ No newline at end of file diff --git a/output/demo/portfolio-truth-latest.json b/output/demo/portfolio-truth-latest.json new file mode 100644 index 0000000..0ea81bf --- /dev/null +++ b/output/demo/portfolio-truth-latest.json @@ -0,0 +1,245 @@ +{ + "schema_version": "demo-pcc-v1", + "generated_at": "2026-04-12T12:00:00+00:00", + "workspace_root": "fixtures/demo", + "projects": [ + { + "identity": { + "project_key": "RepoA", + "display_name": "RepoA", + "path": "fixtures/demo/RepoA", + "section_marker": "fixture-demo", + "has_git": true, + "top_level_dir": "fixtures", + "group_key": "demo", + "group_label": "Demo Portfolio", + "section_label": "Fixture Demo" + }, + "declared": { + "operating_path": "fixtures/demo/RepoA", + "category": "demo-product", + "tool_provenance": "Codex", + "lifecycle_state": "shipped", + "purpose": "A polished shipped project.", + "criticality": "demo", + "review_cadence": "weekly", + "intended_disposition": "keep", + "maturity_program": "operator-os-fixture", + "target_maturity": "public-demo", + "automation_eligible": false + }, + "derived": { + "context_quality": "full", + "registry_status": "active", + "attention_state": "active-product", + "stack": [ + "Python" + ], + "context_files": [ + "README.md", + "docs/current-state.md" + ], + "context_file_count": 2, + "primary_context_file": "README.md", + "project_summary_present": true, + "current_state_present": true, + "stack_present": true, + "run_instructions_present": true, + "known_risks_present": false, + "next_recommended_move_present": true, + "last_meaningful_activity_at": "2026-04-12T12:00:00+00:00", + "activity_status": "current", + "has_tests": true, + "has_ci": true, + "has_license": true, + "readme_char_count": 2100, + "release_count": 2 + }, + "risk": { + "risk_tier": "baseline", + "risk_factors": [], + "risk_summary": "No elevated fixture risk.", + "security_risk": false, + "doctor_gap": false, + "context_risk": false, + "path_risk": false + }, + "security": { + "alerts_available": true, + "dependabot_critical": 0, + "dependabot_high": 0, + "dependabot_medium": 0, + "dependabot_low": 0, + "secret_scanning_open": 0, + "code_scanning_critical": 0, + "code_scanning_high": 0 + }, + "advisory": { + "legacy_status": "shipped", + "legacy_context_quality": "full", + "legacy_category": "fixture-demo", + "legacy_tool_provenance": "sample" + } + }, + { + "identity": { + "project_key": "RepoB", + "display_name": "RepoB", + "path": "fixtures/demo/RepoB", + "section_marker": "fixture-demo", + "has_git": true, + "top_level_dir": "fixtures", + "group_key": "demo", + "group_label": "Demo Portfolio", + "section_label": "Fixture Demo" + }, + "declared": { + "operating_path": "fixtures/demo/RepoB", + "category": "demo-support", + "tool_provenance": "Claude Code", + "lifecycle_state": "functional", + "purpose": "A functional project with follow-through left to do.", + "criticality": "demo", + "review_cadence": "weekly", + "intended_disposition": "keep", + "maturity_program": "operator-os-fixture", + "target_maturity": "public-demo", + "automation_eligible": false + }, + "derived": { + "context_quality": "minimum-viable", + "registry_status": "recent", + "attention_state": "decision-needed", + "stack": [ + "TypeScript" + ], + "context_files": [ + "README.md", + "docs/current-state.md" + ], + "context_file_count": 2, + "primary_context_file": "README.md", + "project_summary_present": true, + "current_state_present": true, + "stack_present": true, + "run_instructions_present": false, + "known_risks_present": true, + "next_recommended_move_present": true, + "last_meaningful_activity_at": "2026-04-12T12:00:00+00:00", + "activity_status": "current", + "has_tests": true, + "has_ci": false, + "has_license": true, + "readme_char_count": 1800, + "release_count": 0 + }, + "risk": { + "risk_tier": "elevated", + "risk_factors": [ + "open high/critical alerts" + ], + "risk_summary": "Security follow-through needs operator review.", + "security_risk": true, + "doctor_gap": false, + "context_risk": true, + "path_risk": false + }, + "security": { + "alerts_available": true, + "dependabot_critical": 0, + "dependabot_high": 1, + "dependabot_medium": 2, + "dependabot_low": 1, + "secret_scanning_open": 0, + "code_scanning_critical": 0, + "code_scanning_high": 0 + }, + "advisory": { + "legacy_status": "functional", + "legacy_context_quality": "minimum-viable", + "legacy_category": "fixture-demo", + "legacy_tool_provenance": "sample" + } + }, + { + "identity": { + "project_key": "RepoC", + "display_name": "RepoC", + "path": "fixtures/demo/RepoC", + "section_marker": "fixture-demo", + "has_git": true, + "top_level_dir": "fixtures", + "group_key": "demo", + "group_label": "Demo Portfolio", + "section_label": "Fixture Demo" + }, + "declared": { + "operating_path": "fixtures/demo/RepoC", + "category": "demo-support", + "tool_provenance": "Codex", + "lifecycle_state": "wip", + "purpose": "A risky work-in-progress project.", + "criticality": "demo", + "review_cadence": "weekly", + "intended_disposition": "keep", + "maturity_program": "operator-os-fixture", + "target_maturity": "public-demo", + "automation_eligible": true + }, + "derived": { + "context_quality": "minimum-viable", + "registry_status": "parked", + "attention_state": "decision-needed", + "stack": [ + "Python" + ], + "context_files": [ + "README.md", + "docs/current-state.md" + ], + "context_file_count": 2, + "primary_context_file": "README.md", + "project_summary_present": true, + "current_state_present": false, + "stack_present": true, + "run_instructions_present": true, + "known_risks_present": true, + "next_recommended_move_present": true, + "last_meaningful_activity_at": "2026-04-12T12:00:00+00:00", + "activity_status": "current", + "has_tests": false, + "has_ci": false, + "has_license": true, + "readme_char_count": 1500, + "release_count": 0 + }, + "risk": { + "risk_tier": "elevated", + "risk_factors": [ + "open high/critical alerts" + ], + "risk_summary": "Security follow-through needs operator review.", + "security_risk": true, + "doctor_gap": true, + "context_risk": true, + "path_risk": false + }, + "security": { + "alerts_available": true, + "dependabot_critical": 1, + "dependabot_high": 2, + "dependabot_medium": 1, + "dependabot_low": 0, + "secret_scanning_open": 0, + "code_scanning_critical": 0, + "code_scanning_high": 1 + }, + "advisory": { + "legacy_status": "wip", + "legacy_context_quality": "minimum-viable", + "legacy_category": "fixture-demo", + "legacy_tool_provenance": "sample" + } + } + ] +} \ No newline at end of file diff --git a/output/demo/portfolio-warehouse.db b/output/demo/portfolio-warehouse.db new file mode 100644 index 0000000000000000000000000000000000000000..cd2f075cc29fb8a22a42bb2447bd54a6a1cf1b8f GIT binary patch literal 385024 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 literal 0 HcmV?d00001 diff --git a/output/demo/security-burndown-sample-user-2026-04-12.json b/output/demo/security-burndown-sample-user-2026-04-12.json new file mode 100644 index 0000000..19b598d --- /dev/null +++ b/output/demo/security-burndown-sample-user-2026-04-12.json @@ -0,0 +1,30 @@ +{ + "distinct_advisories": 2, + "total_repo_instances": 3, + "repos_touched": 2, + "entries": [ + { + "package": "demo-runtime", + "ecosystem": "pip", + "severity": "critical", + "ghsa_id": "GHSA-DEMO-0001", + "first_patched_version": "2.0.0", + "affected_repos": [ + "RepoC" + ], + "affected_repo_count": 1 + }, + { + "package": "demo-ui-kit", + "ecosystem": "npm", + "severity": "high", + "ghsa_id": "GHSA-DEMO-0002", + "first_patched_version": "4.1.0", + "affected_repos": [ + "RepoB", + "RepoC" + ], + "affected_repo_count": 2 + } + ] +} \ No newline at end of file diff --git a/output/demo/weekly-command-center-sample-user-2026-04-12.json b/output/demo/weekly-command-center-sample-user-2026-04-12.json new file mode 100644 index 0000000..bbe1696 --- /dev/null +++ b/output/demo/weekly-command-center-sample-user-2026-04-12.json @@ -0,0 +1,69 @@ +{ + "username": "sample-user", + "generated_at": "2026-04-12T12:00:00+00:00", + "headline": "Fixture portfolio has one security-driven next move.", + "decision": "Review RepoC before expanding lower-pressure cleanup.", + "why_this_week": "RepoC carries the only critical fixture alert and demonstrates the operator-approved review lane.", + "next_step": "Open the burndown view, confirm the grouped fix, then record the decision.", + "risk_posture": { + "elevated_count": 2, + "risk_tier_counts": { + "elevated": 2, + "moderate": 0, + "baseline": 1, + "deferred": 0 + }, + "top_elevated": [ + { + "repo": "RepoB", + "risk_tier": "elevated", + "risk_summary": "Security follow-through needs operator review." + }, + { + "repo": "RepoC", + "risk_tier": "elevated", + "risk_summary": "Security follow-through needs operator review." + } + ] + }, + "security_posture": { + "scanned_count": 3, + "repos_with_open_high_critical": 2, + "total_open_critical": 1, + "total_open_high": 3, + "top_alerts": [ + { + "repo": "RepoB", + "risk_tier": "elevated", + "dependabot_critical": 0, + "dependabot_high": 1 + }, + { + "repo": "RepoC", + "risk_tier": "elevated", + "dependabot_critical": 1, + "dependabot_high": 2 + } + ] + }, + "path_attention": [ + { + "repo": "RepoA", + "headline": "Fixture context is intentionally compact.", + "registry_status": "active", + "context_quality": "full" + }, + { + "repo": "RepoB", + "headline": "Fixture context is intentionally compact.", + "registry_status": "recent", + "context_quality": "minimum-viable" + }, + { + "repo": "RepoC", + "headline": "Fixture context is intentionally compact.", + "registry_status": "parked", + "context_quality": "minimum-viable" + } + ] +} \ No newline at end of file diff --git a/scripts/build_demo_artifacts.py b/scripts/build_demo_artifacts.py index e7341a6..444e5f5 100644 --- a/scripts/build_demo_artifacts.py +++ b/scripts/build_demo_artifacts.py @@ -126,6 +126,7 @@ def main() -> None: export_html_dashboard(report_data, OUTPUT_DIR, diff_data=diff_data) export_excel(report_path, OUTPUT_DIR / "demo-workbook.xlsx", diff_data=diff_data, excel_mode="standard") _write_demo_portfolio_truth(report_data) + _write_demo_portfolio_command_center_files(report_data) _write_demo_warehouse(report_data, report_path) control_center_json = OUTPUT_DIR / "operator-control-center-demo.json" @@ -151,34 +152,296 @@ def _parse_generated_at(value: str | None) -> datetime: def _write_demo_portfolio_truth(report_data: dict[str, Any]) -> None: - repos = [] - for audit in report_data.get("audits", []): + payload = _build_pcc_truth_snapshot(report_data, report_data.get("generated_at", "")) + (OUTPUT_DIR / "portfolio-truth-latest.json").write_text(json.dumps(payload, indent=2)) + + +def _risk_tier(audit: dict[str, Any]) -> str: + score = float(audit.get("overall_score", 0)) + posture = (audit.get("security_posture") or {}).get("label", "") + if posture in {"critical", "watch"} or score < 0.50: + return "elevated" + if score < 0.75: + return "moderate" + return "baseline" + + +def _context_quality(audit: dict[str, Any]) -> str: + score = float((audit.get("lenses", {}).get("ship_readiness") or {}).get("score", 0)) + if score >= 0.85: + return "full" + if score >= 0.65: + return "standard" + if score >= 0.40: + return "minimum-viable" + return "boilerplate" + + +def _registry_status(audit: dict[str, Any]) -> str: + tier = audit.get("completeness_tier", "") + if tier == "shipped": + return "active" + if tier == "functional": + return "recent" + if tier == "wip": + return "parked" + return "deferred" + + +def _attention_state(audit: dict[str, Any], risk_tier: str, high_crit: int) -> str: + name = (audit.get("metadata") or {}).get("name", "") + if high_crit or risk_tier == "elevated": + return "decision-needed" + if name == "RepoA": + return "active-product" + return "manual-only" + + +def _security_fields(audit: dict[str, Any]) -> dict[str, Any]: + name = (audit.get("metadata") or {}).get("name", "") + if name == "RepoC": + return { + "alerts_available": True, + "dependabot_critical": 1, + "dependabot_high": 2, + "dependabot_medium": 1, + "dependabot_low": 0, + "secret_scanning_open": 0, + "code_scanning_critical": 0, + "code_scanning_high": 1, + } + if name == "RepoB": + return { + "alerts_available": True, + "dependabot_critical": 0, + "dependabot_high": 1, + "dependabot_medium": 2, + "dependabot_low": 1, + "secret_scanning_open": 0, + "code_scanning_critical": 0, + "code_scanning_high": 0, + } + return { + "alerts_available": True, + "dependabot_critical": 0, + "dependabot_high": 0, + "dependabot_medium": 0, + "dependabot_low": 0, + "secret_scanning_open": 0, + "code_scanning_critical": 0, + "code_scanning_high": 0, + } + + +def _build_pcc_truth_snapshot( + report_data: dict[str, Any], + generated_at: str, + *, + risk_shift: int = 0, +) -> dict[str, Any]: + projects = [] + for index, audit in enumerate(report_data.get("audits", []), start=1): metadata = audit.get("metadata", {}) repo_name = metadata.get("name", "") if not repo_name: continue - risk_score = round((1.0 - float(audit.get("overall_score", 0))) * 100, 1) - ship_readiness = (audit.get("lenses", {}).get("ship_readiness") or {}).get("score", 0) - repos.append( + language = metadata.get("language") or "Unknown" + risk_tier = _risk_tier(audit) + if risk_shift < 0 and risk_tier == "elevated": + risk_tier = "moderate" + security = _security_fields(audit) + high_crit = security["dependabot_critical"] + security["dependabot_high"] + attention_state = _attention_state(audit, risk_tier, high_crit) + projects.append( { - "name": repo_name, - "full_name": metadata.get("full_name", repo_name), - "language": metadata.get("language") or "Unknown", - "tier": audit.get("completeness_tier", ""), - "total_score": round(float(audit.get("overall_score", 0)) * 100, 1), - "risk_score": risk_score, - "completeness_score": round(float(ship_readiness) * 100, 1), - "interest_score": round(float(audit.get("interest_score", 0)) * 100, 1), + "identity": { + "project_key": repo_name, + "display_name": repo_name, + "path": f"fixtures/demo/{repo_name}", + "section_marker": "fixture-demo", + "has_git": True, + "top_level_dir": "fixtures", + "group_key": "demo", + "group_label": "Demo Portfolio", + "section_label": "Fixture Demo", + }, + "declared": { + "operating_path": f"fixtures/demo/{repo_name}", + "category": "demo-product" if index == 1 else "demo-support", + "tool_provenance": "Codex" if index % 2 else "Claude Code", + "lifecycle_state": audit.get("completeness_tier", "unknown"), + "purpose": metadata.get("description") or "Fixture project", + "criticality": "demo", + "review_cadence": "weekly", + "intended_disposition": "keep", + "maturity_program": "operator-os-fixture", + "target_maturity": "public-demo", + "automation_eligible": index == 3, + }, + "derived": { + "context_quality": _context_quality(audit), + "registry_status": _registry_status(audit), + "attention_state": attention_state, + "stack": [language], + "context_files": ["README.md", "docs/current-state.md"], + "context_file_count": 2, + "primary_context_file": "README.md", + "project_summary_present": True, + "current_state_present": index != 3, + "stack_present": True, + "run_instructions_present": index != 2, + "known_risks_present": risk_tier == "elevated", + "next_recommended_move_present": True, + "last_meaningful_activity_at": generated_at, + "activity_status": "current", + "has_tests": index != 3, + "has_ci": index == 1, + "has_license": True, + "readme_char_count": 2400 - index * 300, + "release_count": 2 if index == 1 else 0, + }, + "risk": { + "risk_tier": risk_tier, + "risk_factors": [ + "open high/critical alerts" + ] + if high_crit + else [], + "risk_summary": "Security follow-through needs operator review." + if high_crit + else "No elevated fixture risk.", + "security_risk": high_crit > 0, + "doctor_gap": index == 3, + "context_risk": _context_quality(audit) in {"minimum-viable", "boilerplate"}, + "path_risk": False, + }, + "security": security, + "advisory": { + "legacy_status": audit.get("completeness_tier", ""), + "legacy_context_quality": _context_quality(audit), + "legacy_category": "fixture-demo", + "legacy_tool_provenance": "sample", + }, } ) - payload = { - "schema_version": "demo", - "generated_at": report_data.get("generated_at", ""), + return { + "schema_version": "demo-pcc-v1", + "generated_at": generated_at, "workspace_root": "fixtures/demo", - "repos": repos, + "projects": projects, } - (OUTPUT_DIR / "portfolio-truth-latest.json").write_text(json.dumps(payload, indent=2)) + + +def _write_demo_portfolio_command_center_files(report_data: dict[str, Any]) -> None: + generated_at = report_data.get("generated_at", "2026-04-12T12:00:00+00:00") + projects = _build_pcc_truth_snapshot(report_data, generated_at)["projects"] + elevated = [p for p in projects if p["risk"]["risk_tier"] == "elevated"] + open_alerts = [ + p + for p in projects + if p["security"]["dependabot_critical"] + p["security"]["dependabot_high"] > 0 + ] + total_critical = sum(p["security"]["dependabot_critical"] for p in projects) + total_high = sum(p["security"]["dependabot_high"] for p in projects) + digest = { + "username": report_data.get("username", "sample-user"), + "generated_at": generated_at, + "headline": "Fixture portfolio has one security-driven next move.", + "decision": "Review RepoC before expanding lower-pressure cleanup.", + "why_this_week": "RepoC carries the only critical fixture alert and demonstrates the operator-approved review lane.", + "next_step": "Open the burndown view, confirm the grouped fix, then record the decision.", + "risk_posture": { + "elevated_count": len(elevated), + "risk_tier_counts": { + "elevated": len(elevated), + "moderate": len([p for p in projects if p["risk"]["risk_tier"] == "moderate"]), + "baseline": len([p for p in projects if p["risk"]["risk_tier"] == "baseline"]), + "deferred": len([p for p in projects if p["risk"]["risk_tier"] == "deferred"]), + }, + "top_elevated": [ + { + "repo": p["identity"]["project_key"], + "risk_tier": p["risk"]["risk_tier"], + "risk_summary": p["risk"]["risk_summary"], + } + for p in elevated + ], + }, + "security_posture": { + "scanned_count": len(projects), + "repos_with_open_high_critical": len(open_alerts), + "total_open_critical": total_critical, + "total_open_high": total_high, + "top_alerts": [ + { + "repo": p["identity"]["project_key"], + "risk_tier": p["risk"]["risk_tier"], + "dependabot_critical": p["security"]["dependabot_critical"], + "dependabot_high": p["security"]["dependabot_high"], + } + for p in open_alerts + ], + }, + "path_attention": [ + { + "repo": p["identity"]["project_key"], + "headline": "Fixture context is intentionally compact.", + "registry_status": p["derived"]["registry_status"], + "context_quality": p["derived"]["context_quality"], + } + for p in projects + ], + } + (OUTPUT_DIR / "weekly-command-center-sample-user-2026-04-12.json").write_text( + json.dumps(digest, indent=2) + ) + + burndown = { + "distinct_advisories": 2, + "total_repo_instances": 3, + "repos_touched": 2, + "entries": [ + { + "package": "demo-runtime", + "ecosystem": "pip", + "severity": "critical", + "ghsa_id": "GHSA-DEMO-0001", + "first_patched_version": "2.0.0", + "affected_repos": ["RepoC"], + "affected_repo_count": 1, + }, + { + "package": "demo-ui-kit", + "ecosystem": "npm", + "severity": "high", + "ghsa_id": "GHSA-DEMO-0002", + "first_patched_version": "4.1.0", + "affected_repos": ["RepoB", "RepoC"], + "affected_repo_count": 2, + }, + ], + } + (OUTPUT_DIR / "security-burndown-sample-user-2026-04-12.json").write_text( + json.dumps(burndown, indent=2) + ) + + (OUTPUT_DIR / "pending-proposals.json").write_text( + json.dumps({"contract_version": "automation_proposals_v1", "proposals": []}, indent=2) + ) + + previous = _build_pcc_truth_snapshot( + report_data, + "2026-04-05T12:00:00+00:00", + risk_shift=-1, + ) + current = _build_pcc_truth_snapshot(report_data, generated_at) + (OUTPUT_DIR / "portfolio-truth-2026-04-05T120000Z.json").write_text( + json.dumps(previous, indent=2) + ) + (OUTPUT_DIR / "portfolio-truth-2026-04-12T120000Z.json").write_text( + json.dumps(current, indent=2) + ) def _write_demo_warehouse(report_data: dict[str, Any], report_path) -> None: