@bendyline/gilde 0.1.40 → 0.1.41
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/authoring/gstack/overlays/investigate.json +1 -0
- package/authoring/gstack/overlays/qa-only.json +1 -0
- package/authoring/gstack/wave.json +12 -2
- package/authoring/tactical/books/accessibility-retrofit.json +188 -0
- package/authoring/tactical/books/apply-review-findings.json +189 -0
- package/authoring/tactical/books/bug-fix-tdd.json +237 -0
- package/authoring/tactical/books/ci-pipeline.json +168 -0
- package/authoring/tactical/books/codemod-sweep.json +182 -0
- package/authoring/tactical/books/dependency-upgrade.json +196 -0
- package/authoring/tactical/books/flaky-test-fix.json +238 -0
- package/authoring/tactical/books/hotfix-flow.json +187 -0
- package/authoring/tactical/books/perf-optimization.json +219 -0
- package/authoring/tactical/books/refactor-module.json +217 -0
- package/authoring/tactical/books/schema-migration.json +192 -0
- package/authoring/tactical/books/test-suite-backfill.json +172 -0
- package/authoring/tactical/books/type-safety-pass.json +185 -0
- package/authoring/tactical/books/ux-update.json +178 -0
- package/authoring/tactical/evals/accessibility-retrofit.json +230 -0
- package/authoring/tactical/evals/apply-review-findings.json +290 -0
- package/authoring/tactical/evals/bug-fix-tdd.json +221 -0
- package/authoring/tactical/evals/ci-pipeline.json +227 -0
- package/authoring/tactical/evals/codemod-sweep.json +252 -0
- package/authoring/tactical/evals/dependency-upgrade.json +235 -0
- package/authoring/tactical/evals/flaky-test-fix.json +239 -0
- package/authoring/tactical/evals/hotfix-flow.json +220 -0
- package/authoring/tactical/evals/perf-optimization.json +235 -0
- package/authoring/tactical/evals/refactor-module.json +241 -0
- package/authoring/tactical/evals/schema-migration.json +225 -0
- package/authoring/tactical/evals/test-suite-backfill.json +197 -0
- package/authoring/tactical/evals/type-safety-pass.json +221 -0
- package/authoring/tactical/evals/ux-update.json +206 -0
- package/authoring/tactical/wave.json +89 -0
- package/data/chat-models/de/deepseek-r1-8b-q4/manifest.json +56 -1
- package/data/chat-models/gl/glm-5.2-754b-q2/manifest.json +56 -0
- package/data/chat-models/gp/gpt-oss-120b-q4/manifest.json +73 -1
- package/data/chat-models/gp/gpt-oss-20b-q4/manifest.json +77 -1
- package/data/chat-models/index.json +1 -1
- package/data/chat-models/ll/llama3.2-3b-q4/manifest.json +3 -1
- package/data/chat-models/mi/mistral-7b-q4/manifest.json +54 -3
- package/data/chat-models/mi/mistral-medium-3.5-128b-q4/manifest.json +76 -1
- package/data/craftbook-templates/ac/accessibility-retrofit/manifest.json +5 -4
- package/data/craftbook-templates/ac/accessibility-retrofit/versions/2.0.0/craftbook.json +451 -0
- package/data/craftbook-templates/ac/accessibility-retrofit/versions/2.0.0/test.json +231 -0
- package/data/craftbook-templates/al/alt-text-pass/manifest.json +5 -1
- package/data/craftbook-templates/ap/apply-review-findings/art.json +12 -0
- package/data/craftbook-templates/ap/apply-review-findings/logo.webp +0 -0
- package/data/craftbook-templates/ap/apply-review-findings/manifest.json +23 -0
- package/data/craftbook-templates/ap/apply-review-findings/versions/1.0.0/craftbook.json +436 -0
- package/data/craftbook-templates/ap/apply-review-findings/versions/1.0.0/test.json +291 -0
- package/data/craftbook-templates/br/browser-qa-audit/manifest.json +5 -1
- package/data/craftbook-templates/br/browser-qa-audit/versions/2.0.5/craftbook.json +438 -0
- package/data/craftbook-templates/br/browser-qa-audit/versions/2.0.5/test.json +379 -0
- package/data/craftbook-templates/bu/bug-fix-tdd/manifest.json +3 -3
- package/data/craftbook-templates/bu/bug-fix-tdd/versions/2.0.0/craftbook.json +545 -0
- package/data/craftbook-templates/bu/bug-fix-tdd/versions/2.0.0/test.json +222 -0
- package/data/craftbook-templates/ch/changelog-cut/manifest.json +5 -1
- package/data/craftbook-templates/ch/changelog-writeup/manifest.json +5 -1
- package/data/craftbook-templates/ci/ci-pipeline/manifest.json +5 -3
- package/data/craftbook-templates/ci/ci-pipeline/versions/2.0.0/craftbook.json +423 -0
- package/data/craftbook-templates/ci/ci-pipeline/versions/2.0.0/test.json +228 -0
- package/data/craftbook-templates/co/codemod-sweep/art.json +12 -0
- package/data/craftbook-templates/co/codemod-sweep/logo.webp +0 -0
- package/data/craftbook-templates/co/codemod-sweep/manifest.json +23 -0
- package/data/craftbook-templates/co/codemod-sweep/versions/1.0.0/craftbook.json +441 -0
- package/data/craftbook-templates/co/codemod-sweep/versions/1.0.0/test.json +253 -0
- package/data/craftbook-templates/de/dependency-upgrade/art.json +12 -0
- package/data/craftbook-templates/de/dependency-upgrade/logo.webp +0 -0
- package/data/craftbook-templates/de/dependency-upgrade/manifest.json +23 -0
- package/data/craftbook-templates/de/dependency-upgrade/versions/1.0.0/craftbook.json +459 -0
- package/data/craftbook-templates/de/dependency-upgrade/versions/1.0.0/test.json +236 -0
- package/data/craftbook-templates/fe/feature-flag-release/manifest.json +5 -1
- package/data/craftbook-templates/fe/feature-flag-rollout/manifest.json +4 -1
- package/data/craftbook-templates/fe/feature-flag-rollout/versions/1.1.0/craftbook.json +203 -0
- package/data/craftbook-templates/fe/feature-flag-rollout/versions/1.1.0/test.json +165 -0
- package/data/craftbook-templates/fl/flaky-test-fix/art.json +12 -0
- package/data/craftbook-templates/fl/flaky-test-fix/logo.webp +0 -0
- package/data/craftbook-templates/fl/flaky-test-fix/manifest.json +24 -0
- package/data/craftbook-templates/fl/flaky-test-fix/versions/1.0.0/craftbook.json +534 -0
- package/data/craftbook-templates/fl/flaky-test-fix/versions/1.0.0/test.json +240 -0
- package/data/craftbook-templates/ho/hotfix-flow/manifest.json +5 -3
- package/data/craftbook-templates/ho/hotfix-flow/versions/2.0.0/craftbook.json +442 -0
- package/data/craftbook-templates/ho/hotfix-flow/versions/2.0.0/test.json +221 -0
- package/data/craftbook-templates/in/investigate/manifest.json +4 -1
- package/data/craftbook-templates/in/investigate-root-cause/manifest.json +5 -1
- package/data/craftbook-templates/index.json +1 -1
- package/data/craftbook-templates/li/live-browser-qa/manifest.json +5 -1
- package/data/craftbook-templates/ni/nightly-fix-sweep/art.json +12 -0
- package/data/craftbook-templates/ni/nightly-fix-sweep/logo.webp +0 -0
- package/data/craftbook-templates/ni/nightly-fix-sweep/manifest.json +23 -0
- package/data/craftbook-templates/ni/nightly-fix-sweep/versions/1.0.0/craftbook.json +145 -0
- package/data/craftbook-templates/ni/nightly-fix-sweep/versions/1.0.0/test.json +121 -0
- package/data/craftbook-templates/pe/perf-audit/versions/1.1.0/craftbook.json +195 -0
- package/data/craftbook-templates/pe/perf-audit/versions/1.1.0/test.json +165 -0
- package/data/craftbook-templates/pe/perf-optimization/manifest.json +3 -3
- package/data/craftbook-templates/pe/perf-optimization/versions/2.0.0/craftbook.json +511 -0
- package/data/craftbook-templates/pe/perf-optimization/versions/2.0.0/test.json +236 -0
- package/data/craftbook-templates/qa/qa/manifest.json +3 -1
- package/data/craftbook-templates/re/refactor-module/manifest.json +2 -2
- package/data/craftbook-templates/re/refactor-module/versions/1.0.4/craftbook.json +150 -0
- package/data/craftbook-templates/re/refactor-module/versions/1.0.4/test.json +95 -0
- package/data/craftbook-templates/re/refactor-module/versions/2.0.0/craftbook.json +509 -0
- package/data/craftbook-templates/re/refactor-module/versions/2.0.0/test.json +242 -0
- package/data/craftbook-templates/re/release-notes/manifest.json +5 -1
- package/data/craftbook-templates/re/release-notes/versions/1.0.3/craftbook.json +220 -0
- package/data/craftbook-templates/re/release-notes/versions/1.0.3/test.json +114 -0
- package/data/craftbook-templates/re/release-pipeline-ci/manifest.json +5 -1
- package/data/craftbook-templates/re/release-readiness-review/versions/1.1.0/craftbook.json +192 -0
- package/data/craftbook-templates/re/release-readiness-review/versions/1.1.0/test.json +113 -0
- package/data/craftbook-templates/ro/root-cause-investigation/manifest.json +7 -1
- package/data/craftbook-templates/ro/root-cause-investigation/versions/2.0.5/craftbook.json +433 -0
- package/data/craftbook-templates/ro/root-cause-investigation/versions/2.0.5/test.json +157 -0
- package/data/craftbook-templates/sc/schema-migration/manifest.json +4 -4
- package/data/craftbook-templates/sc/schema-migration/versions/2.0.0/craftbook.json +459 -0
- package/data/craftbook-templates/sc/schema-migration/versions/2.0.0/test.json +226 -0
- package/data/craftbook-templates/te/test-coverage-review/versions/1.2.0/craftbook.json +195 -0
- package/data/craftbook-templates/te/test-coverage-review/versions/1.2.0/test.json +116 -0
- package/data/craftbook-templates/te/test-suite-backfill/manifest.json +1 -2
- package/data/craftbook-templates/te/test-suite-backfill/versions/2.0.0/craftbook.json +428 -0
- package/data/craftbook-templates/te/test-suite-backfill/versions/2.0.0/test.json +198 -0
- package/data/craftbook-templates/ty/type-safety-pass/manifest.json +3 -3
- package/data/craftbook-templates/ty/type-safety-pass/versions/2.0.0/craftbook.json +428 -0
- package/data/craftbook-templates/ty/type-safety-pass/versions/2.0.0/test.json +222 -0
- package/data/craftbook-templates/ux/ux-update/art.json +12 -0
- package/data/craftbook-templates/ux/ux-update/logo.webp +0 -0
- package/data/craftbook-templates/ux/ux-update/manifest.json +22 -0
- package/data/craftbook-templates/ux/ux-update/versions/1.0.0/craftbook.json +439 -0
- package/data/craftbook-templates/ux/ux-update/versions/1.0.0/test.json +207 -0
- package/data/craftbook-templates/ve/version-bump/versions/1.1.0/craftbook.json +206 -0
- package/data/craftbook-templates/ve/version-bump/versions/1.1.0/test.json +95 -0
- package/data/gezel-templates/bo/boekwachter/versions/1.1.0/about.md +29 -0
- package/data/gezel-templates/bo/boekwachter/versions/1.1.0/manifest.json +16 -0
- package/data/gezel-templates/bu/builder/versions/1.5.0/about.md +34 -0
- package/data/gezel-templates/bu/builder/versions/1.5.0/manifest.json +16 -0
- package/data/gezel-templates/de/developer/versions/1.5.0/about.md +34 -0
- package/data/gezel-templates/de/developer/versions/1.5.0/manifest.json +21 -0
- package/data/gezel-templates/index.json +1 -1
- package/data/gezel-templates/re/reviewer/versions/1.4.0/about.md +49 -0
- package/data/gezel-templates/re/reviewer/versions/1.4.0/manifest.json +21 -0
- package/data/project-types/index.json +1 -1
- package/data/project-types/so/software-project/manifest.json +20 -0
- package/data/project-types/so/software-project/versions/1.0.0/about.md +3 -0
- package/data/project-types/so/software-project/versions/1.0.0/manifest.json +41 -0
- package/data/project-types/so/software-project/versions/1.0.0/mission.md +4 -0
- package/package.json +1 -1
- package/schemas/craftbook-doc.schema.json +248 -0
- package/schemas/craftbook-template-version.schema.json +248 -0
- package/schemas/craftbook-test.schema.json +200 -0
|
@@ -0,0 +1,236 @@
|
|
|
1
|
+
{
|
|
2
|
+
"schemaVersion": 1,
|
|
3
|
+
"title": "Vendored dependency upgrade with staged receipts",
|
|
4
|
+
"objective": "The craftbook drives a staged upgrade of a vendored library across a breaking major: a recorded green suite before any change, the v2 API adopted at both real call sites with behavior preserved against the v1 reference, an honest stage record, and an enforced review - all verified mechanically, including a resolved-module check proving the call sites genuinely run v2.",
|
|
5
|
+
"tags": [
|
|
6
|
+
"code",
|
|
7
|
+
"dependency-upgrade",
|
|
8
|
+
"tactical-fleet"
|
|
9
|
+
],
|
|
10
|
+
"prompt": "Use the Upgrade a Dependency craftbook for this: upgrade our vendored markdownlite library from 1.4.2 to the staged 2.0.0 copy. The vendoring convention and the v2 changelog are in VENDORING.md, and the request is in source/upgrade-request.md. Rendering behavior must not change - adapt the call sites to the new API rather than accepting the new defaults.",
|
|
11
|
+
"setup": {
|
|
12
|
+
"projectName": "Relay Notes",
|
|
13
|
+
"about": "A tiny note-rendering module for a team relay tool. Dependencies are vendored under lib/vendored/ per VENDORING.md. Tests run with `npm run test` (node --test).",
|
|
14
|
+
"files": [
|
|
15
|
+
{
|
|
16
|
+
"path": "package.json",
|
|
17
|
+
"content": "{\n \"name\": \"relay-notes\",\n \"private\": true,\n \"version\": \"1.0.0\",\n \"type\": \"module\",\n \"scripts\": {\n \"test\": \"node --test\"\n }\n}\n"
|
|
18
|
+
},
|
|
19
|
+
{
|
|
20
|
+
"path": "lib/vendored/markdownlite.js",
|
|
21
|
+
"content": "// markdownlite 1.4.2 (vendored - see VENDORING.md)\nexport function parse(text) {\n const lines = String(text).split(/\\r?\\n/);\n const out = [];\n for (const line of lines) {\n const t = line.trim();\n if (t === '') continue;\n const h = /^(#{1,3})\\s+(.*)$/.exec(t);\n if (h) {\n out.push(`<h${h[1].length}>${inline(h[2])}</h${h[1].length}>`);\n } else {\n out.push(`<p>${inline(t)}</p>`);\n }\n }\n return out.join('\\n');\n}\n\nfunction inline(text) {\n return text.replace(/\\*([^*]+)\\*/g, '<em>$1</em>');\n}\n"
|
|
22
|
+
},
|
|
23
|
+
{
|
|
24
|
+
"path": "lib/vendored/v2/markdownlite.js",
|
|
25
|
+
"content": "// markdownlite 2.0.0 (vendored staging copy - see VENDORING.md)\nexport function parseDoc(text, options = {}) {\n const wrapParagraphs = options.wrapParagraphs ?? false;\n const lines = String(text).split(/\\r?\\n/);\n const out = [];\n for (const line of lines) {\n const t = line.trim();\n if (t === '') continue;\n const h = /^(#{1,3})\\s+(.*)$/.exec(t);\n if (h) {\n out.push(`<h${h[1].length}>${inline(h[2])}</h${h[1].length}>`);\n } else {\n out.push(wrapParagraphs ? `<p>${inline(t)}</p>` : inline(t));\n }\n }\n return out.join('\\n');\n}\n\nfunction inline(text) {\n return text.replace(/\\*([^*]+)\\*/g, '<em>$1</em>');\n}\n"
|
|
26
|
+
},
|
|
27
|
+
{
|
|
28
|
+
"path": "src/render-note.js",
|
|
29
|
+
"content": "import { parse } from '../lib/vendored/markdownlite.js';\n\nexport function renderNote(note) {\n return `<h2>${note.title}</h2>\\n${parse(note.body)}`;\n}\n"
|
|
30
|
+
},
|
|
31
|
+
{
|
|
32
|
+
"path": "src/render-digest.js",
|
|
33
|
+
"content": "import { parse } from '../lib/vendored/markdownlite.js';\n\nexport function renderDigest(notes) {\n return notes\n .map((note) => `<section>\\n<h2>${note.title}</h2>\\n${parse(note.body)}\\n</section>`)\n .join('\\n');\n}\n"
|
|
34
|
+
},
|
|
35
|
+
{
|
|
36
|
+
"path": "tests/render-note.test.mjs",
|
|
37
|
+
"content": "import assert from 'node:assert/strict';\nimport { test } from 'node:test';\nimport { renderNote } from '../src/render-note.js';\n\ntest('renders the body as wrapped paragraphs', () => {\n assert.equal(\n renderNote({ title: 'Standup', body: 'we shipped the *fast* path' }),\n '<h2>Standup</h2>\\n<p>we shipped the <em>fast</em> path</p>',\n );\n});\n\ntest('renders headings inside the body', () => {\n assert.equal(\n renderNote({ title: 'Plan', body: '# Goals\\nship it' }),\n '<h2>Plan</h2>\\n<h1>Goals</h1>\\n<p>ship it</p>',\n );\n});\n"
|
|
38
|
+
},
|
|
39
|
+
{
|
|
40
|
+
"path": "tests/render-digest.test.mjs",
|
|
41
|
+
"content": "import assert from 'node:assert/strict';\nimport { test } from 'node:test';\nimport { renderDigest } from '../src/render-digest.js';\n\ntest('joins every note as a wrapped section', () => {\n const html = renderDigest([\n { title: 'One', body: 'first' },\n { title: 'Two', body: 'second line' },\n ]);\n assert.equal(\n html,\n '<section>\\n<h2>One</h2>\\n<p>first</p>\\n</section>\\n<section>\\n<h2>Two</h2>\\n<p>second line</p>\\n</section>',\n );\n});\n"
|
|
42
|
+
},
|
|
43
|
+
{
|
|
44
|
+
"path": "VENDORING.md",
|
|
45
|
+
"content": "# Vendoring convention\n\nThis project vendors small dependencies directly under `lib/vendored/` instead\nof installing them from a registry. Each vendored library is a single file named\nafter the package. Upgrades arrive as a staged copy in a version subfolder\n(for example `lib/vendored/v2/`) so the switch is an explicit, reviewable\nchange: move the staged copy into place (or point the imports at it), adapt the\ncall sites, and remove the staging folder when the switch is complete.\n\n## markdownlite\n\nCurrent vendored version: 1.4.2 at `lib/vendored/markdownlite.js`.\nStaged upgrade: 2.0.0 at `lib/vendored/v2/markdownlite.js`.\n\n### markdownlite 2.0.0 changelog\n\n- BREAKING: `parse(text)` is renamed to `parseDoc(text, options)`.\n- BREAKING: plain lines are no longer wrapped in `<p>` by default. Paragraph\n wrapping is now opt-in: pass `{ wrapParagraphs: true }` to keep the 1.x\n output.\n- Heading and emphasis handling are unchanged.\n"
|
|
46
|
+
},
|
|
47
|
+
{
|
|
48
|
+
"path": "source/upgrade-request.md",
|
|
49
|
+
"content": "# Upgrade request\n\nPlease move us from vendored markdownlite 1.4.2 to the staged 2.0.0 copy.\nThe v2 changelog is in VENDORING.md. Rendering behavior must not change:\nnotes and digests must produce exactly the same HTML as today, so adapt the\ncall sites to the new API rather than accepting the new defaults.\n"
|
|
50
|
+
},
|
|
51
|
+
{
|
|
52
|
+
"path": "tests/verify-upgrade.mjs",
|
|
53
|
+
"content": "import assert from 'node:assert/strict';\nimport { execFileSync } from 'node:child_process';\nimport { readFileSync } from 'node:fs';\nimport { join } from 'node:path';\nimport { pathToFileURL } from 'node:url';\n\nconst root = process.cwd();\n\n// 1) Both call sites moved off the removed v1 API and resolve to a v2 module.\n// Accepted either way: v2 copied into place at lib/vendored/markdownlite.js,\n// or imports repointed at the staged v2 file.\nconst callSites = ['src/render-note.js', 'src/render-digest.js'];\nfor (const file of callSites) {\n const source = readFileSync(join(root, file), 'utf8');\n assert.ok(/\\bparseDoc\\s*\\(/.test(source), `${file} must call the v2 parseDoc API`);\n assert.ok(!/\\bparse\\s*\\(/.test(source), `${file} still calls the removed v1 parse API`);\n const spec = /import\\s*\\{[^}]*\\}\\s*from\\s*['\"]([^'\"]*markdownlite[^'\"]*)['\"]/.exec(source);\n assert.ok(spec, `${file} must import the vendored markdownlite module`);\n const mod = await import(new URL(spec[1], pathToFileURL(join(root, file))).href);\n assert.equal(typeof mod.parseDoc, 'function', `${file} must resolve to markdownlite v2 (parseDoc export)`);\n assert.equal(mod.parse, undefined, `${file} resolves to a module that still exports the removed v1 parse API`);\n}\nconsole.log('DEPUPGRADE_ORACLE call sites adapted');\n\n// 2) Behavior is unchanged against the v1 reference output.\nconst { renderNote } = await import(pathToFileURL(join(root, 'src/render-note.js')).href);\nconst { renderDigest } = await import(pathToFileURL(join(root, 'src/render-digest.js')).href);\nassert.equal(\n renderNote({ title: 'Standup', body: 'we shipped the *fast* path' }),\n '<h2>Standup</h2>\\n<p>we shipped the <em>fast</em> path</p>',\n 'renderNote must keep wrapping paragraphs after the upgrade',\n);\nassert.equal(\n renderNote({ title: 'Plan', body: '# Goals\\nship it' }),\n '<h2>Plan</h2>\\n<h1>Goals</h1>\\n<p>ship it</p>',\n 'renderNote must keep heading handling after the upgrade',\n);\nassert.equal(\n renderDigest([\n { title: 'One', body: 'first' },\n { title: 'Two', body: 'second line' },\n ]),\n '<section>\\n<h2>One</h2>\\n<p>first</p>\\n</section>\\n<section>\\n<h2>Two</h2>\\n<p>second line</p>\\n</section>',\n 'renderDigest must keep its exact output after the upgrade',\n);\nconsole.log('DEPUPGRADE_ORACLE behavior ok');\n\n// 3) The suite is green on the upgraded tree, and the seeded tests survive.\nreadFileSync(join(root, 'tests/render-note.test.mjs'));\nreadFileSync(join(root, 'tests/render-digest.test.mjs'));\nfunction runSuite(cwd) {\n try {\n execFileSync(process.execPath, ['--test'], { cwd, stdio: 'pipe', timeout: 30000 });\n return 0;\n } catch (err) {\n return typeof err.status === 'number' ? err.status : 1;\n }\n}\nassert.equal(runSuite(root), 0, 'the suite must be green on the upgraded tree');\nconsole.log('DEPUPGRADE_ORACLE suite green');\nconsole.log('DEPUPGRADE_ORACLE done');\n",
|
|
54
|
+
"surface": "harness"
|
|
55
|
+
}
|
|
56
|
+
],
|
|
57
|
+
"craftbookParams": {
|
|
58
|
+
"workPath": "tasks/eval",
|
|
59
|
+
"scope": "Upgrade the vendored markdownlite from 1.4.2 to the staged 2.0.0 copy per VENDORING.md; rendering behavior must not change."
|
|
60
|
+
}
|
|
61
|
+
},
|
|
62
|
+
"mocks": [],
|
|
63
|
+
"success": {
|
|
64
|
+
"summary": "The vendored library runs at v2 through both call sites (either moved into place or repointed), every adaptation preserves the exact v1 rendering behavior, the suite is green, and every fleet artifact exists with honest receipts.",
|
|
65
|
+
"deliverables": [
|
|
66
|
+
{
|
|
67
|
+
"path": "tasks/eval/survey.md",
|
|
68
|
+
"kind": "markdown-notes",
|
|
69
|
+
"artifact": true,
|
|
70
|
+
"minBytes": 600,
|
|
71
|
+
"checks": [
|
|
72
|
+
{
|
|
73
|
+
"kind": "contains",
|
|
74
|
+
"file": "tasks/eval/survey.md",
|
|
75
|
+
"pattern": "^##\\s+Current state[\\s\\S]*^##\\s+Candidates[\\s\\S]*^##\\s+Breaking-change notes[\\s\\S]*^##\\s+Stage plan",
|
|
76
|
+
"flags": "im",
|
|
77
|
+
"label": "survey sections in order"
|
|
78
|
+
},
|
|
79
|
+
{
|
|
80
|
+
"kind": "contains",
|
|
81
|
+
"file": "tasks/eval/survey.md",
|
|
82
|
+
"pattern": "parseDoc",
|
|
83
|
+
"label": "names the real v2 API change from the local changelog"
|
|
84
|
+
},
|
|
85
|
+
{
|
|
86
|
+
"kind": "citationsResolve",
|
|
87
|
+
"file": "tasks/eval/survey.md",
|
|
88
|
+
"minCitations": 2,
|
|
89
|
+
"artifact": true
|
|
90
|
+
}
|
|
91
|
+
]
|
|
92
|
+
},
|
|
93
|
+
{
|
|
94
|
+
"path": "tasks/eval/change-notes.md",
|
|
95
|
+
"kind": "markdown-notes",
|
|
96
|
+
"artifact": true,
|
|
97
|
+
"minBytes": 700,
|
|
98
|
+
"checks": [
|
|
99
|
+
{
|
|
100
|
+
"kind": "contains",
|
|
101
|
+
"file": "tasks/eval/change-notes.md",
|
|
102
|
+
"pattern": "^##\\s+Stages executed[\\s\\S]*^##\\s+Files touched[\\s\\S]*^##\\s+Adaptations[\\s\\S]*^##\\s+Reverted stages",
|
|
103
|
+
"flags": "im",
|
|
104
|
+
"label": "change-notes sections in order"
|
|
105
|
+
},
|
|
106
|
+
{
|
|
107
|
+
"kind": "citationsResolve",
|
|
108
|
+
"file": "tasks/eval/change-notes.md",
|
|
109
|
+
"minCitations": 2,
|
|
110
|
+
"artifact": true
|
|
111
|
+
}
|
|
112
|
+
]
|
|
113
|
+
},
|
|
114
|
+
{
|
|
115
|
+
"path": "tasks/eval/verification.md",
|
|
116
|
+
"kind": "markdown-notes",
|
|
117
|
+
"artifact": true,
|
|
118
|
+
"minBytes": 450,
|
|
119
|
+
"checks": [
|
|
120
|
+
{
|
|
121
|
+
"kind": "contains",
|
|
122
|
+
"file": "tasks/eval/verification.md",
|
|
123
|
+
"pattern": "^##\\s+Suite[\\s\\S]*^##\\s+Adaptations verified[\\s\\S]*^##\\s+Rollback[\\s\\S]*^##\\s+Result",
|
|
124
|
+
"flags": "im",
|
|
125
|
+
"label": "verification sections in order"
|
|
126
|
+
}
|
|
127
|
+
]
|
|
128
|
+
},
|
|
129
|
+
{
|
|
130
|
+
"path": "tasks/eval/review.md",
|
|
131
|
+
"kind": "markdown-report",
|
|
132
|
+
"artifact": true,
|
|
133
|
+
"minBytes": 400,
|
|
134
|
+
"checks": [
|
|
135
|
+
{
|
|
136
|
+
"kind": "contains",
|
|
137
|
+
"file": "tasks/eval/review.md",
|
|
138
|
+
"pattern": "Verdict:\\s*(?:PASS|REVISE)",
|
|
139
|
+
"flags": "i",
|
|
140
|
+
"label": "explicit reviewer verdict"
|
|
141
|
+
}
|
|
142
|
+
]
|
|
143
|
+
}
|
|
144
|
+
],
|
|
145
|
+
"checks": [
|
|
146
|
+
{
|
|
147
|
+
"kind": "notContains",
|
|
148
|
+
"file": "src/render-note.js",
|
|
149
|
+
"pattern": "\\bparse\\s*\\(|import\\s*\\{[^}]*\\bparse\\b[^}]*\\}",
|
|
150
|
+
"label": "the removed v1 parse API is gone from the note call site"
|
|
151
|
+
},
|
|
152
|
+
{
|
|
153
|
+
"kind": "notContains",
|
|
154
|
+
"file": "src/render-digest.js",
|
|
155
|
+
"pattern": "\\bparse\\s*\\(|import\\s*\\{[^}]*\\bparse\\b[^}]*\\}",
|
|
156
|
+
"label": "the removed v1 parse API is gone from the digest call site"
|
|
157
|
+
},
|
|
158
|
+
{
|
|
159
|
+
"kind": "sourceParses",
|
|
160
|
+
"file": "src/render-note.js"
|
|
161
|
+
},
|
|
162
|
+
{
|
|
163
|
+
"kind": "sourceParses",
|
|
164
|
+
"file": "src/render-digest.js"
|
|
165
|
+
},
|
|
166
|
+
{
|
|
167
|
+
"kind": "nodeRuns",
|
|
168
|
+
"file": "tests/render-note.test.mjs"
|
|
169
|
+
},
|
|
170
|
+
{
|
|
171
|
+
"kind": "nodeScriptPasses",
|
|
172
|
+
"script": "tests/verify-upgrade.mjs",
|
|
173
|
+
"timeoutMs": 60000,
|
|
174
|
+
"requiredOutput": [
|
|
175
|
+
{
|
|
176
|
+
"pattern": "DEPUPGRADE_ORACLE call sites adapted",
|
|
177
|
+
"label": "both call sites run the v2 API"
|
|
178
|
+
},
|
|
179
|
+
{
|
|
180
|
+
"pattern": "DEPUPGRADE_ORACLE behavior ok",
|
|
181
|
+
"label": "rendering behavior preserved against the v1 reference"
|
|
182
|
+
},
|
|
183
|
+
{
|
|
184
|
+
"pattern": "DEPUPGRADE_ORACLE suite green",
|
|
185
|
+
"label": "suite green on the upgraded tree"
|
|
186
|
+
}
|
|
187
|
+
]
|
|
188
|
+
}
|
|
189
|
+
],
|
|
190
|
+
"taskNotes": {
|
|
191
|
+
"minBytes": 120,
|
|
192
|
+
"checks": [
|
|
193
|
+
{
|
|
194
|
+
"kind": "contains",
|
|
195
|
+
"file": "task-notes.md",
|
|
196
|
+
"pattern": "\\bDONE\\b[\\s\\S]*(npm\\s+run\\s+test|node\\s+--test)",
|
|
197
|
+
"flags": "i",
|
|
198
|
+
"label": "DONE note names the real test command"
|
|
199
|
+
}
|
|
200
|
+
]
|
|
201
|
+
},
|
|
202
|
+
"taskGraph": {
|
|
203
|
+
"requireCraftbookTask": true,
|
|
204
|
+
"requireTerminalStep": true
|
|
205
|
+
},
|
|
206
|
+
"unchangedFixtures": [
|
|
207
|
+
"source/upgrade-request.md",
|
|
208
|
+
"package.json"
|
|
209
|
+
]
|
|
210
|
+
},
|
|
211
|
+
"rubric": {
|
|
212
|
+
"artifact": {
|
|
213
|
+
"path": "tasks/eval/change-notes.md",
|
|
214
|
+
"kind": "markdown"
|
|
215
|
+
},
|
|
216
|
+
"axes": [
|
|
217
|
+
{
|
|
218
|
+
"name": "Staged discipline",
|
|
219
|
+
"description": "The work ran as ordered stages with the suite genuinely run before the first change and between stages, and the record distinguishes executed stages from reverted or deferred ones."
|
|
220
|
+
},
|
|
221
|
+
{
|
|
222
|
+
"name": "Local evidence honesty",
|
|
223
|
+
"description": "Breaking-change notes come from sources actually read in the repository (VENDORING.md, the staged v2 file), with nothing presented as a release note that was invented."
|
|
224
|
+
},
|
|
225
|
+
{
|
|
226
|
+
"name": "Adaptation fidelity",
|
|
227
|
+
"description": "Call sites were adapted at their real locations to preserve exact rendering behavior under the v2 API, rather than accepting changed defaults or weakening tests."
|
|
228
|
+
}
|
|
229
|
+
]
|
|
230
|
+
},
|
|
231
|
+
"qualityFocus": [
|
|
232
|
+
"staged upgrades with receipts",
|
|
233
|
+
"local breaking-change evidence",
|
|
234
|
+
"honest reverts"
|
|
235
|
+
]
|
|
236
|
+
}
|
|
@@ -0,0 +1,203 @@
|
|
|
1
|
+
{
|
|
2
|
+
"id": "feature-flag-rollout",
|
|
3
|
+
"name": "Flagged Feature Rollout",
|
|
4
|
+
"description": "Add a new feature behind a feature flag so it can ship dark, be toggled per-environment/user, and roll back instantly without a deploy. Plans the flag contract FIRST — the flag name/default, the toggle points, the on/off behavior, the targeting (env/percentage/user), and the cleanup plan — then implements the flagged code with both paths working, then a reviewer verifies both states behave and the off-state default is safe. Covers feature flags, toggle points, percentage/targeted rollout, default-off safety, dark launches, and flag-cleanup discipline.\n\nA gallery craftbook generated from an archetype spec. It runs\n`phase → (per-phase gate) → … → evaluate → (loop) → finish`. Each build\nphase that produces a checkable artifact is followed by a **runtime\ngate-checkpoint** — the runtime verifies the artifact and routes with no\nmodel turn, looping back to redo the phase on a miss. The final `evaluate`\nstep holds a static deliverable gate plus a reviewer QA pass. What it adds\nover the generic `build-loop`: a specialist role per phase, a\ndomain-correct ordering, and a concrete per-phase quality bar.\n\nDeliverables marked \"artifact\" land in the project's artifacts drawer (`write_artifact` / `read_artifact`), not the shipped workspace — review output is not product source.\n\nPhases:\n\n1. Plan the flag (planner) — lock flag name, default, toggle points, targeting → gated on artifact `{{workPath}}/plan.md` (markdown-notes)\n2. Build the flagged feature (developer) — implement both paths behind the flag → gated on `src/feature.js` (code-module)\n3. Verify both states (reviewer) — confirm off=original, on=new, safe default → gated on artifact `{{workPath}}/verify.md` (markdown-notes)\n\nThe gates never advance with an unmet criterion, and loop back to the\nowning phase to fix named gaps.\n",
|
|
5
|
+
"entryStepId": "plan",
|
|
6
|
+
"triggers": [
|
|
7
|
+
"add a feature flag",
|
|
8
|
+
"ship behind a flag",
|
|
9
|
+
"feature toggle",
|
|
10
|
+
"gradual rollout",
|
|
11
|
+
"dark launch a feature",
|
|
12
|
+
"feature flag rollout plan",
|
|
13
|
+
"canary release plan",
|
|
14
|
+
"percentage ramp",
|
|
15
|
+
"dark launch behind a flag"
|
|
16
|
+
],
|
|
17
|
+
"steps": [
|
|
18
|
+
{
|
|
19
|
+
"id": "plan",
|
|
20
|
+
"name": "Plan the flag",
|
|
21
|
+
"description": "lock flag name, default, toggle points, targeting",
|
|
22
|
+
"prompt": "Plan the feature flag before coding. Step 1: Name the flag and set its DEFAULT (default-off is the safe choice for new features) and where its value is read from (config/env/flag service). Step 2: Identify the toggle points in the code — exactly where the flag branches old behavior vs new. Step 3: Define the behavior in each state precisely, and the targeting strategy (all-on/off, per-environment, percentage, or specific users). Step 4: Note the rollback story (flip the flag, no deploy) and the cleanup plan (when/how the flag and the dead branch get removed later). Step 5: Write a numbered acceptance-criteria checklist of 5-9 items (e.g. 'flag-off reproduces the original behavior exactly', 'flag-on enables the new feature', 'the default is safe', 'no code path runs both branches'). `write_task_note` the flag plan + checklist and write the same to the produces path.\n\nThe deliverable `{{workPath}}/plan.md` lands in the project's artifacts drawer — write it with `write_artifact` and read it back with `read_artifact`; the shipped workspace stays untouched.",
|
|
23
|
+
"suggestedRole": "planner",
|
|
24
|
+
"advanceWhen": {
|
|
25
|
+
"file": "{{workPath}}/plan.md",
|
|
26
|
+
"minBytes": 1,
|
|
27
|
+
"sniff": "nonempty",
|
|
28
|
+
"artifact": true
|
|
29
|
+
},
|
|
30
|
+
"gate": {
|
|
31
|
+
"at": "completion",
|
|
32
|
+
"checks": [
|
|
33
|
+
{
|
|
34
|
+
"kind": "minBytes",
|
|
35
|
+
"file": "{{workPath}}/plan.md",
|
|
36
|
+
"bytes": 120,
|
|
37
|
+
"artifact": true
|
|
38
|
+
},
|
|
39
|
+
{
|
|
40
|
+
"kind": "sniff",
|
|
41
|
+
"file": "{{workPath}}/plan.md",
|
|
42
|
+
"sniff": "nonempty",
|
|
43
|
+
"artifact": true
|
|
44
|
+
}
|
|
45
|
+
],
|
|
46
|
+
"onReject": "plan",
|
|
47
|
+
"maxAttempts": 3
|
|
48
|
+
},
|
|
49
|
+
"next": "build"
|
|
50
|
+
},
|
|
51
|
+
{
|
|
52
|
+
"id": "build",
|
|
53
|
+
"name": "Build the flagged feature",
|
|
54
|
+
"description": "implement both paths behind the flag",
|
|
55
|
+
"prompt": "Implement the feature behind the flag to the plan. Step 1: Read the flag value from the agreed source with the safe default. Step 2: At each toggle point, branch cleanly: flag-OFF must reproduce the original behavior exactly (no behavior change for existing users), flag-ON enables the new feature. Step 3: Keep the flag check at the boundary so the two paths are clear and neither leaks into the other; support the targeting strategy (e.g. percentage/user check) if specified. Step 4: Ensure the new feature is reachable only when on, and that the off path is the trusted fallback. Write the implementation to the produces path. On a loop-back, fix only the named gap. `write_task_note` the file path and which criteria now pass.",
|
|
56
|
+
"suggestedRole": "developer",
|
|
57
|
+
"advanceWhen": {
|
|
58
|
+
"file": "src/feature.js",
|
|
59
|
+
"minBytes": 1,
|
|
60
|
+
"sniff": "nonempty"
|
|
61
|
+
},
|
|
62
|
+
"gate": {
|
|
63
|
+
"at": "completion",
|
|
64
|
+
"checks": [
|
|
65
|
+
{
|
|
66
|
+
"kind": "minBytes",
|
|
67
|
+
"file": "src/feature.js",
|
|
68
|
+
"bytes": 200
|
|
69
|
+
},
|
|
70
|
+
{
|
|
71
|
+
"kind": "sniff",
|
|
72
|
+
"file": "src/feature.js",
|
|
73
|
+
"sniff": "nonempty"
|
|
74
|
+
},
|
|
75
|
+
{
|
|
76
|
+
"kind": "esmImports",
|
|
77
|
+
"file": "src/feature.js"
|
|
78
|
+
},
|
|
79
|
+
{
|
|
80
|
+
"kind": "sourceParses",
|
|
81
|
+
"file": "src/feature.js"
|
|
82
|
+
}
|
|
83
|
+
],
|
|
84
|
+
"onReject": "build",
|
|
85
|
+
"maxAttempts": 3
|
|
86
|
+
},
|
|
87
|
+
"next": "verify"
|
|
88
|
+
},
|
|
89
|
+
{
|
|
90
|
+
"id": "verify",
|
|
91
|
+
"name": "Verify both states",
|
|
92
|
+
"description": "confirm off=original, on=new, safe default",
|
|
93
|
+
"prompt": "Verify the flag behaves in both states. Step 1: With the flag OFF, confirm the behavior is identical to before the feature existed (existing tests still green, no surprises). Step 2: With the flag ON, confirm the new feature works as specified. Step 3: Confirm the default value is the safe one and that flipping the flag fully switches behavior with no deploy needed. Step 4: Confirm targeting (if any) routes correctly and that no path accidentally runs both branches. Write a verification note covering the off-state, on-state, and default to the produces path.\n\nThe deliverable `{{workPath}}/verify.md` lands in the project's artifacts drawer — write it with `write_artifact` and read it back with `read_artifact`; the shipped workspace stays untouched.",
|
|
94
|
+
"suggestedRole": "reviewer",
|
|
95
|
+
"advanceWhen": {
|
|
96
|
+
"file": "{{workPath}}/verify.md",
|
|
97
|
+
"minBytes": 1,
|
|
98
|
+
"sniff": "nonempty",
|
|
99
|
+
"artifact": true,
|
|
100
|
+
"requireChange": true
|
|
101
|
+
},
|
|
102
|
+
"gate": {
|
|
103
|
+
"at": "completion",
|
|
104
|
+
"checks": [
|
|
105
|
+
{
|
|
106
|
+
"kind": "minBytes",
|
|
107
|
+
"file": "src/feature.js",
|
|
108
|
+
"bytes": 200
|
|
109
|
+
},
|
|
110
|
+
{
|
|
111
|
+
"kind": "sniff",
|
|
112
|
+
"file": "src/feature.js",
|
|
113
|
+
"sniff": "nonempty"
|
|
114
|
+
},
|
|
115
|
+
{
|
|
116
|
+
"kind": "esmImports",
|
|
117
|
+
"file": "src/feature.js"
|
|
118
|
+
},
|
|
119
|
+
{
|
|
120
|
+
"kind": "sourceParses",
|
|
121
|
+
"file": "src/feature.js"
|
|
122
|
+
},
|
|
123
|
+
{
|
|
124
|
+
"kind": "citationsResolve",
|
|
125
|
+
"file": "{{workPath}}/verify.md",
|
|
126
|
+
"minCitations": 2,
|
|
127
|
+
"artifact": true
|
|
128
|
+
}
|
|
129
|
+
],
|
|
130
|
+
"onReject": "verify",
|
|
131
|
+
"maxAttempts": 4
|
|
132
|
+
},
|
|
133
|
+
"next": "evaluate"
|
|
134
|
+
},
|
|
135
|
+
{
|
|
136
|
+
"id": "evaluate",
|
|
137
|
+
"name": "Evaluate",
|
|
138
|
+
"description": "Grade the deliverable against every acceptance criterion. All pass → finish; any fail → loop back and fix the gap.",
|
|
139
|
+
"prompt": "Review `{{workPath}}/verify.md` against the original scope: every claim cites a real path, the severities and priorities are defensible, and nothing important in scope was skipped. Open the underlying files for at least the top findings; do not grade from the report's own summary. If a finding cannot be verified, say so explicitly.\n\nWrite your review to the artifact `{{workPath}}/review.md` with one `write_artifact` call: what you checked, what held, what did not (as a findings table with columns `| Severity | File | Line | Problem | Fix |` when anything needs fixing), ending with exactly `Verdict: PASS` or `Verdict: REVISE`. The gate enforces the verdict: a well-formed REVISE is routed back to the `verify` step automatically with your findings. On PASS, `advance_task_step` to `finish`.",
|
|
140
|
+
"suggestedRole": "reviewer",
|
|
141
|
+
"consumes": [
|
|
142
|
+
{
|
|
143
|
+
"file": "src/feature.js"
|
|
144
|
+
}
|
|
145
|
+
],
|
|
146
|
+
"next": "finish",
|
|
147
|
+
"gate": {
|
|
148
|
+
"at": "completion",
|
|
149
|
+
"checks": [
|
|
150
|
+
{
|
|
151
|
+
"kind": "minBytes",
|
|
152
|
+
"file": "{{workPath}}/review.md",
|
|
153
|
+
"bytes": 300,
|
|
154
|
+
"artifact": true
|
|
155
|
+
},
|
|
156
|
+
{
|
|
157
|
+
"kind": "contains",
|
|
158
|
+
"file": "{{workPath}}/review.md",
|
|
159
|
+
"pattern": "Verdict:\\s*(?:PASS|REVISE)",
|
|
160
|
+
"flags": "i",
|
|
161
|
+
"label": "explicit PASS or REVISE verdict",
|
|
162
|
+
"artifact": true
|
|
163
|
+
}
|
|
164
|
+
],
|
|
165
|
+
"scripts": [
|
|
166
|
+
{
|
|
167
|
+
"name": "checkFixReview",
|
|
168
|
+
"scope": "standard",
|
|
169
|
+
"inputs": {
|
|
170
|
+
"taskRef": "{{task.ref}}",
|
|
171
|
+
"reviewPath": "{{workPath}}/review.md",
|
|
172
|
+
"fixStepId": "verify"
|
|
173
|
+
}
|
|
174
|
+
}
|
|
175
|
+
],
|
|
176
|
+
"onReject": "evaluate",
|
|
177
|
+
"maxAttempts": 4
|
|
178
|
+
}
|
|
179
|
+
},
|
|
180
|
+
{
|
|
181
|
+
"id": "finish",
|
|
182
|
+
"name": "Finish",
|
|
183
|
+
"description": "All acceptance criteria met. Stamp a short summary and report DONE.",
|
|
184
|
+
"prompt": "Every acceptance criterion passed. Write a one-paragraph DONE summary to task notes via `write_task_note`: what was built, the deliverable path(s), and a one-line confirmation that each criterion is met. Then report DONE.",
|
|
185
|
+
"suggestedRole": "developer",
|
|
186
|
+
"terminal": true
|
|
187
|
+
}
|
|
188
|
+
],
|
|
189
|
+
"version": "1.1.0",
|
|
190
|
+
"releasedAt": "2026-08-24T00:00:00.000Z",
|
|
191
|
+
"paramSchema": {
|
|
192
|
+
"type": "object",
|
|
193
|
+
"properties": {
|
|
194
|
+
"workPath": {
|
|
195
|
+
"type": "string",
|
|
196
|
+
"title": "Working folder",
|
|
197
|
+
"description": "Per-task working folder in the artifacts drawer. Defaults to this task's own folder so runs never collide; override with a stable name when you deliberately want runs to share files.",
|
|
198
|
+
"default": "{{task.dir}}"
|
|
199
|
+
}
|
|
200
|
+
}
|
|
201
|
+
},
|
|
202
|
+
"minGezelVersion": "1.26236"
|
|
203
|
+
}
|
|
@@ -0,0 +1,165 @@
|
|
|
1
|
+
{
|
|
2
|
+
"schemaVersion": 1,
|
|
3
|
+
"title": "Flagged Feature Rollout smoke eval",
|
|
4
|
+
"objective": "Self-contained smoke eval for the Flagged Feature Rollout craftbook using the external generic harness.",
|
|
5
|
+
"tags": [
|
|
6
|
+
"external"
|
|
7
|
+
],
|
|
8
|
+
"prompt": "Theres a fake ops service wired up for this so nothing real gets touched — the endpoints are in mocks/services.md, and the ready-made mock-probe script talks to them for you. Can you run the automation against it and write up how it went in automation.md?",
|
|
9
|
+
"setup": {
|
|
10
|
+
"projectName": "Flagged Feature Rollout Eval",
|
|
11
|
+
"about": "Self-contained eval project for feature-flag-rollout. Seeded inputs are under workspace/source or workspace/fixtures; final deliverable is workspace/automation.md.",
|
|
12
|
+
"missionObjectives": "Use the Flagged Feature Rollout craftbook/template, read the seeded local fixtures, and write automation.md without network calls, real credentials, or live services.",
|
|
13
|
+
"files": [
|
|
14
|
+
{
|
|
15
|
+
"path": "source/brief.md",
|
|
16
|
+
"content": "# Flagged Feature Rollout Eval Brief\n\nClient: Boreal Desk, a home-office accessories company.\nAudience: operations leads who need an artifact they can use this week.\n\nFixed source facts for grounding:\n- The returns desk pilot covered 18 SKUs.\n- Median first response improved from 18 hours to 6 hours.\n- Preventable refund leakage fell from 14.2% to 8.9%.\n- The top unresolved complaint is status silence after photo submission.\n- Required next actions are automated status emails, barcode-exception training, and a weekly Finance exception export.\n\nUse these facts when the task asks for prose, analysis, copy, UI content, or test data. Do not use live web services, real credentials, or current outside data.\n\nCraftbook under test: feature-flag-rollout - Flagged Feature Rollout.\n"
|
|
17
|
+
}
|
|
18
|
+
],
|
|
19
|
+
"worker": {
|
|
20
|
+
"name": "Jules",
|
|
21
|
+
"role": "Developer"
|
|
22
|
+
},
|
|
23
|
+
"craftbookParams": {
|
|
24
|
+
"workPath": "tasks/eval"
|
|
25
|
+
}
|
|
26
|
+
},
|
|
27
|
+
"mocks": [
|
|
28
|
+
{
|
|
29
|
+
"kind": "http",
|
|
30
|
+
"id": "ops",
|
|
31
|
+
"description": "Fake operations service for this eval. GET /api/bookings/open lists the open work items; POST /api/bookings/dry-run records a simulated submission and returns DRY_RUN_OK.",
|
|
32
|
+
"credential": {
|
|
33
|
+
"name": "mock.ops"
|
|
34
|
+
},
|
|
35
|
+
"routes": [
|
|
36
|
+
{
|
|
37
|
+
"method": "GET",
|
|
38
|
+
"path": "/api/bookings/open",
|
|
39
|
+
"body": {
|
|
40
|
+
"items": [
|
|
41
|
+
"BKG-1001",
|
|
42
|
+
"BKG-1002",
|
|
43
|
+
"BKG-1003"
|
|
44
|
+
]
|
|
45
|
+
}
|
|
46
|
+
},
|
|
47
|
+
{
|
|
48
|
+
"method": "POST",
|
|
49
|
+
"path": "/api/bookings/dry-run",
|
|
50
|
+
"status": 201,
|
|
51
|
+
"body": {
|
|
52
|
+
"status": "DRY_RUN_OK",
|
|
53
|
+
"recorded": 3
|
|
54
|
+
}
|
|
55
|
+
}
|
|
56
|
+
]
|
|
57
|
+
},
|
|
58
|
+
{
|
|
59
|
+
"kind": "webhook",
|
|
60
|
+
"id": "notify",
|
|
61
|
+
"description": "Notification receiver. POST a JSON completion notice here when the run finishes.",
|
|
62
|
+
"path": "/hooks/notify"
|
|
63
|
+
},
|
|
64
|
+
{
|
|
65
|
+
"kind": "cli",
|
|
66
|
+
"id": "probe",
|
|
67
|
+
"description": "Provenance-trusted project script `mock-probe` that exercises the fake ops service through http.authed and returns the raw responses.",
|
|
68
|
+
"shim": {
|
|
69
|
+
"path": "scripts/mock-probe.ts",
|
|
70
|
+
"content": "import { defineScript, gezel } from '@bendyline/gezel-sdk';\n\nexport const meta = defineScript({\n name: 'mock-probe',\n description:\n 'Probe the live fake ops service for this eval: lists the open work items and records a dry-run submission. Outputs the raw JSON responses as evidence for the write-up.',\n inputs: {},\n outputs: {\n open: { type: 'string', description: 'Raw JSON body from the open-items listing.' },\n dryRun: { type: 'string', description: 'Raw JSON body from the dry-run submission.' },\n },\n requires: ['workspace.read', 'network', 'credential:mock.ops'],\n});\n\nconst services = JSON.parse(await gezel.fs.read('mocks/services.json'));\nconst base = (id) => {\n const service = services.find((entry) => entry.id === id);\n if (!service) throw new Error(`mock service \"${id}\" is not listed in mocks/services.json`);\n return service.baseUrl;\n};\n\nconst open = await gezel.http.authed(`${base('ops')}/api/bookings/open`, {\n credential: 'mock.ops',\n});\nif (!open.ok) throw new Error(`open-items listing failed: ${open.status} ${open.body}`);\n\nconst dryRun = await gezel.http.authed(`${base('ops')}/api/bookings/dry-run`, {\n credential: 'mock.ops',\n method: 'POST',\n body: JSON.stringify({ items: JSON.parse(open.body).items, mode: 'dry-run' }),\n});\nif (!dryRun.ok) throw new Error(`dry-run submission failed: ${dryRun.status} ${dryRun.body}`);\n\ngezel.output({ open: open.body, dryRun: dryRun.body });\n"
|
|
71
|
+
}
|
|
72
|
+
}
|
|
73
|
+
],
|
|
74
|
+
"success": {
|
|
75
|
+
"summary": "automation.md is grounded in live fake-service responses: the open items were actually listed and a dry-run actually recorded (request-log assertions), with safety guards and signals described.",
|
|
76
|
+
"deliverables": [
|
|
77
|
+
{
|
|
78
|
+
"path": "automation.md",
|
|
79
|
+
"kind": "markdown-report",
|
|
80
|
+
"minBytes": 900,
|
|
81
|
+
"checks": [
|
|
82
|
+
{
|
|
83
|
+
"kind": "contains",
|
|
84
|
+
"file": "automation.md",
|
|
85
|
+
"pattern": "(?:^|\\n)#{1,3}\\s+\\S",
|
|
86
|
+
"flags": "i"
|
|
87
|
+
},
|
|
88
|
+
{
|
|
89
|
+
"kind": "contains",
|
|
90
|
+
"file": "automation.md",
|
|
91
|
+
"pattern": "DRY_RUN_OK|dry-run|dry run",
|
|
92
|
+
"flags": "i"
|
|
93
|
+
},
|
|
94
|
+
{
|
|
95
|
+
"kind": "contains",
|
|
96
|
+
"file": "automation.md",
|
|
97
|
+
"pattern": "fake-ci|fake-github|/api/bookings",
|
|
98
|
+
"flags": "i"
|
|
99
|
+
},
|
|
100
|
+
{
|
|
101
|
+
"kind": "contains",
|
|
102
|
+
"file": "automation.md",
|
|
103
|
+
"pattern": "no real|credentials|safety|guard",
|
|
104
|
+
"flags": "i"
|
|
105
|
+
},
|
|
106
|
+
{
|
|
107
|
+
"kind": "contains",
|
|
108
|
+
"file": "automation.md",
|
|
109
|
+
"pattern": "success|failure|retry|abort",
|
|
110
|
+
"flags": "i"
|
|
111
|
+
}
|
|
112
|
+
]
|
|
113
|
+
}
|
|
114
|
+
],
|
|
115
|
+
"mocks": [
|
|
116
|
+
{
|
|
117
|
+
"service": "ops",
|
|
118
|
+
"minRequests": 2,
|
|
119
|
+
"requiredPaths": [
|
|
120
|
+
"^/api/bookings/open$",
|
|
121
|
+
"^/api/bookings/dry-run$"
|
|
122
|
+
]
|
|
123
|
+
}
|
|
124
|
+
]
|
|
125
|
+
},
|
|
126
|
+
"rubric": {
|
|
127
|
+
"artifact": {
|
|
128
|
+
"path": "automation.md",
|
|
129
|
+
"kind": "markdown"
|
|
130
|
+
},
|
|
131
|
+
"axes": [
|
|
132
|
+
{
|
|
133
|
+
"name": "safety",
|
|
134
|
+
"description": "Dry-run posture is explicit: no real credentials, clear stop-before-side-effect boundary."
|
|
135
|
+
},
|
|
136
|
+
{
|
|
137
|
+
"name": "mapping",
|
|
138
|
+
"description": "Fake endpoints/commands are mapped completely to the workflow steps."
|
|
139
|
+
},
|
|
140
|
+
{
|
|
141
|
+
"name": "signals",
|
|
142
|
+
"description": "Success, failure, retry, and abort conditions are all defined."
|
|
143
|
+
},
|
|
144
|
+
{
|
|
145
|
+
"name": "containment",
|
|
146
|
+
"description": "The plan cannot accidentally reach a real service from a mock context."
|
|
147
|
+
}
|
|
148
|
+
]
|
|
149
|
+
},
|
|
150
|
+
"qualityFocus": [
|
|
151
|
+
"dry-run safety",
|
|
152
|
+
"fake tool mapping",
|
|
153
|
+
"side-effect containment"
|
|
154
|
+
],
|
|
155
|
+
"extensions": {
|
|
156
|
+
"legacySimulators": [
|
|
157
|
+
{
|
|
158
|
+
"id": "feature-flag-rollout-fake-service-fixture",
|
|
159
|
+
"kind": "data-source",
|
|
160
|
+
"status": "implemented",
|
|
161
|
+
"description": "Seeded local fake service contract replacing live CLIs, HTTP APIs, credentials, and side effects."
|
|
162
|
+
}
|
|
163
|
+
]
|
|
164
|
+
}
|
|
165
|
+
}
|
|
@@ -0,0 +1,12 @@
|
|
|
1
|
+
{
|
|
2
|
+
"schemaVersion": 1,
|
|
3
|
+
"promptVersion": "workshop-mark-1910-v2",
|
|
4
|
+
"periodCue": "circa-1910-subtle",
|
|
5
|
+
"family": "inspect-review",
|
|
6
|
+
"accents": [
|
|
7
|
+
"muted terracotta",
|
|
8
|
+
"sage"
|
|
9
|
+
],
|
|
10
|
+
"sourceSummary": "Statistically reproduce an intermittent test failure, remove the nondeterminism mechanism, and prove stability with consecutive green runs.",
|
|
11
|
+
"styleReference": "bug-fix-tdd"
|
|
12
|
+
}
|
|
Binary file
|