Skip to content

Commit 5cf0302

Browse files
committed
Another deep audit and production-hardening pass is complete. 102 tests, smoke, operator smoke, and production audit all pass.
Project fingerprint — governance & monorepo project_fingerprint.py now detects industry-standard repo signals: Signal Source governance_files SECURITY.md, CODE_OF_CONDUCT.md, .editorconfig, CHANGELOG.md, docs/adr/ workspace_packages pnpm-workspace.yaml, npm workspaces in package.json These flow through steering context, digest, and live steering lines (Governance, Packages, CI, Origin). Bootstrap fill — no manual dead-ends _fallback_replacement() no longer returns manual — review bootstrap_fill_plan.tasks. The chain is: purpose_hint → operators_hint → runtime_center_hint → stack_summary → steering_brief → entry_points/makefile_targets → git_remote → archetype-specific guidance Every unmapped phrase gets an evidence-backed replacement and source tag. Operator hints — always project-aware build_agent_operator_hints() now attaches: project_steering_brief — for all workspaces with a README/manifest verification_commands — e.g. make verify project_steering_digest — when bootstrap is incomplete Agents see per-project identity on every roadmap tool response, not only during bootstrap fill. Doctor & health — full evidence wiring doctor.run_checks() uses gather_evidence() + build_project_fingerprint() for fill plans (not a stripped steering dict). project_steering_digest is always built when ROADMAP.md exists. Formatted output in doctor and /dietcode doctor now includes Verify: lines from the digest. Gate & JoyZoning Schema gate default fix → roadmap(action='validate') + explain-gate (no generic “Edit ROADMAP.md”) JoyZoning merge adds CI and Origin hints from roadmap_brief Production audit expansion Verifies: SECURITY.md governance detection Operator hints include project_steering_brief + verification_commands No manual-only bootstrap phrase sources End-to-end flow fingerprint (governance, packages, verify, compose, cursor rules, …) → evidence → bootstrap_fill_plan → project_steering_digest → session / cockpit / kernel cockpit / operator hints / doctor / joyzoning → apply_bootstrap_fill → validate → recommended_next_action Per-project steering is now wired through fingerprint → digest → every agent-facing surface, with evidence-backed autofill and no manual-only placeholder paths.
1 parent 9ac2661 commit 5cf0302

11 files changed

Lines changed: 174 additions & 11 deletions

File tree

health.py

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -528,6 +528,9 @@ def format_status_report(
528528
if roadmap.get("steering_brief"):
529529
lines.append(f" Project: {roadmap['steering_brief']}")
530530
digest = roadmap.get("project_steering_digest") or {}
531+
verify_cmds = digest.get("verification_commands") or []
532+
if verify_cmds:
533+
lines.append(f" Verify: {verify_cmds[0]}")
531534
remaining = digest.get("bootstrap_remaining")
532535
if remaining and int(remaining) > 0:
533536
lines.append(

lib/agent/joyzoning/workflow.py

Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -50,6 +50,18 @@ def _merge_steering_next_actions(
5050
if id_hint not in base and id_hint not in hints:
5151
hints.append(id_hint)
5252

53+
ci = roadmap_brief.get("ci_systems") or []
54+
if ci:
55+
ci_hint = f"CI: {ci[0]}"
56+
if ci_hint not in base and ci_hint not in hints:
57+
hints.append(ci_hint)
58+
59+
git_remote = roadmap_brief.get("git_remote")
60+
if git_remote:
61+
origin_hint = f"Origin: {git_remote}"
62+
if origin_hint not in base and origin_hint not in hints:
63+
hints.append(origin_hint)
64+
5365
stack = roadmap_brief.get("stack_summary")
5466
if stack:
5567
stack_hint = f"Stack: {stack}"

lib/agent/roadmap/agent_steering.py

Lines changed: 16 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -48,6 +48,22 @@ def _project_context_lines(steering: dict[str, Any]) -> list[str]:
4848
if compose:
4949
lines.append(f"Compose: {', '.join(compose[:4])}")
5050

51+
packages = steering.get("workspace_packages") or []
52+
if packages:
53+
lines.append(f"Packages: {', '.join(packages[:4])}")
54+
55+
governance = steering.get("governance_files") or []
56+
if governance:
57+
lines.append(f"Governance: {', '.join(governance[:3])}")
58+
59+
ci = steering.get("ci_systems") or []
60+
if ci:
61+
lines.append(f"CI: {', '.join(ci[:2])}")
62+
63+
git_remote = steering.get("git_remote")
64+
if git_remote:
65+
lines.append(f"Origin: {git_remote}")
66+
5167
docs_roots = steering.get("docs_roots") or []
5268
if docs_roots:
5369
lines.append(f"Docs: {', '.join(docs_roots[:3])}")

lib/agent/roadmap/bootstrap_fill.py

Lines changed: 13 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -214,7 +214,17 @@ def _fallback_replacement(phrase: str, *, fingerprint: dict[str, Any]) -> tuple[
214214
return f"Document project-specific detail for {brief} ({stack}).", "project_fingerprint.stack_summary"
215215
if brief:
216216
return f"Document project-specific detail for {brief}.", "project_fingerprint.steering_brief"
217-
return phrase, "manual — review bootstrap_fill_plan.tasks"
217+
entry = fingerprint.get("entry_points") or fingerprint.get("makefile_targets") or []
218+
if entry:
219+
return f"Align with project workflows via `{entry[0]}` and documented center of gravity.", "project_fingerprint.entry_points"
220+
git_remote = fingerprint.get("git_remote")
221+
if git_remote:
222+
return f"Document project-specific detail for repository {git_remote}.", "project_fingerprint.git_remote"
223+
archetype = fingerprint.get("project_archetype") or "project"
224+
return (
225+
f"Replace template guidance with {archetype}-specific steering from README and repo evidence.",
226+
"project_fingerprint.project_archetype",
227+
)
218228

219229

220230
def _architecture_hint(
@@ -510,6 +520,8 @@ def build_project_steering_digest(
510520
"license": fingerprint.get("license"),
511521
"runtime_versions": fingerprint.get("runtime_versions"),
512522
"compose_services": fingerprint.get("compose_services"),
523+
"governance_files": fingerprint.get("governance_files") or [],
524+
"workspace_packages": fingerprint.get("workspace_packages") or [],
513525
"has_codeowners": fingerprint.get("has_codeowners"),
514526
"dependency_automation": fingerprint.get("dependency_automation"),
515527
"has_backstage_catalog": fingerprint.get("has_backstage_catalog"),

lib/agent/roadmap/doctor.py

Lines changed: 15 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -174,18 +174,25 @@ def _check(name: str, ok: bool, detail: str = "") -> None:
174174
)
175175

176176
fill_plan = None
177-
if bootstrap_inc and roadmap_path.is_file():
177+
steering_digest = None
178+
if roadmap_path.is_file():
178179
try:
179180
from plugins.dietcode.lib.agent.roadmap.bootstrap_fill import (
180181
build_bootstrap_fill_plan,
181182
build_project_steering_digest,
182183
)
184+
from plugins.dietcode.lib.agent.roadmap.evidence import gather_evidence
185+
from plugins.dietcode.lib.agent.roadmap.project_fingerprint import build_project_fingerprint
183186

184187
text = roadmap_path.read_text(encoding="utf-8", errors="replace")
185-
evidence = {"project_fingerprint": dict(steering), "git": (snap.evidence or {}).get("git") or {}}
186-
fill_plan = build_bootstrap_fill_plan(roadmap_text=text, evidence=evidence)
188+
evidence = gather_evidence(root, tier="light", roadmap_text=text)
189+
fp = evidence.get("project_fingerprint") or build_project_fingerprint(root)
190+
if bootstrap_inc:
191+
fill_plan = build_bootstrap_fill_plan(roadmap_text=text, evidence=evidence)
192+
steering_digest = build_project_steering_digest(fp, fill_plan=fill_plan)
187193
except OSError:
188194
fill_plan = None
195+
steering_digest = None
189196

190197
if bootstrap_inc:
191198
count = gate_state.get("bootstrap_placeholder_count") or steering.get("bootstrap_placeholder_count")
@@ -207,11 +214,7 @@ def _check(name: str, ok: bool, detail: str = "") -> None:
207214
"project_archetype": steering.get("project_archetype"),
208215
"stack_summary": steering.get("stack_summary"),
209216
"bootstrap_fill_plan": fill_plan,
210-
"project_steering_digest": (
211-
build_project_steering_digest(dict(steering), fill_plan=fill_plan)
212-
if fill_plan
213-
else None
214-
),
217+
"project_steering_digest": steering_digest,
215218
"enabled": cfg.enabled,
216219
"checks": checks,
217220
"validation": validation.to_dict() if validation else None,
@@ -235,6 +238,10 @@ def format_doctor_report(*, workspace: Optional[str] = None) -> str:
235238
lines.append(f"Project: {data['steering_brief']}")
236239
if data.get("stack_summary"):
237240
lines.append(f"Stack: {data['stack_summary']}")
241+
digest = data.get("project_steering_digest") or {}
242+
verify_cmds = digest.get("verification_commands") or []
243+
if verify_cmds:
244+
lines.append(f"Verify: {', '.join(verify_cmds[:3])}")
238245
lines.append(f"Enabled: {data.get('enabled')}")
239246
lines.append("")
240247

lib/agent/roadmap/gate.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -201,7 +201,7 @@ def _check_bootstrap_complete(_: dict[str, Any], inputs: dict[str, Any]) -> bool
201201
"label": "ROADMAP.md schema valid",
202202
"is_open": _check_schema_valid,
203203
"why_closed": "Schema validation failed — checkpoint pass incomplete",
204-
"fix": "Edit ROADMAP.md, then roadmap(action='validate')",
204+
"fix": "roadmap(action='validate') — use /roadmap explain-gate for schema fixes",
205205
"safe": True,
206206
"blocks_kanban_complete": False,
207207
},

lib/agent/roadmap/operator.py

Lines changed: 20 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -299,7 +299,15 @@ def build_agent_operator_hints(
299299
from plugins.dietcode.lib.agent.roadmap.steering_context import build_steering_context
300300

301301
steering = build_steering_context(workspace=workspace)
302+
if steering.get("steering_brief"):
303+
hints["project_steering_brief"] = steering["steering_brief"]
304+
verify_cmds = steering.get("verification_commands") or []
305+
if verify_cmds:
306+
hints["verification_commands"] = verify_cmds
302307
attached = attach_bootstrap_steering_fields(steering, tier="light")
308+
digest = attached.get("project_steering_digest") or {}
309+
if digest:
310+
hints["project_steering_digest"] = digest
303311
plan = attached.get("bootstrap_fill_plan") or {}
304312
hint = format_bootstrap_fill_hint(plan)
305313
if hint:
@@ -308,4 +316,16 @@ def build_agent_operator_hints(
308316
hints["recovery_suggestion"] = hint
309317
except Exception:
310318
pass
319+
elif workspace and str(workspace).strip():
320+
try:
321+
from plugins.dietcode.lib.agent.roadmap.steering_context import build_steering_context
322+
323+
steering = build_steering_context(workspace=workspace)
324+
if steering.get("steering_brief"):
325+
hints["project_steering_brief"] = steering["steering_brief"]
326+
verify_cmds = steering.get("verification_commands") or []
327+
if verify_cmds:
328+
hints["verification_commands"] = verify_cmds
329+
except Exception:
330+
pass
311331
return hints

lib/agent/roadmap/project_fingerprint.py

Lines changed: 46 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -100,7 +100,9 @@ def _fingerprint_cache_token(root: Path) -> float:
100100
"renovate.json",
101101
".github/dependabot.yml",
102102
"docker-compose.yml",
103-
"compose.yml",
103+
"pnpm-workspace.yaml",
104+
"turbo.json",
105+
"SECURITY.md",
104106
):
105107
path = root / rel
106108
if path.is_file():
@@ -458,6 +460,45 @@ def _compose_services(root: Path) -> list[str]:
458460
return []
459461

460462

463+
def _governance_files(root: Path) -> list[str]:
464+
found: list[str] = []
465+
for rel in ("SECURITY.md", "CODE_OF_CONDUCT.md", ".editorconfig", "CHANGELOG.md"):
466+
if (root / rel).is_file() and rel not in found:
467+
found.append(rel)
468+
if (root / "docs" / "adr").is_dir():
469+
found.append("docs/adr")
470+
return found[:6]
471+
472+
473+
def _workspace_packages(root: Path) -> list[str]:
474+
packages: list[str] = []
475+
pnpm_ws = root / "pnpm-workspace.yaml"
476+
if pnpm_ws.is_file():
477+
for line in _read_text(pnpm_ws, limit=2000).splitlines():
478+
match = re.match(r'^\s*-\s*["\']?([^"\']+)["\']?', line)
479+
if match:
480+
name = match.group(1).strip()
481+
if name and name not in packages:
482+
packages.append(name[:60])
483+
data = _package_json(root)
484+
workspaces = data.get("workspaces")
485+
if isinstance(workspaces, list):
486+
for item in workspaces:
487+
if len(packages) >= 8:
488+
break
489+
name = str(item).strip()
490+
if name and name not in packages:
491+
packages.append(name[:60])
492+
elif isinstance(workspaces, dict):
493+
for item in workspaces.get("packages") or []:
494+
if len(packages) >= 8:
495+
break
496+
name = str(item).strip()
497+
if name and name not in packages:
498+
packages.append(name[:60])
499+
return packages[:8]
500+
501+
461502
def _catalog_metadata(root: Path) -> dict[str, Optional[str]]:
462503
catalog = root / "catalog-info.yaml"
463504
if not catalog.is_file():
@@ -594,6 +635,8 @@ def _build_project_fingerprint(root: Path) -> dict[str, Any]:
594635
runtime_versions = _runtime_versions(root)
595636
dependency_automation = _dependency_automation(root)
596637
compose_services = _compose_services(root)
638+
governance_files = _governance_files(root)
639+
workspace_packages = _workspace_packages(root)
597640
has_codeowners = (root / ".github" / "CODEOWNERS").is_file() or (root / "CODEOWNERS").is_file()
598641
verification_commands = _verification_commands(
599642
root,
@@ -674,6 +717,8 @@ def _build_project_fingerprint(root: Path) -> dict[str, Any]:
674717
"dependency_automation": dependency_automation or None,
675718
"has_codeowners": has_codeowners,
676719
"compose_services": compose_services or None,
720+
"governance_files": governance_files or None,
721+
"workspace_packages": workspace_packages or None,
677722
"has_backstage_catalog": has_backstage,
678723
"catalog_name": catalog_meta.get("catalog_name"),
679724
"catalog_description": catalog_meta.get("catalog_description"),

lib/agent/roadmap/steering_context.py

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -171,6 +171,8 @@ def build_steering_context(*, workspace: Optional[str] = None) -> dict[str, Any]
171171
"has_codeowners",
172172
"dependency_automation",
173173
"compose_services",
174+
"governance_files",
175+
"workspace_packages",
174176
"has_backstage_catalog",
175177
"catalog_name",
176178
"catalog_description",

scripts/roadmap_audit.py

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -218,6 +218,10 @@ def main() -> int:
218218
failures.append("fingerprint should detect Makefile targets")
219219
if "make verify" not in (fp.get("verification_commands") or []):
220220
failures.append("fingerprint missing make verify from Makefile targets")
221+
(root / "SECURITY.md").write_text("# Security\n", encoding="utf-8")
222+
fp_sec = build_project_fingerprint(root)
223+
if "SECURITY.md" not in (fp_sec.get("governance_files") or []):
224+
failures.append("fingerprint should detect SECURITY.md governance file")
221225
if fp.get("project_archetype") not in {"project", "library", "application", "web-app", "cli-tool", "hermes-plugin", "monorepo"}:
222226
failures.append(f"unexpected project_archetype: {fp.get('project_archetype')}")
223227
roadmap_text = (root / "ROADMAP.md").read_text(encoding="utf-8")
@@ -301,6 +305,12 @@ def main() -> int:
301305
if str(task.get("evidence_source") or "").startswith("manual"):
302306
failures.append(f"bootstrap phrase manual-only: {phrase[:60]}")
303307

308+
hints = build_agent_operator_hints(workspace=str(root))
309+
if not hints.get("project_steering_brief"):
310+
failures.append("operator hints missing project_steering_brief")
311+
if "make verify" not in (hints.get("verification_commands") or []):
312+
failures.append("operator hints missing verification_commands")
313+
304314
import json as _json
305315
from plugins.dietcode.lib.agent.roadmap.native_bridge import merge_roadmap_hint_into_result, roadmap_write_hint
306316

0 commit comments

Comments
 (0)