From dd84baead2bb16129b6a6df7ab342c39686fc4ad Mon Sep 17 00:00:00 2001 From: Alex J Lennon Date: Fri, 16 Oct 2026 00:00:25 +0100 Subject: [PATCH 1/2] Add a worked example and improve the reader paths Assisted-by: Briar --- AGENTS.md | 4 + README.md | 6 + content/blog.json | 4 +- content/capabilities.json | 6 +- docs/agents.html | 4 +- docs/app.js | 1 + docs/content/blog.json | 4 +- docs/content/capabilities.json | 6 +- docs/downloads.html | 93 +++++++++++++++ docs/examples/array-limit/LICENSE.txt | 49 ++++++++ docs/examples/array-limit/README.md | 67 +++++++++++ docs/examples/array-limit/attempt.cjs | 5 + docs/examples/array-limit/buggy.cjs | 4 + docs/examples/array-limit/fixed.cjs | 4 + docs/examples/array-limit/test.cjs | 31 +++++ docs/feedback.html | 84 +++++++++++++ docs/guides.css | 14 +++ docs/index.html | 15 +++ docs/llms.txt | 3 + ...wers-are-cheap-judgement-matters-more.html | 2 +- docs/packs/SHA256SUMS | 6 + docs/packs/codex-hour-starter-manifest.json | 37 ++++++ docs/packs/codex-hour-starter.zip | Bin 7799 -> 13412 bytes docs/packs/codex-hour/CHECKLIST.md | 2 + docs/packs/codex-hour/README.md | 12 +- docs/packs/cursor-hour-starter-manifest.json | 47 ++++++++ docs/packs/cursor-hour-starter.zip | Bin 9206 -> 14735 bytes docs/packs/cursor-hour/CHECKLIST.md | 2 + docs/packs/cursor-hour/README.md | 12 +- docs/packs/worked-example-manifest.json | 37 ++++++ docs/packs/worked-example.zip | Bin 0 -> 7289 bytes docs/sitemap.xml | 17 ++- docs/worked-example.html | 112 ++++++++++++++++++ examples/array-limit/LICENSE.txt | 49 ++++++++ examples/array-limit/README.md | 67 +++++++++++ examples/array-limit/attempt.cjs | 5 + examples/array-limit/buggy.cjs | 4 + examples/array-limit/fixed.cjs | 4 + examples/array-limit/test.cjs | 31 +++++ package.json | 3 +- packs/codex-hour/CHECKLIST.md | 2 + packs/codex-hour/README.md | 12 +- packs/cursor-hour/CHECKLIST.md | 2 + packs/cursor-hour/README.md | 12 +- scripts/build_downloads.py | 64 ++++++++++ scripts/render_notes.py | 8 +- scripts/sync-content.sh | 10 +- tests/test_downloads.py | 95 +++++++++++++++ tests/useful-next-steps.spec.js | 84 +++++++++++++ 49 files changed, 1114 insertions(+), 28 deletions(-) create mode 100644 docs/downloads.html create mode 100644 docs/examples/array-limit/LICENSE.txt create mode 100644 docs/examples/array-limit/README.md create mode 100644 docs/examples/array-limit/attempt.cjs create mode 100644 docs/examples/array-limit/buggy.cjs create mode 100644 docs/examples/array-limit/fixed.cjs create mode 100644 docs/examples/array-limit/test.cjs create mode 100644 docs/feedback.html create mode 100644 docs/guides.css create mode 100644 docs/packs/SHA256SUMS create mode 100644 docs/packs/codex-hour-starter-manifest.json create mode 100644 docs/packs/cursor-hour-starter-manifest.json create mode 100644 docs/packs/worked-example-manifest.json create mode 100644 docs/packs/worked-example.zip create mode 100644 docs/worked-example.html create mode 100644 examples/array-limit/LICENSE.txt create mode 100644 examples/array-limit/README.md create mode 100644 examples/array-limit/attempt.cjs create mode 100644 examples/array-limit/buggy.cjs create mode 100644 examples/array-limit/fixed.cjs create mode 100644 examples/array-limit/test.cjs create mode 100644 scripts/build_downloads.py create mode 100644 tests/test_downloads.py create mode 100644 tests/useful-next-steps.spec.js diff --git a/AGENTS.md b/AGENTS.md index 5af241c..5d7a8c3 100644 --- a/AGENTS.md +++ b/AGENTS.md @@ -25,6 +25,10 @@ This notebook is for humans **and** coding agents. Do not invent policy from the Done when one useful task has a checked result. No routine reflection record is required. +## Reproducible exercise and feedback + +Guidance reviewed 15th October 2026. Try the [worked exercise](https://chopwoodcarrywater.uk/worked-example.html) or run `examples/array-limit/test.cjs` as described in its README. [Verify downloads](https://chopwoodcarrywater.uk/downloads.html) with the public manifests/checksums. [Feedback](https://chopwoodcarrywater.uk/feedback.html) should include host/version, exact step, expected/actual and a reference, with private project details removed. + ## While you work - Prefer skills/rules/patterns on disk over chat folklore. diff --git a/README.md b/README.md index 4ccad3e..710680c 100644 --- a/README.md +++ b/README.md @@ -111,3 +111,9 @@ See [LICENSE](LICENSE) for the split. --- *AI-assisted (Codex) under Alex’s direction. Use at your own risk.* + +## Try one checked result + +Guidance reviewed 15th October 2026. [Run the evergreen worked example](https://chopwoodcarrywater.uk/worked-example.html), or use [the local offline guide](examples/array-limit/README.md). It deliberately shows a failed correction before a passing fix, with the same tests throughout. + +[Verify starter downloads and file manifests](https://chopwoodcarrywater.uk/downloads.html). [Share feedback](https://chopwoodcarrywater.uk/feedback.html) with host/version, exact step, expected/actual result and a reference; remove secrets and private project details first. diff --git a/content/blog.json b/content/blog.json index c45da0e..bacd834 100644 --- a/content/blog.json +++ b/content/blog.json @@ -532,8 +532,8 @@ "url": "https://penelope.uchicago.edu/Thayer/E/Roman/Texts/Quintilian/Institutio_Oratoria/home.html" }, { - "label": "Leiden University, Ancient Education", - "url": "https://studiegids-archive.leidenuniv.nl/en/courses/43807/tutorial-greek-ancient-education" + "label": "Leiden University, Ancient Education (2014–2015 course archive)", + "url": "https://studiegids-archief.leidenuniv.nl/courses/43807/tutorial-greek-ancient-education" }, { "label": "Cambridge University Press, Dialectic after Plato and Aristotle", diff --git a/content/capabilities.json b/content/capabilities.json index 33ce891..589cdbd 100644 --- a/content/capabilities.json +++ b/content/capabilities.json @@ -60,7 +60,8 @@ "band": "Team knowledge base", "evidence": { "url": "notes/the-token-bonfire.html", - "label": "Token Bonfire: failures and limits" + "label": "Token Bonfire: failures and limits", + "limit": "A reported failure and its lessons; no controlled comparison or general productivity result." } }, { @@ -71,7 +72,8 @@ "band": "Platform engineering", "evidence": { "url": "notes/the-cockpit-changed-the-work-did-not.html", - "label": "Host migration account" + "label": "Host migration account", + "limit": "One host migration account; host versions and permissions vary. It does not validate the other capability estimates." } }, { diff --git a/docs/agents.html b/docs/agents.html index 9c6114a..6534269 100644 --- a/docs/agents.html +++ b/docs/agents.html @@ -39,7 +39,7 @@ "description": "Short get-going path for coding agents: Codex-first pack, portable Agent Skill, fail-closed boundaries, signed pattern, and a 60-minute checklist.", "isPartOf": { "@id": "https://chopwoodcarrywater.uk/#website" }, "about": ["Codex", "Agent Skills", "AI coding agents"], - "dateModified": "2026-09-12", + "dateModified": "2026-10-15", "inLanguage": "en-GB" } @@ -78,6 +78,7 @@

For coding agents

Get going

+

Guidance reviewed .

Before enlightenment: chop wood, carry water.

Do not invent policy from the blog. Install a thin working relationship, @@ -90,6 +91,7 @@

Get going

Open the 60-minute path

+

Run a complete small exercise · Verify pack checksums and file manifests · Tell us where you got stuck

Six steps

  1. diff --git a/docs/app.js b/docs/app.js index 9305680..589b354 100644 --- a/docs/app.js +++ b/docs/app.js @@ -416,6 +416,7 @@ function renderCapabilities(data) { el("span", {}, [ row.note, row.evidence ? el("a", { className: "text-link", href: row.evidence.url, text: row.evidence.label }) : null, + row.evidence?.limit ? el("p", { className: "fineprint", text: row.evidence.limit }) : null, row.band ? el("div", { className: "band", text: row.band }) : null, ]), ]), diff --git a/docs/content/blog.json b/docs/content/blog.json index c45da0e..bacd834 100644 --- a/docs/content/blog.json +++ b/docs/content/blog.json @@ -532,8 +532,8 @@ "url": "https://penelope.uchicago.edu/Thayer/E/Roman/Texts/Quintilian/Institutio_Oratoria/home.html" }, { - "label": "Leiden University, Ancient Education", - "url": "https://studiegids-archive.leidenuniv.nl/en/courses/43807/tutorial-greek-ancient-education" + "label": "Leiden University, Ancient Education (2014–2015 course archive)", + "url": "https://studiegids-archief.leidenuniv.nl/courses/43807/tutorial-greek-ancient-education" }, { "label": "Cambridge University Press, Dialectic after Plato and Aristotle", diff --git a/docs/content/capabilities.json b/docs/content/capabilities.json index 33ce891..589cdbd 100644 --- a/docs/content/capabilities.json +++ b/docs/content/capabilities.json @@ -60,7 +60,8 @@ "band": "Team knowledge base", "evidence": { "url": "notes/the-token-bonfire.html", - "label": "Token Bonfire: failures and limits" + "label": "Token Bonfire: failures and limits", + "limit": "A reported failure and its lessons; no controlled comparison or general productivity result." } }, { @@ -71,7 +72,8 @@ "band": "Platform engineering", "evidence": { "url": "notes/the-cockpit-changed-the-work-did-not.html", - "label": "Host migration account" + "label": "Host migration account", + "limit": "One host migration account; host versions and permissions vary. It does not validate the other capability estimates." } }, { diff --git a/docs/downloads.html b/docs/downloads.html new file mode 100644 index 0000000..a68a9e3 --- /dev/null +++ b/docs/downloads.html @@ -0,0 +1,93 @@ + + + + + + Check your starter download · Chop Wood Carry Water + + + + + + + + + + + + + + + + +
    + + + + Chop Wood Carry Water + Durable Agent Harness + + + +
    + + + + +
    +
    + +

    Guide

    +

    Check your starter download

    + +
    +
    +

    Each ZIP is built from the source files with a fixed file order, timestamp and permissions. The adjacent manifest lists every file’s relative path, byte size and SHA-256. ZIPs include hidden guidance folders.

    + +

    Verify a download

    +

    Save SHA256SUMS, the ZIP and its manifest in the same directory. For the Codex pack on Linux, compare these locally computed hashes with the two matching lines in SHA256SUMS:

    +
    sha256sum codex-hour-starter.zip codex-hour-starter-manifest.json
    +

    On macOS use shasum -a 256 in place of sha256sum. On Windows PowerShell use:

    +
    Get-FileHash .\codex-hour-starter.zip -Algorithm SHA256
    +Get-FileHash .\codex-hour-starter-manifest.json -Algorithm SHA256
    +

    Use the corresponding names for Cursor or the exercise. If either hash differs, stop and download again from the intended source. These hashes check that files agree with the published checksum list. They are not signatures: a compromised download source could replace the ZIP, manifest and list together.

    +

    Check individual files

    +

    After extraction, paths in the manifest are relative to the folder named by its root field, such as codex-hour/. Hash any file you want to check and compare its size and SHA-256 with that entry. Include hidden folders when comparing the complete file list; an extra or missing file means it is not the same package.

    +

    Rebuild from the repository

    +

    From a repository checkout with Python 3, run the standard-library builder. It needs no npm package, external service or credentials.

    +
    python3 scripts/build_downloads.py
    +

    The output goes to docs/packs/. ZIP entries use 1st January 1980, regular-file mode 0644, sorted paths and no compression. Source modification times, permissions and creation order do not affect the bytes. Manifests sit outside the ZIP; SHA256SUMS covers ZIPs and manifests and never hashes itself. No generated timestamp or build counter is added.

    +

    npm test runs the normal sync and verifies source/browse/archive parity, manifest hashes, extracted execution and reproducibility after changing source times, modes and creation order. Checksums describe the files in this candidate, not the date of a historical site snapshot.

    +

    Run the worked example · First-hour setup · Report a download problem

    +

    (Briar helped draft this)

    +
    +
    +
    + +
    + + diff --git a/docs/examples/array-limit/LICENSE.txt b/docs/examples/array-limit/LICENSE.txt new file mode 100644 index 0000000..720ee65 --- /dev/null +++ b/docs/examples/array-limit/LICENSE.txt @@ -0,0 +1,49 @@ +# Licensing + +This repository uses two licences. + +## Site content (notebook) + +The public notebook content — including files under `content/`, `docs/` pages +and assets that present that notebook, `blog-inbox.md`, `AGENTS.md`, +`BASELINE.md`, and the Cursor hour pack’s prose — is licensed under + +**Creative Commons Attribution-ShareAlike 4.0 International (CC BY-SA 4.0)** + +https://creativecommons.org/licenses/by-sa/4.0/ + +Copyright © 2026 Alex Lennon (Chop Wood Carry Water). + +You are free to share and adapt the material for any purpose, even commercially, +provided you give appropriate credit, indicate if changes were made, and +distribute your contributions under the same licence. + +## Code (site machinery) + +Build/test scripts, Playwright tests, and the small amount of site JavaScript / +CSS plumbing are licensed under the **MIT License** — see [LICENSE-MIT.txt](LICENSE-MIT.txt). + +Copyright © 2026 Dynamic Devices Ltd / Alex Lennon. + + +MIT License + +Copyright (c) 2026 Dynamic Devices Ltd / Alex Lennon + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in all +copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +SOFTWARE. diff --git a/docs/examples/array-limit/README.md b/docs/examples/array-limit/README.md new file mode 100644 index 0000000..298d559 --- /dev/null +++ b/docs/examples/array-limit/README.md @@ -0,0 +1,67 @@ +# When zero is a valid limit + +Evergreen exercise. Reviewed 15th October 2026 (Node 24.21.0). + +This deliberately small exercise was run for the guide. It is not a historical +project incident or a measurement of an assistant's performance. + +## Reproduce it + +You need Node.js 24; there are no npm dependencies, accounts or network calls. +After unzipping worked-example.zip, open a terminal in worked-example/. +For a repository clone use examples/array-limit/ instead. + +```sh +node --version +node --test-reporter=tap test.cjs buggy +node --test-reporter=tap test.cjs attempt +node --test-reporter=tap test.cjs fixed +``` + +Run the three stage commands separately. The first two intentionally return exit 1; +this is expected, so do not join them with &&. The fixed stage returns exit 0. + +## The problem + +`take(items, limit)` returns a new array. Omitted or null limits default to three. +Zero means no items; a positive integer caps the result. In buggy.cjs, `limit || 3` +replaces zero with three. The zero test expects [] but receives oak, ash and elm. + +The attempted correction in attempt.cjs moves the default to a variable using +`limit ? limit : 3`. That still treats zero as false. The same test still fails. +In fixed.cjs, `limit ?? 3` defaults only for null or undefined, preserving zero. +All three implementations and the identical six tests are in this folder. + +Actual guide run on Node 24.21.0, 15th October 2026: + +| Stage | Tests | Pass | Fail | Exit | +| --- | ---: | ---: | ---: | ---: | +| buggy | 6 | 5 | 1 | 1 | +| attempt | 6 | 5 | 1 | 1 | +| fixed | 6 | 6 | 0 | 0 | + +The other checks cover omitted/null defaults, positive/large limits, empty input, +and preserving the input. Invalid limits such as strings, negative numbers and +fractions are outside this contract; real APIs need an explicit validation policy. +This does not test model behaviour, host permissions, production integration, +performance or security. + +## Try it with an assistant + +Ask: "Read test.cjs and buggy.cjs. Explain why zero fails, cite the relevant +lines and suggest a focused check. Do not edit files." Check the answer yourself. +Then, if you want to practise editing, explicitly ask for a local correction and +rerun the tests. A plausible explanation or rewrite is not passing evidence. +You can complete the exercise by hand; an assistant is optional. + +## Continue (online) + +- Readable guide: https://chopwoodcarrywater.uk/worked-example.html +- Setup: https://chopwoodcarrywater.uk/#hour +- Download checksums and manifests: https://chopwoodcarrywater.uk/downloads.html +- Feedback: https://chopwoodcarrywater.uk/feedback.html + +If a step fails, include host/version, exact step, expected/actual result and a +link or file reference. Remove secrets and private project details first. + +Content CC BY-SA 4.0; code MIT (see LICENSE.txt). (Briar helped draft this) diff --git a/docs/examples/array-limit/attempt.cjs b/docs/examples/array-limit/attempt.cjs new file mode 100644 index 0000000..bb98057 --- /dev/null +++ b/docs/examples/array-limit/attempt.cjs @@ -0,0 +1,5 @@ +// Attempt: move the default into a variable. Zero is still treated as false. +module.exports = function take(items, limit) { + const count = limit ? limit : 3; + return items.slice(0, count); +}; diff --git a/docs/examples/array-limit/buggy.cjs b/docs/examples/array-limit/buggy.cjs new file mode 100644 index 0000000..ee16b97 --- /dev/null +++ b/docs/examples/array-limit/buggy.cjs @@ -0,0 +1,4 @@ +// Contract: null/undefined use 3; zero returns no items; positive integers cap results. +module.exports = function take(items, limit) { + return items.slice(0, limit || 3); +}; diff --git a/docs/examples/array-limit/fixed.cjs b/docs/examples/array-limit/fixed.cjs new file mode 100644 index 0000000..617ba40 --- /dev/null +++ b/docs/examples/array-limit/fixed.cjs @@ -0,0 +1,4 @@ +module.exports = function take(items, limit) { + const count = limit ?? 3; + return items.slice(0, count); +}; diff --git a/docs/examples/array-limit/test.cjs b/docs/examples/array-limit/test.cjs new file mode 100644 index 0000000..244c54a --- /dev/null +++ b/docs/examples/array-limit/test.cjs @@ -0,0 +1,31 @@ +const { test } = require('node:test'); +const assert = require('node:assert/strict'); +const stage = process.argv[2] || 'fixed'; +if (!['buggy', 'attempt', 'fixed'].includes(stage)) { + throw new Error('Use: node test.cjs buggy|attempt|fixed'); +} +const take = require(`./${stage}.cjs`); +const items = ['oak', 'ash', 'elm', 'beech']; + +test('omitted limit uses the default of three', () => { + assert.deepEqual(take(items), ['oak', 'ash', 'elm']); +}); +test('null limit uses the default of three', () => { + assert.deepEqual(take(items, null), ['oak', 'ash', 'elm']); +}); +test('zero requests no items', () => { + assert.deepEqual(take(items, 0), []); +}); +test('positive limit returns that many items', () => { + assert.deepEqual(take(items, 2), ['oak', 'ash']); +}); +test('large limit and empty input are safe', () => { + assert.deepEqual(take(items, 20), items); + assert.deepEqual(take([], 2), []); +}); +test('input remains unchanged and the result is a new array', () => { + const input = Object.freeze(['oak', 'ash', 'elm', 'beech']); + assert.deepEqual(take(input, 2), ['oak', 'ash']); + assert.deepEqual(input, items); + assert.notEqual(take(input, 20), input); +}); diff --git a/docs/feedback.html b/docs/feedback.html new file mode 100644 index 0000000..8ba4ed0 --- /dev/null +++ b/docs/feedback.html @@ -0,0 +1,84 @@ + + + + + + Help improve a guide · Chop Wood Carry Water + + + + + + + + + + + + + + + + +
    + + + + Chop Wood Carry Water + Durable Agent Harness + + + +
    + + + + +
    +
    + +

    Guide

    +

    Help improve a guide

    + +
    +
    +

    If a guide leaves you stuck, a short account of the step you tried helps us improve it. Suggestions and corrections are welcome too.

    +

    Use the existing repository issue route if you already use GitHub. You can also use Alex’s public @embedded_iot profile, linked from this notebook. There is no need to create an account for this guide; use a route you already have access to.

    +

    What helps

    +

    Copy the outline below into your message and fill in what you know. You do not need to include a project archive or complete transcript.

    +
    Host and version (Codex/Cursor, OS, Node if relevant):
    +Exact step or command:
    +Expected result:
    +Actual result (short error extract if useful):
    +Guide URL and heading, or file/line reference:
    +Pack/version reference (ZIP checksum or repository commit, if known):
    +

    Leave out secrets and private project or customer details. A small made-up example is often enough to reproduce a problem. GitHub issues are public; use the outline in whichever contact route you choose. Missing version details are fine.

    +

    Back to the exercise · Download checks · First-hour setup

    +

    (Briar helped draft this)

    +
    +
    +
    + +
    + + diff --git a/docs/guides.css b/docs/guides.css new file mode 100644 index 0000000..6aa5119 --- /dev/null +++ b/docs/guides.css @@ -0,0 +1,14 @@ +/* Evergreen guides reuse the notebook shell, typography and colour tokens. */ +.guide-code { + max-width: 100%; + overflow: auto; + padding: 1rem; + border: 1px solid var(--line); + border-radius: var(--radius); + background: var(--card); + font-size: .85em; + line-height: 1.6; +} +.guide-code:focus-visible { outline: 3px solid var(--water); outline-offset: 3px; } +.note-body table { width: 100%; border-collapse: collapse; margin: 1.5rem 0; } +.note-body th, .note-body td { text-align: left; padding: .5rem; border-bottom: 1px solid var(--line); } diff --git a/docs/index.html b/docs/index.html index fc977d4..145ace3 100644 --- a/docs/index.html +++ b/docs/index.html @@ -271,13 +271,28 @@

    Durable Agent Harness

+
+ +
+

Start in 60 minutes

+

Guidance reviewed ; historical snapshot dates below are unchanged.

+

Try the runnable exercise · Verify downloads and browse file manifests · Feedback on a step

    diff --git a/docs/llms.txt b/docs/llms.txt index 3b68538..ed2b9df 100644 --- a/docs/llms.txt +++ b/docs/llms.txt @@ -5,6 +5,9 @@ ## Main pages - [Notebook](https://chopwoodcarrywater.uk/) - [Agents: start here](https://chopwoodcarrywater.uk/agents.html) +- [Worked exercise](https://chopwoodcarrywater.uk/worked-example.html) +- [Download verification](https://chopwoodcarrywater.uk/downloads.html) +- [Feedback](https://chopwoodcarrywater.uk/feedback.html) - [RSS feed](https://chopwoodcarrywater.uk/feed.xml) ## Insights diff --git a/docs/notes/when-answers-are-cheap-judgement-matters-more.html b/docs/notes/when-answers-are-cheap-judgement-matters-more.html index 9caf3ec..4c05051 100644 --- a/docs/notes/when-answers-are-cheap-judgement-matters-more.html +++ b/docs/notes/when-answers-are-cheap-judgement-matters-more.html @@ -140,7 +140,7 @@

    When answers are cheap, judgement matters more

    Sources and further reading

    diff --git a/docs/packs/SHA256SUMS b/docs/packs/SHA256SUMS new file mode 100644 index 0000000..0766600 --- /dev/null +++ b/docs/packs/SHA256SUMS @@ -0,0 +1,6 @@ +28399450ab75c3d0f522ce7e52a620743604bf5674d30d85b363ce0666f6238f codex-hour-starter-manifest.json +18d81c5b151fb46135740771ab0cf04fc8e33b12ddc2aeb39db4a08e93f9badf codex-hour-starter.zip +f4193d2437bbd67e50743da170cc92e476b5a9f10d738487eaede2f829eaea6e cursor-hour-starter-manifest.json +89c7900ffd6168526ad47fe5666ac39c2fc3855f4973d6839be18dfe9fb708cd cursor-hour-starter.zip +c38d8ed15110766dc30515e071f77d8eabaa0c1cf436d379c38b519479ca7901 worked-example-manifest.json +448697b1200f187a7420b53338688ac8a41521eceadc5a10544f99d1ec2ab5dd worked-example.zip diff --git a/docs/packs/codex-hour-starter-manifest.json b/docs/packs/codex-hour-starter-manifest.json new file mode 100644 index 0000000..a12b6b6 --- /dev/null +++ b/docs/packs/codex-hour-starter-manifest.json @@ -0,0 +1,37 @@ +{ + "schema": "cwcw/download-manifest/v1", + "archive": "codex-hour-starter.zip", + "root": "codex-hour", + "files": [ + { + "path": ".agents/skills/example-domain-task/SKILL.md", + "bytes": 1051, + "sha256": "2eb885769f820263ded8d459b47b84130166d33d30c94234bb5a23594669161b" + }, + { + "path": "AGENTS.md", + "bytes": 2090, + "sha256": "8294201cd006fb8a676c7f16c114d91b0b5430ec02afa761ccc624bf020d9145" + }, + { + "path": "CHECKLIST.md", + "bytes": 3577, + "sha256": "3d95e56fec3cea7155dc51354908122087d0754618e91b6fe17c7405f97c99eb" + }, + { + "path": "README.md", + "bytes": 3621, + "sha256": "74ea0e1da43991c16b6418900ea9b1b960acd1725d1dab09fb23a85f8d77a13f" + }, + { + "path": "clocks.json", + "bytes": 385, + "sha256": "2785c238f93ce8236a13ac0f020cb0f18b5d28c4bc7554946909c1b1754c338a" + }, + { + "path": "patterns/WORKING-PATTERNS.md", + "bytes": 1854, + "sha256": "37851836bd711125ac23d42b1d5519825923bf5c0ecf83ff12fbc208894edd37" + } + ] +} diff --git a/docs/packs/codex-hour-starter.zip b/docs/packs/codex-hour-starter.zip index 695934d55ba1be299176e17cc036cb8de08bc931..da5ff2e12e42ee7c044e293ea919c57a9372f026 100644 GIT binary patch literal 13412 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 literal 7799 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 qC;xi__$wLaaan)aUQg4(NBD1#Ak5 ## Install in a project you control -1. Compare `AGENTS.md and .agents/` with existing files. Merge instructions and skill folders; never overwrite existing project guidance. Resolve conflicting instructions with the human. +1. Compare `AGENTS.md` and `.agents/` with existing files. Merge instructions and skill folders; never overwrite existing project guidance. Resolve conflicting instructions with the human. 2. Keep secrets out of chat and require a human decision for consequential actions. Check the host’s sandbox and permission settings separately. 3. Start a new task in the project. Ask which guidance files it can read; check that `.agents/skills/example-domain-task/SKILL.md` is discoverable. Loading can vary with host version and settings; do not assume a running task reloaded changed files. 4. Follow `CHECKLIST.md`: do useful work early, then adapt a skill only if the job recurs. Copy pattern and clock files only when needed, merging any existing records. ## What this pack provides -`AGENTS.md and .agents/` contains written guidance and an example skill. It does not install an interceptor, authority verifier or runtime security system. AGENTS.md guides Codex; it does not replace sandboxing or permissions. Test the controls your host actually provides. Stop a consequential action when required approval is missing or cannot be verified. +`AGENTS.md` and `.agents/` contain written guidance and an example skill. It does not install an interceptor, authority verifier or runtime security system. AGENTS.md guides Codex; it does not replace sandboxing or permissions. Test the controls your host actually provides. Stop a consequential action when required approval is missing or cannot be verified. `patterns/WORKING-PATTERNS.md` contains editorial examples, not action permissions. `clocks.json` contains optional historical start dates; the checklist explains the host-specific fields. Leave unknown dates unset. @@ -28,4 +30,10 @@ Model access depends on host configuration. A gateway for an external review doe - Humans decide consequential actions. An agent may execute an authorised action within its exact scope after required checks; a signed-off pattern or passing review is not authority. - Diagnose failures before adding process. A smaller task, clearer existing instructions, removal of conflicts or a runtime restriction may solve the problem. No routine reflection note or new rule is required. +## Exercise, download checks and feedback + +- [Run the complete worked exercise](https://chopwoodcarrywater.uk/worked-example.html): a deliberately small failing test, unsuccessful correction and passing fix. Its ZIP includes source and an offline guide; no model or npm dependency is needed. +- [Verify this ZIP and inspect the file manifest](https://chopwoodcarrywater.uk/downloads.html#verify). Checksums detect changed bytes; they are not signatures or proof of a safe host. +- [Tell us which step needs improving](https://chopwoodcarrywater.uk/feedback.html) through the existing public repo/contact route. Include host/version, exact step, expected/actual result and a link or file reference. Remove private project details and secrets first. + (Briar helped draft this) diff --git a/docs/packs/cursor-hour-starter-manifest.json b/docs/packs/cursor-hour-starter-manifest.json new file mode 100644 index 0000000..c1f92a8 --- /dev/null +++ b/docs/packs/cursor-hour-starter-manifest.json @@ -0,0 +1,47 @@ +{ + "schema": "cwcw/download-manifest/v1", + "archive": "cursor-hour-starter.zip", + "root": "cursor-hour", + "files": [ + { + "path": ".cursor/rules/p0-human-gate-irreversible.mdc", + "bytes": 1251, + "sha256": "9048328ca80fcafd8bb0b94160b19fa75d1bc9cf3c2d65b70d14d9ac59efec1a" + }, + { + "path": ".cursor/rules/p0-no-secrets-in-chat.mdc", + "bytes": 996, + "sha256": "5b4325309d1e187803eb8e929e77854f1115ecae0f16643d59c7a5ba88dde437" + }, + { + "path": ".cursor/rules/working-agreements.mdc", + "bytes": 1234, + "sha256": "c80571f7aca8dd8b505f78dcc8762e88f9630cf0aeddf9fc78285e2eb4b6d24a" + }, + { + "path": ".cursor/skills/example-domain-task/SKILL.md", + "bytes": 1029, + "sha256": "4a4a8a2bd9b8ac0e11a80d2bf74538526a6129b136d68ad7cdc97fed66d6c0b7" + }, + { + "path": "CHECKLIST.md", + "bytes": 3578, + "sha256": "a66919fb12621dd4d7cc22422da08a95b812d21eb309c8409c53c134accd5082" + }, + { + "path": "README.md", + "bytes": 3691, + "sha256": "8655f459f1d99c218338d665d07ab9dba961d8f10f19e3a079121659d9bc31ed" + }, + { + "path": "clocks.json", + "bytes": 233, + "sha256": "1ed33fb8408281d096a164540c19b3dd1793d01c191f2c1f6b880928420852cf" + }, + { + "path": "patterns/WORKING-PATTERNS.md", + "bytes": 1457, + "sha256": "1358a39d6871c5747f7d920465184bfe433cfc65e72befadf8b9995710c9ffa0" + } + ] +} diff --git a/docs/packs/cursor-hour-starter.zip b/docs/packs/cursor-hour-starter.zip index f3e348837cd3f00ca7120718b6fb1d1a6275f5e4..ddadf9e9becd3d229234df7c066d2fe297983635 100644 GIT binary patch literal 14735 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 diff --git a/docs/packs/cursor-hour/CHECKLIST.md b/docs/packs/cursor-hour/CHECKLIST.md index 53febbe..1fc819e 100644 --- a/docs/packs/cursor-hour/CHECKLIST.md +++ b/docs/packs/cursor-hour/CHECKLIST.md @@ -2,6 +2,8 @@ Start with a small piece of work in a project you control. Use Codex or Cursor; the packs share the same boundaries but use different project paths. +Guidance reviewed 15th October 2026. Need a self-contained task? The [worked exercise](https://chopwoodcarrywater.uk/worked-example.html) includes an offline guide and runnable source. [Download verification](https://chopwoodcarrywater.uk/downloads.html) and [feedback](https://chopwoodcarrywater.uk/feedback.html) use the same public routes. For feedback include host/version, step, expected/actual and a reference; remove private details. + ## 5 min - Choose a small task and your host Download the Codex or Cursor pack. Start with a read-only job: explain one failing test, naming the file, likely cause and one way to check it. diff --git a/docs/packs/cursor-hour/README.md b/docs/packs/cursor-hour/README.md index 534825d..47072fc 100644 --- a/docs/packs/cursor-hour/README.md +++ b/docs/packs/cursor-hour/README.md @@ -2,18 +2,20 @@ Complete one small, checked task before keeping extra process. +Guidance reviewed 15th October 2026; optional clocks keep their own historical dates. + Site: ## Install in a project you control -1. Compare `.cursor/rules/ and .cursor/skills/` with existing files. Merge instructions and skill folders; never overwrite existing project guidance. Resolve conflicting instructions with the human. +1. Compare `.cursor/rules/` and `.cursor/skills/` with existing files. Merge instructions and skill folders; never overwrite existing project guidance. Resolve conflicting instructions with the human. 2. Keep secrets out of chat and require a human decision for consequential actions. Check the host’s sandbox and permission settings separately. 3. Start a new task in the project. Ask which guidance files it can read; check that `.cursor/skills/example-domain-task/SKILL.md` is discoverable. Loading can vary with host version and settings; do not assume a running task reloaded changed files. 4. Follow `CHECKLIST.md`: do useful work early, then adapt a skill only if the job recurs. Copy pattern and clock files only when needed, merging any existing records. ## What this pack provides -`.cursor/rules/ and .cursor/skills/` contains written guidance and an example skill. It does not install an interceptor, authority verifier or runtime security system. Cursor’s alwaysApply metadata requests rule loading; it does not guarantee compliance or fail-closed enforcement. Test the controls your host actually provides. Stop a consequential action when required approval is missing or cannot be verified. +`.cursor/rules/` and `.cursor/skills/` contain written guidance and an example skill. It does not install an interceptor, authority verifier or runtime security system. Cursor’s alwaysApply metadata requests rule loading; it does not guarantee compliance or fail-closed enforcement. Test the controls your host actually provides. Stop a consequential action when required approval is missing or cannot be verified. `patterns/WORKING-PATTERNS.md` contains editorial examples, not action permissions. `clocks.json` contains optional historical start dates; the checklist explains the host-specific fields. Leave unknown dates unset. @@ -28,4 +30,10 @@ Model access depends on host configuration. A gateway for an external review doe - Humans decide consequential actions. An agent may execute an authorised action within its exact scope after required checks; a signed-off pattern or passing review is not authority. - Diagnose failures before adding process. A smaller task, clearer existing instructions, removal of conflicts or a runtime restriction may solve the problem. No routine reflection note or new rule is required. +## Exercise, download checks and feedback + +- [Run the complete worked exercise](https://chopwoodcarrywater.uk/worked-example.html): a deliberately small failing test, unsuccessful correction and passing fix. Its ZIP includes source and an offline guide; no model or npm dependency is needed. +- [Verify this ZIP and inspect the file manifest](https://chopwoodcarrywater.uk/downloads.html#verify). Checksums detect changed bytes; they are not signatures or proof of a safe host. +- [Tell us which step needs improving](https://chopwoodcarrywater.uk/feedback.html) through the existing public repo/contact route. Include host/version, exact step, expected/actual result and a link or file reference. Remove private project details and secrets first. + (Briar helped draft this) diff --git a/docs/packs/worked-example-manifest.json b/docs/packs/worked-example-manifest.json new file mode 100644 index 0000000..530b4cf --- /dev/null +++ b/docs/packs/worked-example-manifest.json @@ -0,0 +1,37 @@ +{ + "schema": "cwcw/download-manifest/v1", + "archive": "worked-example.zip", + "root": "worked-example", + "files": [ + { + "path": "LICENSE.txt", + "bytes": 2039, + "sha256": "3e8a9fdbbe7af384798e42018c6b82dd70dc7dba1633e6bae1ee8619f1eca371" + }, + { + "path": "README.md", + "bytes": 2833, + "sha256": "2fd77641b5f25245559dfbe237d791414261c9a244a8c9feebb179b09f761928" + }, + { + "path": "attempt.cjs", + "bytes": 195, + "sha256": "47bd56c78c7235a0f534c560a8f6c513eb93c88e0de133f34b402be4b701250c" + }, + { + "path": "buggy.cjs", + "bytes": 176, + "sha256": "c59dfca3dba7306b4e608e567972be956083611f9a971be3ece208ee1faad40b" + }, + { + "path": "fixed.cjs", + "bytes": 110, + "sha256": "1cfcf1ce25beb16a99ccc169f3daf7f652518cb9b3191f6392821d38bff9f5b4" + }, + { + "path": "test.cjs", + "bytes": 1164, + "sha256": "7766fab424b8d9dc33f2bbe7585030f2a7e1f5f04db27a76b39ae6976a64870f" + } + ] +} diff --git a/docs/packs/worked-example.zip b/docs/packs/worked-example.zip new file mode 100644 index 0000000000000000000000000000000000000000..0cb266eb3b5ac288c44d0df34c441a96173712cd GIT binary patch literal 7289 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 https://chopwoodcarrywater.uk/agents.html - 2026-09-05 + 2026-10-15 + 0.8 + + + https://chopwoodcarrywater.uk/worked-example.html + 2026-10-15 0.8 + + https://chopwoodcarrywater.uk/downloads.html + 2026-10-15 + 0.7 + + + https://chopwoodcarrywater.uk/feedback.html + 2026-10-15 + 0.6 + https://chopwoodcarrywater.uk/notes/the-token-bonfire.html 2026-10-15 diff --git a/docs/worked-example.html b/docs/worked-example.html new file mode 100644 index 0000000..f247cd0 --- /dev/null +++ b/docs/worked-example.html @@ -0,0 +1,112 @@ + + + + + + When zero is a valid limit · Chop Wood Carry Water + + + + + + + + + + + + + + + + +
    + + + + Chop Wood Carry Water + Durable Agent Harness + + + +
    + + + + +
    +
    + +

    Guide

    +

    When zero is a valid limit

    + +
    +
    +

    A default can hide a valid value. Here, a caller asks for zero items and gets three. Run the failing test, try a correction that still fails, then check the fix against the same tests.

    +

    This is a deliberately small exercise run for this guide, not a historical project incident. You can reproduce it by hand or use it to practise checking an assistant’s diagnosis.

    +

    Get the exercise

    +

    You need Node.js 24 and a terminal. No dependencies to install, service, account or paid model is needed.

    +

    Download the exercise ZIP · Browse the offline guide · Verify the download

    +

    Unzip it into a new folder, then open a terminal in worked-example/. If you already have the repository, use examples/array-limit/.

    +
    node --version
    +node --test-reporter=tap test.cjs buggy
    +node --test-reporter=tap test.cjs attempt
    +node --test-reporter=tap test.cjs fixed
    +

    Run each stage separately. The first two commands deliberately exit with code 1. Do not chain them with &&, which would stop at the first failure. The fixed stage should exit with code 0.

    +

    1. Make the failure visible

    +

    The contract is small: an omitted or null limit means three; zero means none; a positive integer caps the result. The function returns a new array.

    +
    // Contract: null/undefined use 3; zero returns no items; positive integers cap results.
    +module.exports = function take(items, limit) {
    +  return items.slice(0, limit || 3);
    +};
    +

    The same six tests run against every stage. With ["oak", "ash", "elm", "beech"] and a limit of zero, the test expects [] but the original returns ["oak", "ash", "elm"]. || treats zero as false and selects the default.

    +

    2. Check the attempted correction

    +
    // Attempt: move the default into a variable. Zero is still treated as false.
    +module.exports = function take(items, limit) {
    +  const count = limit ? limit : 3;
    +  return items.slice(0, count);
    +};
    +

    Moving the default into a variable looks plausible. The condition still treats zero as false, so the zero test still fails. A changed implementation is not enough to show that the problem is fixed.

    +

    3. Preserve zero and verify

    +
    module.exports = function take(items, limit) {
    +  const count = limit ?? 3;
    +  return items.slice(0, count);
    +};
    +

    ?? selects the default only for null or undefined. Zero reaches slice unchanged. The other tests check the defaults, positive and large limits, empty input and that the input stays unchanged.

    +

    Actual run

    +

    Run for this guide on 15th October 2026 with Node 24.21.0. These are the test counts and exit codes from that run; timings and stack paths depend on your machine.

    +
    Same six tests for all three stages
    StagePassFailExit
    buggy511
    attempt511
    fixed600
    +

    What this proves

    +

    You can reproduce a specific failure, see why an attempted correction leaves it in place, and verify a fix against a stated contract. The six tests cover this function. A real API also needs a policy for invalid limits, such as negative numbers, fractions or strings, and checks in the project where it will run.

    +

    Try the diagnosis with your host

    +

    Ask: “Read test.cjs and buggy.cjs. Explain why zero fails, cite the relevant lines and suggest a focused check. Do not edit files.” Check the answer against the source. If you then want to practise editing, explicitly ask for a local correction and rerun the tests.

    +

    Try the first-hour setup · Agents: get going · Read the engineering stories

    +

    If a step does not work, tell us which step and what happened.

    +

    (Briar helped draft this)

    +
    +
    +
    + +
    + + diff --git a/examples/array-limit/LICENSE.txt b/examples/array-limit/LICENSE.txt new file mode 100644 index 0000000..720ee65 --- /dev/null +++ b/examples/array-limit/LICENSE.txt @@ -0,0 +1,49 @@ +# Licensing + +This repository uses two licences. + +## Site content (notebook) + +The public notebook content — including files under `content/`, `docs/` pages +and assets that present that notebook, `blog-inbox.md`, `AGENTS.md`, +`BASELINE.md`, and the Cursor hour pack’s prose — is licensed under + +**Creative Commons Attribution-ShareAlike 4.0 International (CC BY-SA 4.0)** + +https://creativecommons.org/licenses/by-sa/4.0/ + +Copyright © 2026 Alex Lennon (Chop Wood Carry Water). + +You are free to share and adapt the material for any purpose, even commercially, +provided you give appropriate credit, indicate if changes were made, and +distribute your contributions under the same licence. + +## Code (site machinery) + +Build/test scripts, Playwright tests, and the small amount of site JavaScript / +CSS plumbing are licensed under the **MIT License** — see [LICENSE-MIT.txt](LICENSE-MIT.txt). + +Copyright © 2026 Dynamic Devices Ltd / Alex Lennon. + + +MIT License + +Copyright (c) 2026 Dynamic Devices Ltd / Alex Lennon + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in all +copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +SOFTWARE. diff --git a/examples/array-limit/README.md b/examples/array-limit/README.md new file mode 100644 index 0000000..298d559 --- /dev/null +++ b/examples/array-limit/README.md @@ -0,0 +1,67 @@ +# When zero is a valid limit + +Evergreen exercise. Reviewed 15th October 2026 (Node 24.21.0). + +This deliberately small exercise was run for the guide. It is not a historical +project incident or a measurement of an assistant's performance. + +## Reproduce it + +You need Node.js 24; there are no npm dependencies, accounts or network calls. +After unzipping worked-example.zip, open a terminal in worked-example/. +For a repository clone use examples/array-limit/ instead. + +```sh +node --version +node --test-reporter=tap test.cjs buggy +node --test-reporter=tap test.cjs attempt +node --test-reporter=tap test.cjs fixed +``` + +Run the three stage commands separately. The first two intentionally return exit 1; +this is expected, so do not join them with &&. The fixed stage returns exit 0. + +## The problem + +`take(items, limit)` returns a new array. Omitted or null limits default to three. +Zero means no items; a positive integer caps the result. In buggy.cjs, `limit || 3` +replaces zero with three. The zero test expects [] but receives oak, ash and elm. + +The attempted correction in attempt.cjs moves the default to a variable using +`limit ? limit : 3`. That still treats zero as false. The same test still fails. +In fixed.cjs, `limit ?? 3` defaults only for null or undefined, preserving zero. +All three implementations and the identical six tests are in this folder. + +Actual guide run on Node 24.21.0, 15th October 2026: + +| Stage | Tests | Pass | Fail | Exit | +| --- | ---: | ---: | ---: | ---: | +| buggy | 6 | 5 | 1 | 1 | +| attempt | 6 | 5 | 1 | 1 | +| fixed | 6 | 6 | 0 | 0 | + +The other checks cover omitted/null defaults, positive/large limits, empty input, +and preserving the input. Invalid limits such as strings, negative numbers and +fractions are outside this contract; real APIs need an explicit validation policy. +This does not test model behaviour, host permissions, production integration, +performance or security. + +## Try it with an assistant + +Ask: "Read test.cjs and buggy.cjs. Explain why zero fails, cite the relevant +lines and suggest a focused check. Do not edit files." Check the answer yourself. +Then, if you want to practise editing, explicitly ask for a local correction and +rerun the tests. A plausible explanation or rewrite is not passing evidence. +You can complete the exercise by hand; an assistant is optional. + +## Continue (online) + +- Readable guide: https://chopwoodcarrywater.uk/worked-example.html +- Setup: https://chopwoodcarrywater.uk/#hour +- Download checksums and manifests: https://chopwoodcarrywater.uk/downloads.html +- Feedback: https://chopwoodcarrywater.uk/feedback.html + +If a step fails, include host/version, exact step, expected/actual result and a +link or file reference. Remove secrets and private project details first. + +Content CC BY-SA 4.0; code MIT (see LICENSE.txt). (Briar helped draft this) diff --git a/examples/array-limit/attempt.cjs b/examples/array-limit/attempt.cjs new file mode 100644 index 0000000..bb98057 --- /dev/null +++ b/examples/array-limit/attempt.cjs @@ -0,0 +1,5 @@ +// Attempt: move the default into a variable. Zero is still treated as false. +module.exports = function take(items, limit) { + const count = limit ? limit : 3; + return items.slice(0, count); +}; diff --git a/examples/array-limit/buggy.cjs b/examples/array-limit/buggy.cjs new file mode 100644 index 0000000..ee16b97 --- /dev/null +++ b/examples/array-limit/buggy.cjs @@ -0,0 +1,4 @@ +// Contract: null/undefined use 3; zero returns no items; positive integers cap results. +module.exports = function take(items, limit) { + return items.slice(0, limit || 3); +}; diff --git a/examples/array-limit/fixed.cjs b/examples/array-limit/fixed.cjs new file mode 100644 index 0000000..617ba40 --- /dev/null +++ b/examples/array-limit/fixed.cjs @@ -0,0 +1,4 @@ +module.exports = function take(items, limit) { + const count = limit ?? 3; + return items.slice(0, count); +}; diff --git a/examples/array-limit/test.cjs b/examples/array-limit/test.cjs new file mode 100644 index 0000000..244c54a --- /dev/null +++ b/examples/array-limit/test.cjs @@ -0,0 +1,31 @@ +const { test } = require('node:test'); +const assert = require('node:assert/strict'); +const stage = process.argv[2] || 'fixed'; +if (!['buggy', 'attempt', 'fixed'].includes(stage)) { + throw new Error('Use: node test.cjs buggy|attempt|fixed'); +} +const take = require(`./${stage}.cjs`); +const items = ['oak', 'ash', 'elm', 'beech']; + +test('omitted limit uses the default of three', () => { + assert.deepEqual(take(items), ['oak', 'ash', 'elm']); +}); +test('null limit uses the default of three', () => { + assert.deepEqual(take(items, null), ['oak', 'ash', 'elm']); +}); +test('zero requests no items', () => { + assert.deepEqual(take(items, 0), []); +}); +test('positive limit returns that many items', () => { + assert.deepEqual(take(items, 2), ['oak', 'ash']); +}); +test('large limit and empty input are safe', () => { + assert.deepEqual(take(items, 20), items); + assert.deepEqual(take([], 2), []); +}); +test('input remains unchanged and the result is a new array', () => { + const input = Object.freeze(['oak', 'ash', 'elm', 'beech']); + assert.deepEqual(take(input, 2), ['oak', 'ash']); + assert.deepEqual(input, items); + assert.notEqual(take(input, 20), input); +}); diff --git a/package.json b/package.json index 2f89eb0..dfc79ba 100644 --- a/package.json +++ b/package.json @@ -12,7 +12,8 @@ "serve": "npx --yes serve docs -l 4173", "test:e2e": "npx playwright test", "test:insight": "python3 tests/test_insight_tools.py", - "test": "npm run sync && npm run privacy && npm run test:insight && npm run test:e2e", + "test:downloads": "python3 tests/test_downloads.py", + "test": "npm run sync && npm run privacy && npm run test:insight && npm run test:downloads && npm run test:e2e", "check": "npm test" }, "devDependencies": { diff --git a/packs/codex-hour/CHECKLIST.md b/packs/codex-hour/CHECKLIST.md index ac3979a..f6de0e8 100644 --- a/packs/codex-hour/CHECKLIST.md +++ b/packs/codex-hour/CHECKLIST.md @@ -2,6 +2,8 @@ Start with a small piece of work in a project you control. Use Codex or Cursor; the packs share the same boundaries but use different project paths. +Guidance reviewed 15th October 2026. Need a self-contained task? The [worked exercise](https://chopwoodcarrywater.uk/worked-example.html) includes an offline guide and runnable source. [Download verification](https://chopwoodcarrywater.uk/downloads.html) and [feedback](https://chopwoodcarrywater.uk/feedback.html) use the same public routes. For feedback include host/version, step, expected/actual and a reference; remove private details. + ## 5 min - Choose a small task and your host Download the Codex or Cursor pack. Start with a read-only job: explain one failing test, naming the file, likely cause and one way to check it. diff --git a/packs/codex-hour/README.md b/packs/codex-hour/README.md index ae0ecb9..e0fb2eb 100644 --- a/packs/codex-hour/README.md +++ b/packs/codex-hour/README.md @@ -2,18 +2,20 @@ Complete one small, checked task before keeping extra process. +Guidance reviewed 15th October 2026; optional clocks keep their own historical dates. + Site: ## Install in a project you control -1. Compare `AGENTS.md and .agents/` with existing files. Merge instructions and skill folders; never overwrite existing project guidance. Resolve conflicting instructions with the human. +1. Compare `AGENTS.md` and `.agents/` with existing files. Merge instructions and skill folders; never overwrite existing project guidance. Resolve conflicting instructions with the human. 2. Keep secrets out of chat and require a human decision for consequential actions. Check the host’s sandbox and permission settings separately. 3. Start a new task in the project. Ask which guidance files it can read; check that `.agents/skills/example-domain-task/SKILL.md` is discoverable. Loading can vary with host version and settings; do not assume a running task reloaded changed files. 4. Follow `CHECKLIST.md`: do useful work early, then adapt a skill only if the job recurs. Copy pattern and clock files only when needed, merging any existing records. ## What this pack provides -`AGENTS.md and .agents/` contains written guidance and an example skill. It does not install an interceptor, authority verifier or runtime security system. AGENTS.md guides Codex; it does not replace sandboxing or permissions. Test the controls your host actually provides. Stop a consequential action when required approval is missing or cannot be verified. +`AGENTS.md` and `.agents/` contain written guidance and an example skill. It does not install an interceptor, authority verifier or runtime security system. AGENTS.md guides Codex; it does not replace sandboxing or permissions. Test the controls your host actually provides. Stop a consequential action when required approval is missing or cannot be verified. `patterns/WORKING-PATTERNS.md` contains editorial examples, not action permissions. `clocks.json` contains optional historical start dates; the checklist explains the host-specific fields. Leave unknown dates unset. @@ -28,4 +30,10 @@ Model access depends on host configuration. A gateway for an external review doe - Humans decide consequential actions. An agent may execute an authorised action within its exact scope after required checks; a signed-off pattern or passing review is not authority. - Diagnose failures before adding process. A smaller task, clearer existing instructions, removal of conflicts or a runtime restriction may solve the problem. No routine reflection note or new rule is required. +## Exercise, download checks and feedback + +- [Run the complete worked exercise](https://chopwoodcarrywater.uk/worked-example.html): a deliberately small failing test, unsuccessful correction and passing fix. Its ZIP includes source and an offline guide; no model or npm dependency is needed. +- [Verify this ZIP and inspect the file manifest](https://chopwoodcarrywater.uk/downloads.html#verify). Checksums detect changed bytes; they are not signatures or proof of a safe host. +- [Tell us which step needs improving](https://chopwoodcarrywater.uk/feedback.html) through the existing public repo/contact route. Include host/version, exact step, expected/actual result and a link or file reference. Remove private project details and secrets first. + (Briar helped draft this) diff --git a/packs/cursor-hour/CHECKLIST.md b/packs/cursor-hour/CHECKLIST.md index 53febbe..1fc819e 100644 --- a/packs/cursor-hour/CHECKLIST.md +++ b/packs/cursor-hour/CHECKLIST.md @@ -2,6 +2,8 @@ Start with a small piece of work in a project you control. Use Codex or Cursor; the packs share the same boundaries but use different project paths. +Guidance reviewed 15th October 2026. Need a self-contained task? The [worked exercise](https://chopwoodcarrywater.uk/worked-example.html) includes an offline guide and runnable source. [Download verification](https://chopwoodcarrywater.uk/downloads.html) and [feedback](https://chopwoodcarrywater.uk/feedback.html) use the same public routes. For feedback include host/version, step, expected/actual and a reference; remove private details. + ## 5 min - Choose a small task and your host Download the Codex or Cursor pack. Start with a read-only job: explain one failing test, naming the file, likely cause and one way to check it. diff --git a/packs/cursor-hour/README.md b/packs/cursor-hour/README.md index 534825d..47072fc 100644 --- a/packs/cursor-hour/README.md +++ b/packs/cursor-hour/README.md @@ -2,18 +2,20 @@ Complete one small, checked task before keeping extra process. +Guidance reviewed 15th October 2026; optional clocks keep their own historical dates. + Site: ## Install in a project you control -1. Compare `.cursor/rules/ and .cursor/skills/` with existing files. Merge instructions and skill folders; never overwrite existing project guidance. Resolve conflicting instructions with the human. +1. Compare `.cursor/rules/` and `.cursor/skills/` with existing files. Merge instructions and skill folders; never overwrite existing project guidance. Resolve conflicting instructions with the human. 2. Keep secrets out of chat and require a human decision for consequential actions. Check the host’s sandbox and permission settings separately. 3. Start a new task in the project. Ask which guidance files it can read; check that `.cursor/skills/example-domain-task/SKILL.md` is discoverable. Loading can vary with host version and settings; do not assume a running task reloaded changed files. 4. Follow `CHECKLIST.md`: do useful work early, then adapt a skill only if the job recurs. Copy pattern and clock files only when needed, merging any existing records. ## What this pack provides -`.cursor/rules/ and .cursor/skills/` contains written guidance and an example skill. It does not install an interceptor, authority verifier or runtime security system. Cursor’s alwaysApply metadata requests rule loading; it does not guarantee compliance or fail-closed enforcement. Test the controls your host actually provides. Stop a consequential action when required approval is missing or cannot be verified. +`.cursor/rules/` and `.cursor/skills/` contain written guidance and an example skill. It does not install an interceptor, authority verifier or runtime security system. Cursor’s alwaysApply metadata requests rule loading; it does not guarantee compliance or fail-closed enforcement. Test the controls your host actually provides. Stop a consequential action when required approval is missing or cannot be verified. `patterns/WORKING-PATTERNS.md` contains editorial examples, not action permissions. `clocks.json` contains optional historical start dates; the checklist explains the host-specific fields. Leave unknown dates unset. @@ -28,4 +30,10 @@ Model access depends on host configuration. A gateway for an external review doe - Humans decide consequential actions. An agent may execute an authorised action within its exact scope after required checks; a signed-off pattern or passing review is not authority. - Diagnose failures before adding process. A smaller task, clearer existing instructions, removal of conflicts or a runtime restriction may solve the problem. No routine reflection note or new rule is required. +## Exercise, download checks and feedback + +- [Run the complete worked exercise](https://chopwoodcarrywater.uk/worked-example.html): a deliberately small failing test, unsuccessful correction and passing fix. Its ZIP includes source and an offline guide; no model or npm dependency is needed. +- [Verify this ZIP and inspect the file manifest](https://chopwoodcarrywater.uk/downloads.html#verify). Checksums detect changed bytes; they are not signatures or proof of a safe host. +- [Tell us which step needs improving](https://chopwoodcarrywater.uk/feedback.html) through the existing public repo/contact route. Include host/version, exact step, expected/actual result and a link or file reference. Remove private project details and secrets first. + (Briar helped draft this) diff --git a/scripts/build_downloads.py b/scripts/build_downloads.py new file mode 100644 index 0000000..ac99825 --- /dev/null +++ b/scripts/build_downloads.py @@ -0,0 +1,64 @@ +#!/usr/bin/env python3 +"""Build byte-reproducible public downloads from source; no host metadata.""" +import hashlib +import json +from pathlib import Path +import stat +import zipfile + +ROOT = Path(__file__).resolve().parents[1] +PACKAGES = ( + ("packs/codex-hour", "codex-hour", "codex-hour-starter"), + ("packs/cursor-hour", "cursor-hour", "cursor-hour-starter"), + ("examples/array-limit", "worked-example", "worked-example"), +) + + +def digest(data): + return hashlib.sha256(data).hexdigest() + + +def build_package(source, prefix, name, destination): + """Manifest is adjacent to the ZIP, never part of its own hash input.""" + source, destination = Path(source), Path(destination) + destination.mkdir(parents=True, exist_ok=True) + files = sorted((p for p in source.rglob("*") if p.is_file()), + key=lambda p: p.relative_to(source).as_posix()) + if not files: + raise ValueError(f"Empty download source: {source}") + if any(p.is_symlink() for p in source.rglob("*")): + raise ValueError(f"Symlinks are not supported: {source}") + entries = [] + archive_path = destination / f"{name}.zip" + # STORE avoids zlib-version differences. These small text packs need no compression. + with zipfile.ZipFile(archive_path, "w", compression=zipfile.ZIP_STORED) as archive: + for path in files: + relative = path.relative_to(source).as_posix() + data = path.read_bytes() + info = zipfile.ZipInfo(f"{prefix}/{relative}", (1980, 1, 1, 0, 0, 0)) + info.create_system = 3 + info.external_attr = (stat.S_IFREG | 0o644) << 16 + info.compress_type = zipfile.ZIP_STORED + archive.writestr(info, data) + entries.append({"path": relative, "bytes": len(data), "sha256": digest(data)}) + manifest_path = destination / f"{name}-manifest.json" + manifest_path.write_text(json.dumps({ + "schema": "cwcw/download-manifest/v1", "archive": archive_path.name, + "root": prefix, "files": entries, + }, indent=2) + "\n", encoding="utf-8", newline="\n") + return [archive_path, manifest_path] + + +def main(): + destination = ROOT / "docs/packs" + artifacts = [] + for source, prefix, name in PACKAGES: + artifacts.extend(build_package(ROOT / source, prefix, name, destination)) + (destination / "SHA256SUMS").write_text("".join( + f"{digest(p.read_bytes())} {p.name}\n" for p in sorted(artifacts) + ), encoding="utf-8", newline="\n") + print("Built 3 deterministic ZIPs, public file manifests and SHA256SUMS") + + +if __name__ == "__main__": + main() diff --git a/scripts/render_notes.py b/scripts/render_notes.py index 1d1af4c..17fc2c1 100755 --- a/scripts/render_notes.py +++ b/scripts/render_notes.py @@ -357,7 +357,10 @@ def render_feed(posts: list[dict]) -> str: def render_sitemap(posts: list[dict]) -> str: urls = [ ("/", max(post.get("dateModified", post["date"]) for post in posts), "1.0"), - ("/agents.html", "2026-09-05", "0.8"), + ("/agents.html", "2026-10-15", "0.8"), + ("/worked-example.html", "2026-10-15", "0.8"), + ("/downloads.html", "2026-10-15", "0.7"), + ("/feedback.html", "2026-10-15", "0.6"), ] urls.extend( (f"/notes/{post['id']}.html", post.get("dateModified", post["date"]), "0.9") @@ -387,6 +390,9 @@ def render_llms(posts: list[dict]) -> str: ## Main pages - [Notebook]({ORIGIN}/) - [Agents: start here]({ORIGIN}/agents.html) +- [Worked exercise]({ORIGIN}/worked-example.html) +- [Download verification]({ORIGIN}/downloads.html) +- [Feedback]({ORIGIN}/feedback.html) - [RSS feed]({ORIGIN}/feed.xml) ## Insights diff --git a/scripts/sync-content.sh b/scripts/sync-content.sh index e57e4d2..3eb7593 100755 --- a/scripts/sync-content.sh +++ b/scripts/sync-content.sh @@ -12,13 +12,9 @@ rsync -a --delete \ rsync -a --delete "$ROOT/starters/" "$ROOT/docs/starters/" rsync -a --delete "$ROOT/packs/cursor-hour/" "$ROOT/docs/packs/cursor-hour/" rsync -a --delete "$ROOT/packs/codex-hour/" "$ROOT/docs/packs/codex-hour/" +mkdir -p "$ROOT/docs/examples/array-limit" +rsync -a --delete "$ROOT/examples/array-limit/" "$ROOT/docs/examples/array-limit/" "$ROOT/scripts/render_notes.py" "$ROOT/scripts/render_review_drafts.py" -( - cd "$ROOT/packs" - rm -f "$ROOT/docs/packs/cursor-hour-starter.zip" - rm -f "$ROOT/docs/packs/codex-hour-starter.zip" - zip -qr "$ROOT/docs/packs/cursor-hour-starter.zip" cursor-hour - zip -qr "$ROOT/docs/packs/codex-hour-starter.zip" codex-hour -) +python3 "$ROOT/scripts/build_downloads.py" echo "Synced content + rendered notes/reviews/feed/sitemap; synced starters and Codex/Cursor packs (+ zip)" diff --git a/tests/test_downloads.py b/tests/test_downloads.py new file mode 100644 index 0000000..b05d14d --- /dev/null +++ b/tests/test_downloads.py @@ -0,0 +1,95 @@ +"""Exercise the published artifacts, not just the builder's implementation.""" +import hashlib +import importlib.util +import json +import os +from pathlib import Path +import stat +import subprocess +import tempfile +import unittest +import zipfile + +ROOT = Path(__file__).resolve().parents[1] +spec = importlib.util.spec_from_file_location("downloads", ROOT / "scripts/build_downloads.py") +downloads = importlib.util.module_from_spec(spec) +spec.loader.exec_module(downloads) + + +class DownloadsTest(unittest.TestCase): + def test_every_published_file_matches_source_browse_zip_and_manifest(self): + destination = ROOT / "docs/packs" + expected_artifacts = set() + for source, prefix, name in downloads.PACKAGES: + source = ROOT / source + browse = ROOT / ("docs/examples/array-limit" if name == "worked-example" else f"docs/packs/{prefix}") + files = {p.relative_to(source).as_posix(): p.read_bytes() for p in source.rglob("*") if p.is_file()} + browsed = {p.relative_to(browse).as_posix(): p.read_bytes() for p in browse.rglob("*") if p.is_file()} + self.assertEqual(files, browsed, f"Source/browse mismatch: {name}") + manifest = json.loads((destination / f"{name}-manifest.json").read_text()) + self.assertEqual(manifest["root"], prefix) + self.assertEqual(manifest["archive"], f"{name}.zip") + self.assertEqual([entry["path"] for entry in manifest["files"]], sorted(files)) + with zipfile.ZipFile(destination / f"{name}.zip") as archive: + self.assertEqual(archive.namelist(), [f"{prefix}/{path}" for path in sorted(files)]) + for entry in manifest["files"]: + data = files[entry["path"]] + self.assertEqual(archive.read(f"{prefix}/{entry['path']}"), data) + self.assertEqual(entry["bytes"], len(data)) + self.assertEqual(entry["sha256"], hashlib.sha256(data).hexdigest()) + expected_artifacts.update((f"{name}.zip", f"{name}-manifest.json")) + listed = {} + for line in (destination / "SHA256SUMS").read_text().splitlines(): + checksum, name = line.split(" ") + self.assertNotIn(name, listed) + listed[name] = checksum + self.assertEqual(checksum, hashlib.sha256((destination / name).read_bytes()).hexdigest()) + self.assertEqual(set(listed), expected_artifacts) + + def test_reproducible_despite_mtimes_modes_and_creation_order(self): + # Rebuild every real package twice with different filesystem metadata/order. + with tempfile.TemporaryDirectory() as temp: + temp = Path(temp) + for source, prefix, name in downloads.PACKAGES: + files = sorted(p for p in (ROOT / source).rglob("*") if p.is_file()) + outputs = [] + for variant in range(2): + tree = temp / name / str(variant) / "source" + for path in files if variant == 0 else reversed(files): + target = tree / path.relative_to(ROOT / source) + target.parent.mkdir(parents=True, exist_ok=True) + target.write_bytes(path.read_bytes()) + target.chmod(0o600 if variant == 0 else 0o755) + os.utime(target, (946684800 + variant * 100000000, 946684800 + variant * 100000000)) + output = temp / name / str(variant) / "out" + artifacts = downloads.build_package(tree, prefix, name, output) + outputs.append([p.read_bytes() for p in artifacts]) + with zipfile.ZipFile(artifacts[0]) as archive: + for entry in archive.infolist(): + self.assertEqual(entry.date_time, (1980, 1, 1, 0, 0, 0)) + self.assertEqual(stat.S_IMODE(entry.external_attr >> 16), 0o644) + self.assertEqual(entry.compress_type, zipfile.ZIP_STORED) + self.assertEqual(outputs[0], outputs[1], name) + self.assertEqual(outputs[0][0], (ROOT / f"docs/packs/{name}.zip").read_bytes()) + self.assertEqual(outputs[0][1], (ROOT / f"docs/packs/{name}-manifest.json").read_bytes()) + + def test_downloaded_exercise_reproduces_both_failures_and_the_fix(self): + with tempfile.TemporaryDirectory() as temp: + with zipfile.ZipFile(ROOT / "docs/packs/worked-example.zip") as archive: + archive.extractall(temp) + for stage, passes, failures in (("buggy", 5, 1), ("attempt", 5, 1), ("fixed", 6, 0)): + result = subprocess.run( + ["node", "--test-reporter=tap", "test.cjs", stage], + cwd=Path(temp) / "worked-example", capture_output=True, text=True, + timeout=15, + ) + self.assertEqual(result.returncode, 1 if failures else 0, result.stdout + result.stderr) + self.assertIn("# tests 6", result.stdout) + self.assertIn(f"# pass {passes}", result.stdout) + self.assertIn(f"# fail {failures}", result.stdout) + if failures: + self.assertIn("not ok 3 - zero requests no items", result.stdout) + + +if __name__ == "__main__": + unittest.main() diff --git a/tests/useful-next-steps.spec.js b/tests/useful-next-steps.spec.js new file mode 100644 index 0000000..f86658b --- /dev/null +++ b/tests/useful-next-steps.spec.js @@ -0,0 +1,84 @@ +const { test, expect } = require('@playwright/test'); +const fs = require('node:fs'); +const path = require('node:path'); +const axePath = require.resolve('axe-core/axe.min.js'); + +test('three starting points work with keyboard and preserve reference destinations', async ({ page }, testInfo) => { + await page.goto('/'); + await expect(page.locator('body')).toHaveAttribute('data-ready', 'true'); + const starts = page.locator('#start-here'); + const links = starts.locator('.path-card'); + await expect(links).toHaveCount(3); + const targets = ['worked-example.html', '#hour', '#blog']; + for (let i = 0; i < targets.length; i++) { + await expect(links.nth(i)).toHaveAttribute('href', targets[i]); + } + // Tab through the actual links; Enter must navigate to the exercise. + await links.nth(0).focus(); + await page.keyboard.press('Tab'); + await expect(links.nth(1)).toBeFocused(); + await page.keyboard.press('Tab'); + await expect(links.nth(2)).toBeFocused(); + await page.keyboard.press('Shift+Tab'); + await page.keyboard.press('Shift+Tab'); + await expect(links.nth(0)).toBeFocused(); + await links.nth(0).scrollIntoViewIfNeeded(); + await page.screenshot({ path: testInfo.outputPath('starting-points.png') }); + for (const id of ['hour', 'codex', 'playbook', 'starters', 'learning', 'runtime', 'channels', 'explore', 'measure', 'blog']) { + await expect(page.locator(`#${id}`)).toHaveCount(1); + } + await page.keyboard.press('Enter'); + // The local static server redirects .html to an extensionless URL. + await expect(page).toHaveURL(/\/worked-example(?:\.html)?$/); + await expect(page.getByRole('heading', { level: 1 })).toBeVisible(); + const sample = page.getByRole('region', { name: 'Exercise commands' }); + await page.getByRole('link', { name: 'Verify the download', exact: true }).focus(); + await page.keyboard.press('Tab'); + await expect(sample).toBeFocused(); + const focus = await sample.evaluate(el => ({ visible: el.matches(':focus-visible'), width: parseFloat(getComputedStyle(el).outlineWidth) })); + expect(focus.visible).toBe(true); + expect(focus.width).toBeGreaterThanOrEqual(3); + await page.keyboard.press('Tab'); + await expect(sample).not.toBeFocused(); +}); + +for (const file of ['worked-example.html', 'downloads.html', 'feedback.html']) { + test(`${file} is readable, linked and accessible`, async ({ page, request }, testInfo) => { + const errors = []; + page.on('pageerror', error => errors.push(error.message)); + await page.goto(`/${file}`); + await expect(page.locator('main h1')).toHaveCount(1); + const brand = page.locator('.brand img'); + expect(await brand.evaluate(el => el.naturalWidth)).toBeGreaterThan(0); + expect(await page.evaluate(() => document.documentElement.scrollWidth <= innerWidth)).toBe(true); + for (const href of new Set(await page.locator('main a[href]').evaluateAll(links => links.map(a => a.getAttribute('href'))))) { + if (/^https?:/.test(href)) continue; // Local candidate checks need no external traffic. + const url = new URL(href, page.url()); + expect((await request.get(url.pathname)).ok(), href).toBe(true); + if (url.hash && url.pathname.endsWith('.html') && url.pathname === `/${file}`) { + await expect(page.locator(url.hash)).toHaveCount(1); + } + } + await page.addScriptTag({ path: axePath }); + const result = await page.evaluate(async () => { + const r = await axe.run(document, { runOnly: { type: 'tag', values: ['wcag2a', 'wcag2aa', 'wcag21a', 'wcag21aa'] } }); + return { violations: r.violations, passes: r.passes.length, incomplete: r.incomplete.length }; + }); + fs.writeFileSync(testInfo.outputPath('axe.json'), JSON.stringify(result, null, 2)); + await page.screenshot({ path: testInfo.outputPath(file.replace('.html', '.png')), fullPage: true }); + expect(result.violations).toEqual([]); + expect(errors).toEqual([]); + if (file === 'worked-example.html') { + const downloadEvent = page.waitForEvent('download'); + await page.getByRole('link', { name: 'Download the exercise ZIP', exact: true }).click(); + const download = await downloadEvent; + expect(download.suggestedFilename()).toBe('worked-example.zip'); + await download.saveAs(testInfo.outputPath('worked-example.zip')); + expect(fs.readFileSync(testInfo.outputPath('worked-example.zip'))).toEqual(fs.readFileSync(path.join(__dirname, '../docs/packs/worked-example.zip'))); + } + if (file === 'feedback.html') { + await expect(page.locator('form, input, textarea')).toHaveCount(0); + await expect(page.getByRole('link', { name: 'existing repository issue route' })).toHaveAttribute('href', 'https://github.com/DynamicDevices/durable-agent-harness/issues'); + } + }); +} From 7a4a7eefb377059b1b2558e96a3b23657011874b Mon Sep 17 00:00:00 2001 From: Alex J Lennon Date: Fri, 16 Oct 2026 00:10:46 +0100 Subject: [PATCH 2/2] Clarify licensing in the standalone exercise Assisted-by: Briar --- docs/examples/array-limit/LICENSE.txt | 29 ++++++------------------ docs/packs/SHA256SUMS | 4 ++-- docs/packs/worked-example-manifest.json | 4 ++-- docs/packs/worked-example.zip | Bin 7289 -> 6896 bytes examples/array-limit/LICENSE.txt | 29 ++++++------------------ 5 files changed, 18 insertions(+), 48 deletions(-) diff --git a/docs/examples/array-limit/LICENSE.txt b/docs/examples/array-limit/LICENSE.txt index 720ee65..a219034 100644 --- a/docs/examples/array-limit/LICENSE.txt +++ b/docs/examples/array-limit/LICENSE.txt @@ -1,30 +1,15 @@ -# Licensing - -This repository uses two licences. - -## Site content (notebook) - -The public notebook content — including files under `content/`, `docs/` pages -and assets that present that notebook, `blog-inbox.md`, `AGENTS.md`, -`BASELINE.md`, and the Cursor hour pack’s prose — is licensed under - -**Creative Commons Attribution-ShareAlike 4.0 International (CC BY-SA 4.0)** +# Worked exercise licence +The README and explanatory prose in this exercise are licensed under Creative +Commons Attribution-ShareAlike 4.0 International (CC BY-SA 4.0): https://creativecommons.org/licenses/by-sa/4.0/ Copyright © 2026 Alex Lennon (Chop Wood Carry Water). +Credit the author, indicate changes, link to the licence, and share adaptations +of that prose under the same licence. The linked licence contains the terms. -You are free to share and adapt the material for any purpose, even commercially, -provided you give appropriate credit, indicate if changes were made, and -distribute your contributions under the same licence. - -## Code (site machinery) - -Build/test scripts, Playwright tests, and the small amount of site JavaScript / -CSS plumbing are licensed under the **MIT License** — see [LICENSE-MIT.txt](LICENSE-MIT.txt). - -Copyright © 2026 Dynamic Devices Ltd / Alex Lennon. - +The JavaScript files (buggy.cjs, attempt.cjs, fixed.cjs and test.cjs) are +licensed under the MIT License reproduced below. MIT License diff --git a/docs/packs/SHA256SUMS b/docs/packs/SHA256SUMS index 0766600..1d5c504 100644 --- a/docs/packs/SHA256SUMS +++ b/docs/packs/SHA256SUMS @@ -2,5 +2,5 @@ 18d81c5b151fb46135740771ab0cf04fc8e33b12ddc2aeb39db4a08e93f9badf codex-hour-starter.zip f4193d2437bbd67e50743da170cc92e476b5a9f10d738487eaede2f829eaea6e cursor-hour-starter-manifest.json 89c7900ffd6168526ad47fe5666ac39c2fc3855f4973d6839be18dfe9fb708cd cursor-hour-starter.zip -c38d8ed15110766dc30515e071f77d8eabaa0c1cf436d379c38b519479ca7901 worked-example-manifest.json -448697b1200f187a7420b53338688ac8a41521eceadc5a10544f99d1ec2ab5dd worked-example.zip +974550a715e2dad6c19cbae8742e66e82629f827101c2f15e6763dbe19a32d01 worked-example-manifest.json +723017ea63f69d23f16a79d26a411647be04a0ce5755c83f005cac5df9c94b14 worked-example.zip diff --git a/docs/packs/worked-example-manifest.json b/docs/packs/worked-example-manifest.json index 530b4cf..64d8467 100644 --- a/docs/packs/worked-example-manifest.json +++ b/docs/packs/worked-example-manifest.json @@ -5,8 +5,8 @@ "files": [ { "path": "LICENSE.txt", - "bytes": 2039, - "sha256": "3e8a9fdbbe7af384798e42018c6b82dd70dc7dba1633e6bae1ee8619f1eca371" + "bytes": 1646, + "sha256": "eebd537367425d79230388cb948da4638c51f23f24b11f27ae33d1706fbb061f" }, { "path": "README.md", diff --git a/docs/packs/worked-example.zip b/docs/packs/worked-example.zip index 0cb266eb3b5ac288c44d0df34c441a96173712cd..75c858f8f1ee96f206f08a25f5481d2d2f4c1cea 100644 GIT binary patch delta 456 zcmYLGu}T9$5KS)O!0Xf?(WF?#!axXu2x22*A{Y%A4QL~{*_-56lig!?FD8}WAo~xg z1$#e1u(7ujM6k7U?k?z7GsAoH-n{+U`Q9#`9_R9fO!`(c?dxejXf~8vFHDgHRCz!T}Z3NHrm$l8EGjn1Jg)s-?NY+<^jW_y{~J zvU}NG`!U8J#psT1WZi$fzYUZJu2FToxLFGA z$sVGpNp09yr+80dv+)MJWJV@T3PZWj$wmWesB7s_O**3IO!3f=9v^@v8{MeipVZh5 z+Mve3Ff?h?<74pSGBIL6C-VwHLtY}IQ7;nyI;cdYb<`mzaekPN0!+z|7$UkbkaxAG w&)oZx_aDA}Te)3-%eimqnW|*Bw=`&2q)vT8=;N7r(xkmH+?% delta 847 zcmYjQF>ljA6b>$e>NZ4+lpxTnx-?drOqIH!HVvrIMwJ{15CY}wdx=lAedg|*HeyHz z{y=3G#KgqNz{X_kH)h=bszDH}4)iS-8Gbn?EbH#qS?J z|GHVLxwlcis^6Qf!k&yUGcp@9Hi)GGjkz+?Dm{h5paFZNAaQ3RG;PLKS0RuVAyS#e z%)(lxEQU%QHeEkLUW9ZSF0)tX&QIQf%%Y?aLWwit<+NI|?) zLLNIho>ML-0O!0$A#ID?6f)v=h9E}}#XKX&;0TF2<${1o029(!EyIG^2uoMfsA8!y z=fAVx$um5~%PG%?+*JZ$jTXVdMX}6KPie&4g-k@pqOo8iEpuyTEjUQ{^hnEbOn0S< zskrC3DcuNostTH#8bO8km``|6HA9DWg8=fRNJF<4&bMmUu1v2`e1Cs;aIvW9`_*_1 zdHrH-uT*Z|Ic4Ch$Bh> diff --git a/examples/array-limit/LICENSE.txt b/examples/array-limit/LICENSE.txt index 720ee65..a219034 100644 --- a/examples/array-limit/LICENSE.txt +++ b/examples/array-limit/LICENSE.txt @@ -1,30 +1,15 @@ -# Licensing - -This repository uses two licences. - -## Site content (notebook) - -The public notebook content — including files under `content/`, `docs/` pages -and assets that present that notebook, `blog-inbox.md`, `AGENTS.md`, -`BASELINE.md`, and the Cursor hour pack’s prose — is licensed under - -**Creative Commons Attribution-ShareAlike 4.0 International (CC BY-SA 4.0)** +# Worked exercise licence +The README and explanatory prose in this exercise are licensed under Creative +Commons Attribution-ShareAlike 4.0 International (CC BY-SA 4.0): https://creativecommons.org/licenses/by-sa/4.0/ Copyright © 2026 Alex Lennon (Chop Wood Carry Water). +Credit the author, indicate changes, link to the licence, and share adaptations +of that prose under the same licence. The linked licence contains the terms. -You are free to share and adapt the material for any purpose, even commercially, -provided you give appropriate credit, indicate if changes were made, and -distribute your contributions under the same licence. - -## Code (site machinery) - -Build/test scripts, Playwright tests, and the small amount of site JavaScript / -CSS plumbing are licensed under the **MIT License** — see [LICENSE-MIT.txt](LICENSE-MIT.txt). - -Copyright © 2026 Dynamic Devices Ltd / Alex Lennon. - +The JavaScript files (buggy.cjs, attempt.cjs, fixed.cjs and test.cjs) are +licensed under the MIT License reproduced below. MIT License