一键导入
fsharp-build-orchestration
Drive FAKE targets from the compiled front-end; golden-diff parity with DiffPlex; property/unit tests with Expecto + FsCheck.
用 Codex 或 Claude 帮你安装 复制这段 Prompt,粘贴到 Codex、Claude 或其他助手里,让它检查 Skill 页面并帮你完成安装。
菜单
Drive FAKE targets from the compiled front-end; golden-diff parity with DiffPlex; property/unit tests with Expecto + FsCheck.
用 Codex 或 Claude 帮你安装 复制这段 Prompt,粘贴到 Codex、Claude 或其他助手里,让它检查 Skill 页面并帮你完成安装。
基于 SOC 职业分类
Consumer-facing guide to hosting an interactive FS.Skia.UI app — the keyboard/pointer input surface, the preview-vs-tree render distinction, and the windowed-fullscreen blur caveat.
Build Skia-rendered FS.Skia.UI Controls, rich text, chart controls, graph controls, DataGrid, custom wrappers, and generated product examples.
Generated product guidance for Skia-rendered FS.Skia.UI Controls, rich text, chart controls, graph controls, DataGrid, and custom wrappers.
Wire a generated FS.Skia.UI product to the desktop viewer host.
Understand and work with the internal keyed VDOM diff over the lowered Control<'msg> IR (feature 067) — its key-first-then-positional matching, the NodePatch/ChildOp operation set, the totality/determinism/identity-at-rest/round-trip invariants, and the module's disposition (internal, property-tested, wired onto the live render path via RetainedRender in feature 091 and current through feature 103 — layout/bounds cache, injected-delta animation clock, visual-state cross-fade). Use when reading the diff invariants, extending the property tests, or working on the wired retained render path.
Maintainer-facing guide to the FS.Skia.UI.Controls.Elmish interactive-host seam — how runInteractiveApp drives the retained render structure each frame (RetainedRender.step over the keyed diff), advances per-identity animation clocks from an injected Tick delta, stamps runtime visual state pre-reconcile, routes keys focus-first through routeFocusedKey, and resolves pointer hits to a stable identity via retainedHitTest. Use when reading or extending the live controls host loop, the per-frame retained-state/clock/visual-state wiring, or the key/pointer routing seam.
| name | fsharp-build-orchestration |
| description | Drive FAKE targets from the compiled front-end; golden-diff parity with DiffPlex; property/unit tests with Expecto + FsCheck. |
| compatibility | F# governance library (build/Governance) + build/Build.fsproj under net10.0; build-tooling scope only. |
| metadata | {"author":"fs-skia-ui","source":"docs/reports/2026-05-31-1714-foundations-fsharp-capabilities-and-libraries.md"} |
Cookbook for the compiled build front-end, the parity gates, and the test harness. Owns C18
(build orchestration / CLI), C19 (golden-output text diffing), and C20 (property/unit
testing). Verdicts come from the capability report (metadata.source) §8.
build/Build.fsproj exe (no FSX runner,
no FCS).tests/Governance.Tests.Fake.Core.Target 6.1.4 (present). The D2 spike proved it drives
targets from the compiled exe with no FSX runner and no FSharp.Compiler.* transitive
(FR-008). Dispatch via Target.runOrDefaultWithArguments; delegate each target body to a library
function. Argu (typed CLI) and Spectre.Console (tables/colour) are optional — adopt only
if the Route CLI grows.Expecto.FsCheck adds the ergonomic
testProperty; until referenced, call FsCheck's Check directly inside an Expecto test.Fake.Core.Target)Target.create name body registers a target; ==> (from Fake.Core.TargetOperators) declares a
dependency edge. Bodies delegate to library functions so a mistyped target/predicate fails to compile.
open Fake.Core
open Fake.Core.TargetOperators
/// C18 — register two targets and the edge Build -> Test. Dispatch (elsewhere)
/// via Target.runOrDefaultWithArguments "Test".
let defineTargets () =
Target.create "Build" (fun _ -> ())
Target.create "Test" (fun _ -> ())
"Build" ==> "Test" |> ignore
Every ported parser/algorithm/renderer must produce byte-identical output to the Stage-0 golden fixtures before the Python/Bash is deleted (Invariant 6). Return both the verdict and readable drift for the failure report.
open DiffPlex
open DiffPlex.DiffBuilder
open DiffPlex.DiffBuilder.Model
/// C19 — true when ported output equals the committed golden, with readable drift.
let goldenParity (golden: string) (ported: string) =
let model = InlineDiffBuilder(Differ()).BuildDiffModel(golden, ported)
let drift =
model.Lines
|> Seq.filter (fun line -> line.Type <> ChangeType.Unchanged)
|> Seq.map (fun line -> sprintf "%A | %s" line.Type line.Text)
|> Seq.toList
List.isEmpty drift, drift
open Expecto
let parserTests =
testList "parser parity" [
test "task id is extracted from a well-formed line" {
let line = "- [X] T024 [skillist: []] do the thing"
let id = line.Split(' ') |> Array.tryItem 2
Expect.equal id (Some "T024") "the id token is the third field"
}
]
Without Expecto.FsCheck referenced, call FsCheck's Check.QuickThrowOnFailure inside a normal
Expecto test — it throws on a counterexample (failing the test), exactly the gate behaviour. With
Expecto.FsCheck, prefer testProperty "name" prop.
open Expecto
open FsCheck
let propertyTests =
testList "graph properties" [
test "reverse is an involution" {
Check.QuickThrowOnFailure(fun (xs: int list) -> List.rev (List.rev xs) = xs)
}
]
.fake state); use the
deterministic serialized order from CLAUDE.md/AGENTS.md.Expecto.FsCheck is a separate package — testProperty needs it; otherwise call Check
directly (as above).build/** or tests/Governance.Tests,
never shipped in a generated product; versions go in Directory.Packages.props (Central Package
Management). No FCS.Stage 5 (compiled build front-end + routing), Stage 4/5 (golden-parity exit gates), all stages
(Expecto + FsCheck regression/property tests). See the plan in metadata.source.
When a problem outlasts reasonable in-repo attempts, extensive external research is
mandatory — consult official online docs first (the F#/.NET docs and the driven
library's own documentation/API reference), then community sources (forums, Reddit, Q&A
sites, issue trackers and changelogs). Record the findings and resolving links in the
feature's specs/<feature>/feedback/ folder and, for durable lessons, in this skill's
Sources line. Offline, the mandate degrades to recording "research blocked — "
rather than hard-failing the phase.
docs/reports/2026-05-31-1714-foundations-fsharp-capabilities-and-libraries.md §8.[[fsharp-parsing]], [[fsharp-graph-algorithms]] (the ported logic under test), [[fsharp-code-generation]] (DiffPlex also backs the currency check), [[fsharp-io-globbing]], [[fsharp-shell-process]] (the residual processes the front-end drives).