Logo FS-Skia-UI

Governance System Agent Analysis

Executive Verdict

The governance system is heavy, but its weight is mostly in the right place: it is an agent-facing contract, not a human-facing product workflow. Its job is to give an autonomous agent deterministic commands, typed invariants, readiness artifacts, and failure ownership. On that premise, the core design is sound.

A rewrite is not warranted. The project already completed the highest-value rewrite: the old script/Python/Bash governance path was moved into compiled F# under FS.Skia.UI.Build, with a dedicated build front-end, typed targets, compiled routing, in-process evidence graph and audit, generated validation.contract.yml, and generated .claude skill mirrors. Starting over would mostly recreate those decisions and risk losing the hard-won parity and tests.

What is warranted is a focused second pass:

  1. Keep codifying mechanical rules in F#.
  2. Keep Markdown for agent judgement, examples, and durable evidence.
  3. Remove or regenerate stale active guidance that still names retired paths.
  4. Add better machine outputs for agents, especially Route --json.
  5. Make routing coverage explicit for build/Governance/** and other current governance homes, instead of depending on default-deny fallback behavior.

The most important conclusion: "put it in F#" should mean "make the invariant typed, testable, and self-enforcing." It should not mean "hide prose inside F# string literals and render the same long Markdown later."

Premise: The User Is The Agent

This governance should not be judged like a human developer onboarding guide. For a human, the system is too large. For a Spec Kit agent, the useful question is different:

The system answers many of those questions well. The burden is carried by the agent and the build, not by the end user of a generated FS.Skia.UI app. That does not make all complexity acceptable, but it changes the standard: the system can be heavy if the heaviness buys determinism, observability, and safe failure.

Current Architecture

1. Compiled Build Front-End

The root build no longer depends on a repository build.fsx. fake.sh runs the compiled build/Build.fsproj executable. build/Program.fs registers every FAKE target from the typed Targets.dispatchTargets list and delegates target bodies to Engine.Interpret.runTarget.

That is a strong boundary:

Relevant sources:

2. Route As The Agent Entry Point

Route is the best architectural feature in the governance system. It reads the union of branch-vs-main merge-base diff and current working tree changes, runs the pure Routing.selectForFeature selector, and prints the tier plus the minimal gate list.

The important design choices are correct:

Relevant sources:

3. Evidence Graph And Audit

The evidence system has been moved into compiled F#. It parses tasks.md, tasks.deps.yml, the skill registry, skill-loading evidence, readiness files, audit-status regions, audit patterns, and the unified git diff. It computes the task graph, validates metadata, detects cycles, performs topological sort, propagates synthetic evidence, and renders JSON/Markdown/audit artifacts.

This is exactly the kind of logic that belongs in F# rather than Markdown: the rules are mechanical, central, and review-blocking.

Relevant sources:

4. Single-Source Generation And Currency

The project has moved away from hand-synced duplicates:

This is stronger than merely comparing two files. A drift check says "we have two sources of truth and hope they agree." Generation says "there is one source of truth and the other artifact is a view."

Relevant sources:

5. Skill Governance

The governance system treats skills as first-class inputs to agent work:

This is heavy, but it targets a real failure mode: agents often skip specialized local guidance unless the task itself forces discovery and loading.

Relevant sources:

6. Generated Product And Template Contract

The generated project path is governed as a consumer contract, not a convenient sample. Template checks, generated product checks, capability catalog validation, selected skills, package references, local packages, API surface bundles, and evidence commands are all validated.

The versioned generated-product structural contract is particularly important: it gives the system a deprecation model instead of turning every template change into a hard break.

Relevant sources:

Strengths

Determinism Around Nondeterministic Agents

The governance system's core thesis is right. An agent can be creative in implementation, but completion is checked by deterministic F# gates. This reduces the chance that a final response claims readiness without proof.

The strongest examples are Route, EvidenceGraph, EvidenceAudit, TargetMetadataDrift, SkillSyncCheck, and SkillQualityCheck.

Minimal Gate Selection Is A Major Quality Improvement

The old failure mode was "run everything because missing proof is worse than over-validation." Route changes that. A routine internal change can run Dev only, while contract changes still escalate. That makes the system heavy only when the changed surface justifies it.

For an agent, this is more useful than a shorter manual README. It gives the agent an authoritative action.

Typed Targets And Compiled Routing Remove A Whole Class Of Drift

The target union and RoutingRule.RequiredGates: Targets.Target list make incorrect gate names hard to represent. This is a decisive improvement over stringly typed YAML or Markdown rules.

The Evidence Engine Is In The Right Language

Task parsing, dependency validation, cycle detection, topological sorting, synthetic propagation, audit-status scanning, diff scanning, and report rendering are all better as compiled F# than as prose or ad hoc scripts.

The graph tests include typed unit tests and property checks over the real logic. That is a major strength because synthetic propagation is exactly the kind of rule an agent might misunderstand if it lived only in text.

Single-Source Generation Is The Right Drift Strategy

The generated .claude tree and generated validation contract are good examples of a mature approach. Agents still receive Markdown where Markdown is the right medium, but maintainers edit one canonical source.

Readiness Artifacts Create Reviewable Memory

Per-feature readiness/ files let a reviewer inspect what happened without depending on chat history. This is especially important with agents because the final answer is a lossy summary.

Failure Ownership Is Explicit

Targets and contract rules carry failure-owner concepts such as product, template, governance, missing evidence, unsupported host, and stale prerequisite. That helps agents avoid wasting time on the wrong layer.

Skills Are Treated As Operational Inputs

The skill governance system is opinionated, but it solves a real agent problem: the agent must load the right specialized instructions before it edits code. Structured skillist metadata plus evidence validation makes that enforceable.

The Current System Is Already A Successful Partial Rewrite

The measured current shape is not the pre-refactor state:

Live measurement during this report:

git ls-files 'build.fsx' '.specify/**/*.py' '**/run-audit.sh' \
  '**/compute-task-graph.py' '**/audit-status-scan.py'
# no tracked files

git ls-files 'build/Governance/*.fs' 'build/Governance/*.fsi' \
  'build/Governance/**/*.fs' 'build/Governance/**/*.fsi' \
  'build/*.fs' 'src/SkillSupport/*.fs' 'src/SkillSupport/*.fsi' \
  | sort -u | xargs wc -l | tail -1
# 13896 total

git ls-files 'tests/Governance.Tests/*.fs' 'tests/SkillSupport.Tests/*.fs' \
  | xargs wc -l | tail -1
# 8005 total

Those numbers show the governance system is substantial, but substantially codified.

Weaknesses And Risks

The Agent-Facing Prose Is Still Large

The current .agents/skills/**/*.md plus .specify/**/*.md corpus measures about 7,038 lines. The .agents plus generated .claude skill trees together measure about 8,494 lines. That is no longer the old "rules only in prose" problem, but it is still a lot of text for agents to rank, reconcile, and load.

This matters even if the burden is agent-borne:

Some Active Guidance Still Names Retired Paths

Repository search still finds active, non-historical guidance mentioning the old root build.fsx, deleted Python scripts, and deleted run-audit.sh. Some of this is harmless in historical reports and golden fixtures. Some is not harmless because it lives in active skills or templates an agent may load.

Examples found during this analysis include:

This is a high-priority cleanup because it is active agent guidance, not merely archive text. The current F# implementation can be correct while the agent is still told to think in retired terms.

Routing Has A Current-Path Coverage Gap

validation.contract.yml and Routing.fs still name the old build.fsx and scripts/build/** build-target contract paths. The new governance code lives under build/Governance/** and build/Program.fs.

Those paths are not silently accepted because Route default-denies unmatched non-src/** paths to broad Verify, which is safe. But relying on default-deny for the primary governance implementation is not as good as naming the rule explicitly. It hides intent from both the agent and the generated contract.

Recommendation: add explicit build/Governance/**, build/Program.fs, build/Build.fsproj, and possibly build/** routing coverage under a governance/build-target contract rule.

Route Output Is Human-Readable, Not Fully Machine-Readable

Route prints stable lines such as tier=... and gates=.... That is fine for a chat agent, but the governance system is clearly moving toward machine contracts. A JSON mode would be better:

{
  "developer_class": "framework-author",
  "tier": "focused-authority",
  "gates": ["Dev", "EvidenceGraph"],
  "matched_rules": ["docs-only"],
  "expected_artifacts": ["readiness/validation-contract.md"],
  "dogfood_forced": false
}

This would let future tools run exactly the printed gates without string splitting, and it would make final responses cite structured facts.

--enforce Checks Artifact Presence, Not Full Freshness

The Route --enforce core checks whether expected artifact paths exist. That is useful, but existence is weaker than freshness:

Some freshness is covered by specific gates such as TargetMetadataDrift and SkillSyncCheck, but route-level enforce semantics should be documented as "presence gate, not proof of current execution."

The Current Feature Directory Is A Global State Coupling

Many gates write into the active feature resolved by .specify/feature.json. That is convenient for Spec Kit, but it couples validation of a docs-only report or a small internal change to the active feature's task graph and readiness state. For an agent, this is usually acceptable because a Spec Kit run has an active feature. For ad hoc analysis, it can be surprising.

Possible improvement: let Route or focused gates accept an explicit --feature <id> override for validation-only runs, while keeping the current default.

Some Validators Remain Heuristic Text Scanners

Not everything can or should be parsed as a formal language, but several checks still rely on substrings, headings, or simplified line grammars:

These are pragmatic choices, but they can create false positives or false negatives. The key is to keep them narrow and backed by tests.

The Governance Library Has A Large Public-Looking Surface

FS.Skia.UI.Build is packable and consumed by generated products. That is useful, but it raises the bar for separating stable consumer APIs from internal repository machinery. AgentValidation.fsi, evidence APIs, generated product contract APIs, and build-front-end modules should be reviewed as if accidental public expansion matters.

The new FS.Skia.UI.SkillSupport library is a good pattern because it exposes small, family-specific APIs through .fsi files. The build governance library should keep moving in that direction: small signatures, fewer broad modules.

Target Count And Concept Count Are Still High

The system has many named gates. That is not inherently wrong for an agent, but it increases the chance that a failure is classified by the wrong target or that two targets overlap awkwardly. Route mitigates this, but the next phase should look for target consolidation only where two gates own the same evidence class.

Avoid consolidation for its own sake. It is useful only if it makes ownership clearer or removes duplicated work.

Alternatives

Alternative A: Keep The Current System And Only Patch Stale Guidance

This is the lowest-risk option.

Pros:

Cons:

Verdict: reasonable short-term path.

Alternative B: Full Rewrite Of Governance

Rewrite the governance system from scratch as a new tool, new schemas, new targets, and new Spec Kit integration.

Pros:

Cons:

Verdict: not warranted. The keystone rewrite already happened. Continue incrementally.

Alternative C: All-In F# Governance DSL

Represent most governance facts as F# records and discriminated unions, then generate Markdown, YAML, reports, and skill skeletons from that model.

Pros:

Cons:

Verdict: good for identifiers, rule metadata, target lists, generated skeletons, and provenance. Bad as a wholesale replacement for agent-readable prose.

Alternative D: Data-Driven YAML/JSON Schemas

Move rules from Markdown into structured YAML or JSON, validate schemas, and let the build interpret the data.

Pros:

Cons:

Verdict: keep for agent-authored instance data such as tasks.deps.yml. Do not use for framework-owned routing and target policy that can be compiled.

Alternative E: CI-Only Governance

Move most governance to GitHub Actions or another CI pipeline and keep local agent guidance minimal.

Pros:

Cons:

Verdict: CI should consume the same gates, not replace local governance.

Alternative F: Vanilla Spec Kit With Minimal Custom Rules

Drop most custom governance and rely on upstream Spec Kit conventions.

Pros:

Cons:

Verdict: not a good fit. The repo has already accepted a custom Spec Kit fork stance for governance-critical behavior.

Alternative G: Agent Prompt Only, No Gates

Use concise instructions and trust the model.

Pros:

Cons:

Verdict: reject.

F# Versus Markdown

What Should Be In F#

Put a governance element in F# when it is:

The current system already follows this direction for the most important rules. The remaining good candidates are:

What Should Stay In Markdown

Keep a governance element in Markdown when it is:

The reason is practical: agents consume natural language well. The problem with Markdown is not that it exists. The problem is when Markdown carries a machine-checkable invariant that should instead fail in F#.

What Should Be Hybrid

Several artifacts should remain Markdown views generated or checked by F#:

Rewrite Assessment

Is A Rewrite Warranted?

No. A ground-up rewrite would be a net negative today.

The major architectural correction already landed:

That is the rewrite one would have recommended before the foundations work. The remaining issues are cleanup, hardening, and information architecture, not a need to start over.

What Kind Of Refactor Is Warranted?

A focused hardening refactor is warranted:

  1. Active guidance cleanup: remove stale active references to root build.fsx, deleted Python scripts, and deleted run-audit.sh.
  2. Routing coverage update: explicitly route current governance homes such as build/Governance/** and build/Program.fs.
  3. Machine output: add Route --json and possibly write readiness/route-selection.json.
  4. Freshness semantics: document --enforce as artifact-presence only, or extend it with gate timestamp/hash provenance.
  5. Public API discipline: review FS.Skia.UI.Build packable signatures and split stable consumer APIs from repo-internal front-end modules where needed.
  6. Guidance minimization: shrink active skill prose after stale references are gone, but keep useful agent examples and sources.

Final Recommendation

Keep the governance system. It is heavy, but it is heavy for a reason: it is the agent's deterministic operating contract. The important rule is not "make it small"; the important rule is "make the agent read only judgement guidance, and make everything mechanical enforce itself."

Do not rewrite. Continue the current trajectory:

The governance system is now closer to the right architecture than to the old problem it replaced. The next work should make it clearer, less stale, and more machine-readable, not throw it away.

Type something to start searching.