[{"data":1,"prerenderedAt":-1},["ShallowReactive",2],{"skill:01M72SDAJSXYV698P0VP90JAND":3,"skill-same:01M72SDAJSXYV698P0VP90JAND":48},{"skillNo":4,"name":5,"nameZh":6,"description":7,"descriptionZh":6,"repositoryFullName":8,"ownerLogin":9,"ownerAvatarUrl":10,"ownerAccountNo":11,"ownerDisplayName":6,"repositoryNo":12,"starsCount":13,"licenseSpdxId":14,"licenseFileUrl":6,"sourceHtmlUrl":15,"categories":16,"keywords":17,"publishedAt":18,"linkOnly":19,"markdownContent":20,"markdownBody":21,"frontMatter":22,"refName":27,"commitSha":28,"skillDirectory":29,"forksCount":30,"repositoryHtmlUrl":31,"repositoryHomepageUrl":6,"ownerHtmlUrl":32,"ownerBlogUrl":6,"ownerDescription":6,"updatedAt":33,"install":34,"resources":47},"01M72SDAJSXYV698P0VP90JAND","fsharp-build-orchestration",null,"Drive FAKE targets from the compiled front-end; golden-diff parity with DiffPlex; property\u002Funit tests with Expecto + FsCheck.","EHotwagner\u002FFS-Skia-UI","EHotwagner","https:\u002F\u002Favatars.githubusercontent.com\u002Fu\u002F1645484?v=4","01M72S7CTBDPQDQHQJKKHY87K9","01M72S7CVFD0JN82RVX21NFEVC",2,"MIT","https:\u002F\u002Fgithub.com\u002FEHotwagner\u002FFS-Skia-UI\u002Fblob\u002Fmain\u002F.claude\u002Fskills\u002Ffsharp-build-orchestration\u002FSKILL.md",[],[],"2026-11-10 22:39:42",false,"---\nname: fsharp-build-orchestration\ndescription: Drive FAKE targets from the compiled front-end; golden-diff parity with DiffPlex; property\u002Funit tests with Expecto + FsCheck.\ncompatibility: F# governance library (build\u002FGovernance) + build\u002FBuild.fsproj under net10.0; build-tooling scope only.\nmetadata:\n  author: fs-skia-ui\n  source: docs\u002Freports\u002F2026-05-31-1714-foundations-fsharp-capabilities-and-libraries.md\n---\n\n# fsharp-build-orchestration\n\nCookbook for the compiled build front-end, the parity gates, and the test harness. Owns **C18**\n(build orchestration \u002F CLI), **C19** (golden-output text diffing), and **C20** (property\u002Funit\ntesting). Verdicts come from the capability report (`metadata.source`) §8.\n\n## When to use\n\n- Registering and dispatching FAKE targets from the compiled `build\u002FBuild.fsproj` exe (no FSX runner,\n  no FCS).\n- The Stage-4\u002F5 golden-parity gate: prove ported output is byte-identical to the Stage-0 fixtures.\n- Unit- and property-testing the ported parsers\u002Falgorithms in `tests\u002FGovernance.Tests`.\n\n## Library verdicts\n\n- **Orchestration \u002F CLI (C18) → `Fake.Core.Target` 6.1.4** (present). The D2 spike proved it drives\n  targets from the compiled exe with **no FSX runner** and **no `FSharp.Compiler.*`** transitive\n  (FR-008). Dispatch via `Target.runOrDefaultWithArguments`; delegate each target body to a library\n  function. **Argu** (typed CLI) and **Spectre.Console** (tables\u002Fcolour) are **optional** — adopt only\n  if the `Route` CLI grows.\n- **Golden diff (C19) → DiffPlex 1.9.0.** Readable unified\u002Fside-by-side diffs for the parity gate and\n  the Stage-2 generation-currency check. **Adopt DiffPlex.**\n- **Testing (C20) → Expecto 10.2.2** (in-tree) **+ FsCheck 3.3.3.** Re-point moved-logic tests at the\n  real library functions (assert typed errors, not strings). `Expecto.FsCheck` adds the ergonomic\n  `testProperty`; until referenced, call FsCheck's `Check` directly inside an Expecto `test`.\n\n## API walkthrough + runnable examples\n\n### C18 — targets and dependency edges (`Fake.Core.Target`)\n\n`Target.create name body` registers a target; `==>` (from `Fake.Core.TargetOperators`) declares a\ndependency edge. Bodies delegate to library functions so a mistyped target\u002Fpredicate fails to **compile**.\n\n```fsharp\nopen Fake.Core\nopen Fake.Core.TargetOperators\n\n\u002F\u002F\u002F C18 — register two targets and the edge Build -> Test. Dispatch (elsewhere)\n\u002F\u002F\u002F via Target.runOrDefaultWithArguments \"Test\".\nlet defineTargets () =\n    Target.create \"Build\" (fun _ -> ())\n    Target.create \"Test\" (fun _ -> ())\n    \"Build\" ==> \"Test\" |> ignore\n```\n\n### C19 — golden-output parity gate (DiffPlex)\n\nEvery ported parser\u002Falgorithm\u002Frenderer must produce **byte-identical** output to the Stage-0 golden\nfixtures before the Python\u002FBash is deleted (Invariant 6). Return both the verdict and readable drift\nfor the failure report.\n\n```fsharp\nopen DiffPlex\nopen DiffPlex.DiffBuilder\nopen DiffPlex.DiffBuilder.Model\n\n\u002F\u002F\u002F C19 — true when ported output equals the committed golden, with readable drift.\nlet goldenParity (golden: string) (ported: string) =\n    let model = InlineDiffBuilder(Differ()).BuildDiffModel(golden, ported)\n\n    let drift =\n        model.Lines\n        |> Seq.filter (fun line -> line.Type \u003C> ChangeType.Unchanged)\n        |> Seq.map (fun line -> sprintf \"%A | %s\" line.Type line.Text)\n        |> Seq.toList\n\n    List.isEmpty drift, drift\n```\n\n### C20 — unit tests (Expecto)\n\n```fsharp\nopen Expecto\n\nlet parserTests =\n    testList \"parser parity\" [\n        test \"task id is extracted from a well-formed line\" {\n            let line = \"- [X] T024 [skillist: []] do the thing\"\n            let id = line.Split(' ') |> Array.tryItem 2\n            Expect.equal id (Some \"T024\") \"the id token is the third field\"\n        }\n    ]\n```\n\n### C20 — property tests (FsCheck inside Expecto)\n\nWithout `Expecto.FsCheck` referenced, call FsCheck's `Check.QuickThrowOnFailure` inside a normal\nExpecto `test` — it throws on a counterexample (failing the test), exactly the gate behaviour. With\n`Expecto.FsCheck`, prefer `testProperty \"name\" prop`.\n\n```fsharp\nopen Expecto\nopen FsCheck\n\nlet propertyTests =\n    testList \"graph properties\" [\n        test \"reverse is an involution\" {\n            Check.QuickThrowOnFailure(fun (xs: int list) -> List.rev (List.rev xs) = xs)\n        }\n    ]\n```\n\n## Cautions\n\n- **FAKE concurrency:** never run FAKE-backed targets concurrently (shared `.fake` state); use the\n  deterministic serialized order from `CLAUDE.md`\u002F`AGENTS.md`.\n- **`Expecto.FsCheck` is a separate package** — `testProperty` needs it; otherwise call `Check`\n  directly (as above).\n- **Build-tooling scope.** All packages are referenced by `build\u002F**` or `tests\u002FGovernance.Tests`,\n  **never shipped** in a generated product; versions go in `Directory.Packages.props` (Central Package\n  Management). No FCS.\n- Record warm\u002Fcold build wall-clock vs the Stage-0 baseline; the compiled library should beat the\n  207 KB script recompilation.\n\n## Consuming stages\n\nStage 5 (compiled build front-end + routing), Stage 4\u002F5 (golden-parity exit gates), all stages\n(Expecto + FsCheck regression\u002Fproperty tests). See the plan in `metadata.source`.\n\n## Persistent problems\n\nWhen a problem outlasts reasonable in-repo attempts, extensive external research is\n**mandatory** — consult **official online docs first** (the F#\u002F.NET docs and the driven\nlibrary's own documentation\u002FAPI reference), then community sources (forums, Reddit, Q&A\nsites, issue trackers and changelogs). Record the findings and resolving links in the\nfeature's `specs\u002F\u003Cfeature>\u002Ffeedback\u002F` folder and, for durable lessons, in this skill's\n**Sources** line. Offline, the mandate degrades to recording \"research blocked — \u003Cwhy>\"\nrather than hard-failing the phase.\n\n## Sources \u002F links\n\n- Fake.Core.Target: \u003Chttps:\u002F\u002Ffake.build\u002Freference\u002Ffake-core-target.html>\n- DiffPlex: \u003Chttps:\u002F\u002Fgithub.com\u002Fmmanela\u002Fdiffplex>\n- Expecto: \u003Chttps:\u002F\u002Fgithub.com\u002Fhaf\u002Fexpecto> · FsCheck 3: \u003Chttps:\u002F\u002Ffscheck.github.io\u002FFsCheck\u002F>\n- Capability report: `docs\u002Freports\u002F2026-05-31-1714-foundations-fsharp-capabilities-and-libraries.md` §8.\n\n## Related\n\n[[fsharp-parsing]], [[fsharp-graph-algorithms]] (the ported logic under test),\n[[fsharp-code-generation]] (DiffPlex also backs the currency check), [[fsharp-io-globbing]],\n[[fsharp-shell-process]] (the residual processes the front-end drives).\n","# fsharp-build-orchestration\n\nCookbook for the compiled build front-end, the parity gates, and the test harness. Owns **C18**\n(build orchestration \u002F CLI), **C19** (golden-output text diffing), and **C20** (property\u002Funit\ntesting). Verdicts come from the capability report (`metadata.source`) §8.\n\n## When to use\n\n- Registering and dispatching FAKE targets from the compiled `build\u002FBuild.fsproj` exe (no FSX runner,\n  no FCS).\n- The Stage-4\u002F5 golden-parity gate: prove ported output is byte-identical to the Stage-0 fixtures.\n- Unit- and property-testing the ported parsers\u002Falgorithms in `tests\u002FGovernance.Tests`.\n\n## Library verdicts\n\n- **Orchestration \u002F CLI (C18) → `Fake.Core.Target` 6.1.4** (present). The D2 spike proved it drives\n  targets from the compiled exe with **no FSX runner** and **no `FSharp.Compiler.*`** transitive\n  (FR-008). Dispatch via `Target.runOrDefaultWithArguments`; delegate each target body to a library\n  function. **Argu** (typed CLI) and **Spectre.Console** (tables\u002Fcolour) are **optional** — adopt only\n  if the `Route` CLI grows.\n- **Golden diff (C19) → DiffPlex 1.9.0.** Readable unified\u002Fside-by-side diffs for the parity gate and\n  the Stage-2 generation-currency check. **Adopt DiffPlex.**\n- **Testing (C20) → Expecto 10.2.2** (in-tree) **+ FsCheck 3.3.3.** Re-point moved-logic tests at the\n  real library functions (assert typed errors, not strings). `Expecto.FsCheck` adds the ergonomic\n  `testProperty`; until referenced, call FsCheck's `Check` directly inside an Expecto `test`.\n\n## API walkthrough + runnable examples\n\n### C18 — targets and dependency edges (`Fake.Core.Target`)\n\n`Target.create name body` registers a target; `==>` (from `Fake.Core.TargetOperators`) declares a\ndependency edge. Bodies delegate to library functions so a mistyped target\u002Fpredicate fails to **compile**.\n\n```fsharp\nopen Fake.Core\nopen Fake.Core.TargetOperators\n\n\u002F\u002F\u002F C18 — register two targets and the edge Build -> Test. Dispatch (elsewhere)\n\u002F\u002F\u002F via Target.runOrDefaultWithArguments \"Test\".\nlet defineTargets () =\n    Target.create \"Build\" (fun _ -> ())\n    Target.create \"Test\" (fun _ -> ())\n    \"Build\" ==> \"Test\" |> ignore\n```\n\n### C19 — golden-output parity gate (DiffPlex)\n\nEvery ported parser\u002Falgorithm\u002Frenderer must produce **byte-identical** output to the Stage-0 golden\nfixtures before the Python\u002FBash is deleted (Invariant 6). Return both the verdict and readable drift\nfor the failure report.\n\n```fsharp\nopen DiffPlex\nopen DiffPlex.DiffBuilder\nopen DiffPlex.DiffBuilder.Model\n\n\u002F\u002F\u002F C19 — true when ported output equals the committed golden, with readable drift.\nlet goldenParity (golden: string) (ported: string) =\n    let model = InlineDiffBuilder(Differ()).BuildDiffModel(golden, ported)\n\n    let drift =\n        model.Lines\n        |> Seq.filter (fun line -> line.Type \u003C> ChangeType.Unchanged)\n        |> Seq.map (fun line -> sprintf \"%A | %s\" line.Type line.Text)\n        |> Seq.toList\n\n    List.isEmpty drift, drift\n```\n\n### C20 — unit tests (Expecto)\n\n```fsharp\nopen Expecto\n\nlet parserTests =\n    testList \"parser parity\" [\n        test \"task id is extracted from a well-formed line\" {\n            let line = \"- [X] T024 [skillist: []] do the thing\"\n            let id = line.Split(' ') |> Array.tryItem 2\n            Expect.equal id (Some \"T024\") \"the id token is the third field\"\n        }\n    ]\n```\n\n### C20 — property tests (FsCheck inside Expecto)\n\nWithout `Expecto.FsCheck` referenced, call FsCheck's `Check.QuickThrowOnFailure` inside a normal\nExpecto `test` — it throws on a counterexample (failing the test), exactly the gate behaviour. With\n`Expecto.FsCheck`, prefer `testProperty \"name\" prop`.\n\n```fsharp\nopen Expecto\nopen FsCheck\n\nlet propertyTests =\n    testList \"graph properties\" [\n        test \"reverse is an involution\" {\n            Check.QuickThrowOnFailure(fun (xs: int list) -> List.rev (List.rev xs) = xs)\n        }\n    ]\n```\n\n## Cautions\n\n- **FAKE concurrency:** never run FAKE-backed targets concurrently (shared `.fake` state); use the\n  deterministic serialized order from `CLAUDE.md`\u002F`AGENTS.md`.\n- **`Expecto.FsCheck` is a separate package** — `testProperty` needs it; otherwise call `Check`\n  directly (as above).\n- **Build-tooling scope.** All packages are referenced by `build\u002F**` or `tests\u002FGovernance.Tests`,\n  **never shipped** in a generated product; versions go in `Directory.Packages.props` (Central Package\n  Management). No FCS.\n- Record warm\u002Fcold build wall-clock vs the Stage-0 baseline; the compiled library should beat the\n  207 KB script recompilation.\n\n## Consuming stages\n\nStage 5 (compiled build front-end + routing), Stage 4\u002F5 (golden-parity exit gates), all stages\n(Expecto + FsCheck regression\u002Fproperty tests). See the plan in `metadata.source`.\n\n## Persistent problems\n\nWhen a problem outlasts reasonable in-repo attempts, extensive external research is\n**mandatory** — consult **official online docs first** (the F#\u002F.NET docs and the driven\nlibrary's own documentation\u002FAPI reference), then community sources (forums, Reddit, Q&A\nsites, issue trackers and changelogs). Record the findings and resolving links in the\nfeature's `specs\u002F\u003Cfeature>\u002Ffeedback\u002F` folder and, for durable lessons, in this skill's\n**Sources** line. Offline, the mandate degrades to recording \"research blocked — \u003Cwhy>\"\nrather than hard-failing the phase.\n\n## Sources \u002F links\n\n- Fake.Core.Target: \u003Chttps:\u002F\u002Ffake.build\u002Freference\u002Ffake-core-target.html>\n- DiffPlex: \u003Chttps:\u002F\u002Fgithub.com\u002Fmmanela\u002Fdiffplex>\n- Expecto: \u003Chttps:\u002F\u002Fgithub.com\u002Fhaf\u002Fexpecto> · FsCheck 3: \u003Chttps:\u002F\u002Ffscheck.github.io\u002FFsCheck\u002F>\n- Capability report: `docs\u002Freports\u002F2026-05-31-1714-foundations-fsharp-capabilities-and-libraries.md` §8.\n\n## Related\n\n[[fsharp-parsing]], [[fsharp-graph-algorithms]] (the ported logic under test),\n[[fsharp-code-generation]] (DiffPlex also backs the currency check), [[fsharp-io-globbing]],\n[[fsharp-shell-process]] (the residual processes the front-end drives).\n",{"name":5,"metadata":23,"description":7,"compatibility":26},{"author":24,"source":25},"fs-skia-ui","docs\u002Freports\u002F2026-05-31-1714-foundations-fsharp-capabilities-and-libraries.md","F# governance library (build\u002FGovernance) + build\u002FBuild.fsproj under net10.0; build-tooling scope only.","main","f943406829a9218b2882e09eb88d4ddb539c5e72",".claude\u002Fskills\u002Ffsharp-build-orchestration",0,"https:\u002F\u002Fgithub.com\u002FEHotwagner\u002FFS-Skia-UI","https:\u002F\u002Fgithub.com\u002FEHotwagner","2026-06-16 16:16:52",{"source":8,"skillName":5,"commands":35,"prompt":45,"zipAvailable":46},[36,39,42],{"tool":37,"command":38},"npx","npx skills add EHotwagner\u002FFS-Skia-UI --skill fsharp-build-orchestration",{"tool":40,"command":41},"bunx","bunx skills add EHotwagner\u002FFS-Skia-UI --skill fsharp-build-orchestration",{"tool":43,"command":44},"pnpm","pnpm dlx skills add EHotwagner\u002FFS-Skia-UI --skill fsharp-build-orchestration","安装技能，技能地址：https:\u002F\u002Fgithub.com\u002FEHotwagner\u002FFS-Skia-UI\u002Fblob\u002Fmain\u002F.claude\u002Fskills\u002Ffsharp-build-orchestration\u002FSKILL.md",true,[],[49,56,63,70,77,84],{"skillNo":50,"name":51,"nameZh":6,"description":52,"descriptionZh":6,"repositoryFullName":8,"ownerLogin":9,"ownerAvatarUrl":10,"ownerAccountNo":11,"ownerDisplayName":6,"repositoryNo":12,"starsCount":13,"licenseSpdxId":14,"licenseFileUrl":6,"sourceHtmlUrl":53,"categories":54,"keywords":55,"publishedAt":18},"01M72SGYR4T02T1HTS175E0V86","fs-skia-ui-widgets","Generated product guidance for Skia-rendered FS.Skia.UI Controls, rich text, chart controls, graph controls, DataGrid, and custom wrappers.","https:\u002F\u002Fgithub.com\u002FEHotwagner\u002FFS-Skia-UI\u002Fblob\u002Fmain\u002Ftemplate\u002Fproduct-skills\u002Ffs-skia-ui-widgets\u002FSKILL.md",[],[],{"skillNo":57,"name":58,"nameZh":6,"description":59,"descriptionZh":6,"repositoryFullName":8,"ownerLogin":9,"ownerAvatarUrl":10,"ownerAccountNo":11,"ownerDisplayName":6,"repositoryNo":12,"starsCount":13,"licenseSpdxId":14,"licenseFileUrl":6,"sourceHtmlUrl":60,"categories":61,"keywords":62,"publishedAt":18},"01M72SGVZJR1B117QK7TCC6E0J","fs-skia-testing","Assert generated-product expectations and evidence in a governed FS.Skia.UI product.","https:\u002F\u002Fgithub.com\u002FEHotwagner\u002FFS-Skia-UI\u002Fblob\u002Fmain\u002Ftemplate\u002Fproduct-skills\u002Ffs-skia-testing\u002FSKILL.md",[],[],{"skillNo":64,"name":65,"nameZh":6,"description":66,"descriptionZh":6,"repositoryFullName":8,"ownerLogin":9,"ownerAvatarUrl":10,"ownerAccountNo":11,"ownerDisplayName":6,"repositoryNo":12,"starsCount":13,"licenseSpdxId":14,"licenseFileUrl":6,"sourceHtmlUrl":67,"categories":68,"keywords":69,"publishedAt":18},"01M72SGTC5HZYEVVVZT4X51AZ3","fs-skia-skiaviewer","Wire a generated FS.Skia.UI product to the desktop viewer host.","https:\u002F\u002Fgithub.com\u002FEHotwagner\u002FFS-Skia-UI\u002Fblob\u002Fmain\u002Ftemplate\u002Fproduct-skills\u002Ffs-skia-skiaviewer\u002FSKILL.md",[],[],{"skillNo":71,"name":72,"nameZh":6,"description":73,"descriptionZh":6,"repositoryFullName":8,"ownerLogin":9,"ownerAvatarUrl":10,"ownerAccountNo":11,"ownerDisplayName":6,"repositoryNo":12,"starsCount":13,"licenseSpdxId":14,"licenseFileUrl":6,"sourceHtmlUrl":74,"categories":75,"keywords":76,"publishedAt":18},"01M72SGS47RPYPC9JTC39CC6EF","fs-skia-scene","Build pure scene descriptions in a generated FS.Skia.UI product.","https:\u002F\u002Fgithub.com\u002FEHotwagner\u002FFS-Skia-UI\u002Fblob\u002Fmain\u002Ftemplate\u002Fproduct-skills\u002Ffs-skia-scene\u002FSKILL.md",[],[],{"skillNo":78,"name":79,"nameZh":6,"description":80,"descriptionZh":6,"repositoryFullName":8,"ownerLogin":9,"ownerAvatarUrl":10,"ownerAccountNo":11,"ownerDisplayName":6,"repositoryNo":12,"starsCount":13,"licenseSpdxId":14,"licenseFileUrl":6,"sourceHtmlUrl":81,"categories":82,"keywords":83,"publishedAt":18},"01M72SGQF4G76C4NGSF69KZRRF","fs-skia-keyboard-input","Map keyboard input to product commands in a generated FS.Skia.UI product.","https:\u002F\u002Fgithub.com\u002FEHotwagner\u002FFS-Skia-UI\u002Fblob\u002Fmain\u002Ftemplate\u002Fproduct-skills\u002Ffs-skia-keyboard-input\u002FSKILL.md",[],[],{"skillNo":85,"name":86,"nameZh":6,"description":87,"descriptionZh":6,"repositoryFullName":8,"ownerLogin":9,"ownerAvatarUrl":10,"ownerAccountNo":11,"ownerDisplayName":6,"repositoryNo":12,"starsCount":13,"licenseSpdxId":14,"licenseFileUrl":6,"sourceHtmlUrl":88,"categories":89,"keywords":90,"publishedAt":18},"01M72SGNJP3PMSS2VRP98G7Z42","fs-skia-elmish","Drive a generated FS.Skia.UI product through the pure Elmish adapter.","https:\u002F\u002Fgithub.com\u002FEHotwagner\u002FFS-Skia-UI\u002Fblob\u002Fmain\u002Ftemplate\u002Fproduct-skills\u002Ffs-skia-elmish\u002FSKILL.md",[],[]]