Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
20 commits
Select commit Hold shift + click to select a range
4ef940c
feat(ui): friendly column headers on leadership tables via shared lab…
CJud25 Jul 23, 2026
854bbb3
fix(home): legible hero KPIs - short labels, gap in words, no sign le…
CJud25 Jul 23, 2026
765fe3e
fix(ratio-forecast): formula id to caption, relabel internal planning…
CJud25 Jul 23, 2026
793ee3d
fix(forecast): reconcile 'ready hires' measures with distinct labels …
CJud25 Jul 23, 2026
7d08022
fix(resource-network): add zero-result empty-state before chart/table
CJud25 Jul 23, 2026
fa4ef65
fix(outreach): mark generated draft fields read-only
CJud25 Jul 23, 2026
1d7da47
fix(sidebar): surface Planning controls above the nav fold
CJud25 Jul 23, 2026
7eba782
feat(triage): shade the overdue queue and flag the weakest funnel step
CJud25 Jul 23, 2026
caf4370
docs(ui): honest wording for the unreachable-target guard + disclose …
CJud25 Jul 23, 2026
7568525
docs(governance): add glossary and expand ODLH/DLR/QDLH on first use
CJud25 Jul 23, 2026
c19a86a
docs(outreach): state the queue is a read-only planning view (ADR-009…
CJud25 Jul 23, 2026
6411404
feat(site-readiness): data-driven, site-specific manager action plan
CJud25 Jul 23, 2026
46ef6ec
fix(security): html.escape the site-name heading interpolation
CJud25 Jul 23, 2026
0489a9d
chore(config): disable Streamlit usage telemetry (offline posture)
CJud25 Jul 23, 2026
b10f3ab
fix(source-perf): label the log-scale x-axis
CJud25 Jul 23, 2026
84c625c
chore(ci): add permissive ruff gate and remove seven dead-code items
CJud25 Jul 23, 2026
4f99033
refactor(validation): derive drift-prone counts from constants + drif…
CJud25 Jul 23, 2026
f5921df
chore(ci): advisory pip-audit + boot the built container and probe he…
CJud25 Jul 23, 2026
6d2faea
chore(scripts): align run_demo.ps1 to runtime dependencies
CJud25 Jul 23, 2026
1f831fc
chore(ci): pin pip-audit version in the advisory scan step
CJud25 Jul 23, 2026
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
26 changes: 26 additions & 0 deletions .github/workflows/ci.yml
Original file line number Diff line number Diff line change
Expand Up @@ -27,11 +27,37 @@ jobs:
- name: Install development dependencies
run: python -m pip install --disable-pip-version-check -r requirements-dev.txt

- name: Lint (ruff)
run: python -m ruff check .

- name: Run tests
run: python -m pytest -q

- name: Validate deterministic synthetic data
run: python scripts/validate_demo_data.py

- name: Dependency vulnerability scan (advisory)
continue-on-error: true
run: |
python -m pip install pip-audit==2.10.1
python -m pip_audit --strict --requirement requirements.txt

- name: Build demo container
run: docker build --tag rocc-demo:ci .

- name: Boot demo container and probe health
run: |
docker run -d --name rocc-ci -p 8501:8501 rocc-demo:ci
ok=0
for i in $(seq 1 30); do
if curl -fsS http://localhost:8501/_stcore/health >/dev/null 2>&1; then
ok=1; break
fi
sleep 2
done
docker logs rocc-ci || true
docker rm -f rocc-ci || true
if [ "$ok" -ne 1 ]; then
echo "container did not become healthy within 60s"; exit 1
fi
echo "container healthy"
3 changes: 3 additions & 0 deletions .streamlit/config.toml
Original file line number Diff line number Diff line change
Expand Up @@ -7,3 +7,6 @@ font = "sans serif"

[server]
headless = true

[browser]
gatherUsageStats = false
6 changes: 5 additions & 1 deletion README.md
Original file line number Diff line number Diff line change
Expand Up @@ -35,7 +35,11 @@ planning simulation, reports, and the privacy & governance statement.
- Referral-source quality and cold-source tracking against real cadences.
- Mass-push planning when new contracts approach (via a future GovCon Recompete
Radar handoff).
- Contract DLR trends and ODLH 75%-floor monitoring.
- Contract direct-labor-ratio (DLR) trends and direct-labor-hours (ODLH) 75%-floor monitoring.

> Acronyms: QDLH = Qualifying Direct Labor Hours, DLH = Direct Labor Hours,
ratio = QDLH / DLH (the AbilityOne 75% requirement). A full glossary is on the
Privacy & Governance page.

## Quickstart

Expand Down
10 changes: 5 additions & 5 deletions app.py
Original file line number Diff line number Diff line change
Expand Up @@ -61,6 +61,11 @@ def main() -> None:
with st.sidebar:
st.markdown("# ROCC — Recruiting & Outreach Control Center")
st.caption("part of TENS HQ")
st.markdown("**Planning controls**")
scenario = st.selectbox("Scenario", ["Base", "Conservative", "Optimistic"])
target_pct = st.slider("Planning target", 70.0, 82.0, DEFAULT_TARGET * 100.0, 0.5)
st.caption("Site indicators are planning proxies. They are not official ODLH determinations.")
st.markdown("---")
visible_pages = [page for page in PAGE_RENDERERS if page in allowed_pages()]
_restore_and_clamp_navigation(visible_pages)
page = st.radio(
Expand All @@ -74,11 +79,6 @@ def main() -> None:
unsafe_allow_html=True,
)
st.markdown("---")
st.markdown("**Planning controls**")
scenario = st.selectbox("Scenario", ["Base", "Conservative", "Optimistic"])
target_pct = st.slider("Planning target", 70.0, 82.0, DEFAULT_TARGET * 100.0, 0.5)
st.caption("Site indicators are planning proxies. They are not official ODLH determinations.")
st.markdown("---")
st.caption(f"Demo v{APP_VERSION} · Seed {DEFAULT_SEED}")

st.query_params["nav"] = page
Expand Down
7 changes: 7 additions & 0 deletions pyproject.toml
Original file line number Diff line number Diff line change
Expand Up @@ -18,3 +18,10 @@ dev = ["pytest==8.4.1"]
pythonpath = ["src"]
testpaths = ["tests"]
addopts = "-q"

[tool.ruff]
target-version = "py311"
src = ["src"]

[tool.ruff.lint]
select = ["F", "E9"]
1 change: 1 addition & 0 deletions requirements-dev.txt
Original file line number Diff line number Diff line change
@@ -1,2 +1,3 @@
-r requirements.txt
pytest==8.4.1
ruff==0.15.22
2 changes: 1 addition & 1 deletion run_demo.ps1
Original file line number Diff line number Diff line change
Expand Up @@ -20,7 +20,7 @@ if (-not (Test-Path -LiteralPath $VenvPython)) {
$BasePython = $PythonCommand.Source
}
& $BasePython -m venv $VenvRoot
& $VenvPython -m pip install --disable-pip-version-check -r (Join-Path $ProjectRoot 'requirements-dev.txt')
& $VenvPython -m pip install --disable-pip-version-check -r (Join-Path $ProjectRoot 'requirements.txt')
}

& $VenvPython -m streamlit run (Join-Path $ProjectRoot 'app.py')
53 changes: 53 additions & 0 deletions src/tens_hq/constants.py
Original file line number Diff line number Diff line change
Expand Up @@ -214,3 +214,56 @@
"psychological_evaluation",
"disability_narrative",
}

COLUMN_LABELS = {
# identity / org
"organization_name": "Organization",
"organization_type": "Type",
"relationship_status": "Relationship",
"confidence_level": "Confidence",
# geography
"county_name": "County",
"state_code": "State",
"site_name": "Site",
# dates / contacts
"next_follow_up_date": "Next follow-up",
"activity_date": "Activity date",
"outreach_type": "Outreach type",
"outcome_code": "Outcome",
"contact_name": "Contact",
"contact_title": "Title",
"contact_email": "Email",
"preferred_channel": "Preferred channel",
# coverage / capability
"coverage_strength": "Coverage strength",
"verified_status": "Verified",
"job_family": "Job family",
"capability_level": "Capability level",
"evidence_source": "Evidence source",
# scores / risk
"partner_priority_score": "Partner priority",
"reliability_score": "Reliability",
"risk_status": "Risk",
"days_overdue": "Days overdue",
"suggested_next_action": "Suggested next action",
# source-performance rates
"referral_volume": "Referrals",
"hire_yield": "Hire yield %",
"eligibility_clearance_yield": "Clearance yield %",
"documentation_completion": "Docs complete %",
"retention_90": "90-day retention %",
# forecast columns
"current_ratio": "Current indicator",
"projected_ratio": "Projected indicator",
"direction": "Change",
"expected_attrition_fte": "Expected attrition (FTE)",
"pipeline_candidates": "Pipeline candidates",
"expected_ready_hires": "Projected pipeline arrivals", # S4 reconciliation
"qualified_hiring_need": "Ready hires still needed", # S4 reconciliation
"pipeline_coverage": "Coverage (arrivals / need)", # S4 reconciliation
"open_roles_count": "Open roles",
# privacy inventory
"dataset": "Dataset",
"rows": "Rows",
"synthetic_flag_complete": "All rows synthetic",
}
1 change: 0 additions & 1 deletion src/tens_hq/metrics.py
Original file line number Diff line number Diff line change
Expand Up @@ -174,7 +174,6 @@ def forecast_sites(
if scenario not in _SCENARIO_SETTINGS:
raise ValueError(f"Unknown scenario: {scenario}")
settings = _SCENARIO_SETTINGS[scenario]
as_of = pd.Timestamp(DATA_AS_OF_DATE)
weeks = horizon_days / 7.0
months = horizon_days / 30.4375

Expand Down
Loading
Loading