Skip to content

Commit d500194

Browse files
authored
Merge pull request #1 from TensorOpsAI/codex/intent-md-exercise
Add the first intent.md student exercise
2 parents 701679c + bbce737 commit d500194

10 files changed

Lines changed: 202 additions & 2 deletions

File tree

‎.github/workflows/grade.yml‎

Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,12 @@
1+
name: Check intent submission
2+
on:
3+
push:
4+
branches: [main]
5+
permissions:
6+
contents: read
7+
pull-requests: read
8+
jobs:
9+
grade:
10+
uses: TensorOpsAI/tensorlearn-intent-grader/.github/workflows/grade.yml@9e40d82165c88f9028c6b119f5833dac5d48da9b
11+
with:
12+
grader-sha: 9e40d82165c88f9028c6b119f5833dac5d48da9b

‎.gitignore‎

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,3 @@
1+
node_modules/
2+
.env*
3+
.DS_Store

‎CLAUDE.md‎

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,9 @@
1+
# Intent authoring exercise
2+
3+
Read @docs/product-brief.md for the fictional project requirements.
4+
Read @intent.md for the student's proposed implementation instructions.
5+
6+
This round is about writing a useful intent document, not implementing the feature.
7+
Change only intent.md. Help the student reason about scope, constraints and testable
8+
acceptance criteria. Do not silently commit, push, open or merge a PR. The student
9+
must explicitly choose to merge their solution PR into their own fork's main branch.

‎README.md‎

Lines changed: 47 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,48 @@
1-
# tensorlearn-intent-lab
1+
# Write an intent document for Claude
22

3-
Fictional intent.md authoring exercise.
3+
A 25–40 minute exercise using a fictional support-ticket project. Your deliverable
4+
is **intent.md**. Claude Code reads it through the supplied `CLAUDE.md` import.
5+
Read [the product brief and published rubric](docs/product-brief.md).
6+
7+
## Student steps
8+
9+
1. Fork this repository to your personal GitHub account. Use fictional information
10+
only, keep the fork public, and keep `main` as its default branch.
11+
2. Clone your fork, open it in Claude Code, and enable GitHub Actions in the fork.
12+
3. Create a branch such as `intent/first-draft`. Read the brief and ask Claude to
13+
help you write `intent.md`. Change only that file. Review the document yourself.
14+
4. Start a fresh Claude session. Ask it to explain the scope and acceptance criteria
15+
it loaded before doing any implementation. Refine your document as needed.
16+
5. Commit and push your branch. Open a PR **inside your own fork**, targeting its
17+
`main` branch. GitHub may suggest the upstream repository: select your fork instead.
18+
6. Review and merge your PR. **The merge is your submission for this exercise.**
19+
7. Open the Actions run for the merged commit. Download `intent-score` and inspect
20+
`score.json`. Discuss the feedback with your facilitator and repeat with a new PR.
21+
22+
## What is verified
23+
24+
Twenty published checks each award five points. The checker reads documents as data
25+
and recomputes the acceptance examples. It never runs your code or asks an LLM to
26+
judge your prose. The facilitator separately reviews clarity, contradictions, and
27+
whether Claude follows the intent. Local `npm test` checks the starter module only.
28+
29+
Claude imports are described in [the official memory documentation](https://code.claude.com/docs/en/memory#import-additional-files).
30+
31+
## Facilitator setup and server scoring
32+
33+
The separate [document checker](https://github.com/TensorOpsAI/tensorlearn-intent-grader)
34+
is pinned to an immutable commit in `.github/workflows/grade.yml`. No server secrets
35+
belong in this starter or student forks. The workflow emits the platform's score.json
36+
format; GitHub App delivery and admission of the submission must also be configured
37+
on the platform before a score can appear there.
38+
39+
**Rehearsal blocker:** the currently observed platform requires a private repository
40+
and explicit submission of an open PR. It does not currently accept this exercise's
41+
public-fork merge as an official submission. The exercise can be prepared and its
42+
checker tested, but the website score step remains unverified and blocked by that
43+
mismatch. Do not treat an Actions score as proof that the server saved it.
44+
45+
The exercise should remain unlaunched until the facilitator has resolved that setup
46+
and checked one actual learner result end to end. See the checker repository's
47+
rehearsal checklist. No customer identity, credentials, or participant data is stored
48+
in these public repositories.

‎docs/product-brief.md‎

Lines changed: 85 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,85 @@
1+
# Product brief: preview a support-ticket CSV import
2+
3+
This is a fictional training project. A support coordinator wants to preview tickets
4+
from a CSV file before any later import is approved. In this round you write
5+
`intent.md` to instruct Claude how to implement that feature in a future round.
6+
**Do not implement the feature now. Change only `intent.md`.**
7+
8+
The repository already has `src/tickets.mjs` and its tests. That code is the stable
9+
ticket representation. A future implementation may add only
10+
`src/import-tickets.mjs` and `tests/import-tickets.test.mjs`. It must not alter the
11+
existing ticket module, the grading workflow, or Claude's instruction loader.
12+
No UI, database, network calls, file writes or package dependencies are needed.
13+
14+
The proposed preview takes CSV text and returns a result without changing any data:
15+
16+
- Require a `title` column; an optional `priority` column is allowed. Reject other,
17+
missing, or duplicate column names and malformed rows with `unknown-column`.
18+
- Trim surrounding whitespace from values. Reject an empty title with `empty-title`.
19+
- Priorities are `low`, `normal`, `urgent`; missing or blank priority becomes `normal`.
20+
Reject anything else with `invalid-priority`.
21+
- Accept at most 100 data rows. Check this before validating row values; more rows
22+
produces `row-limit`. An empty CSV with no header produces `unknown-column`.
23+
- Respect CSV quoting (for example, a title containing a comma).
24+
- Success is `{"tickets":[{"title":"...","priority":"normal"}]}` in input order.
25+
Failure is `{"error":"error-code"}`. No partial success is returned.
26+
- Verification commands are `npm test` and `git diff --check`.
27+
28+
## What to write
29+
30+
Keep the six headings in `intent.md`: Goal, Scope, Constraints, Plan, Acceptance,
31+
and Verification. Under each, write at least 30 characters of useful, original prose.
32+
Explain the outcome, boundaries, implementation sequence, and observable completion
33+
checks. Tell Claude to ask before implementing or expanding scope. Avoid placeholders.
34+
35+
Include exactly one fenced **json** block with this contract shape:
36+
37+
```json
38+
{
39+
"schema": 1,
40+
"change": "ticket-csv-preview",
41+
"allowed_changes": ["src/import-tickets.mjs", "tests/import-tickets.test.mjs"],
42+
"protected_paths": ["src/tickets.mjs", ".github/", "CLAUDE.md"],
43+
"non_goals": ["ui", "database", "network"],
44+
"requirements": {
45+
"columns": ["title", "priority"],
46+
"default_priority": "normal",
47+
"valid_priorities": ["low", "normal", "urgent"],
48+
"reject_unknown_columns": true,
49+
"reject_empty_title": true,
50+
"max_rows": 100,
51+
"side_effects": "preview-only"
52+
},
53+
"verification": ["npm test", "git diff --check"],
54+
"approval": "ask-before-implementation",
55+
"acceptance_cases": [
56+
{
57+
"csv": "title,priority\nPrinter issue,urgent\n",
58+
"expected": {"tickets":[{"title":"Printer issue","priority":"urgent"}]}
59+
}
60+
]
61+
}
62+
```
63+
64+
The example contains only one case. Add correctly predicted cases covering all seven
65+
categories: valid explicit priority, default priority, a quoted title containing a
66+
comma, empty title, unknown column, invalid priority, and too many rows. You may use
67+
`"repeat": 101` on a one-data-row case to represent 101 copies without a long document.
68+
Otherwise omit `repeat`; the input is used once. All expected results must be correct.
69+
The JSON gives the checker objective facts to verify; the prose makes the document
70+
useful for a human and Claude. The JSON alone is not a complete intent document.
71+
72+
## How the score works
73+
74+
Twenty published checks are worth five points each (100 total): document structure,
75+
Claude import, scope and constraints, contract values, verification/approval, correct
76+
examples, and coverage of all seven categories. The trusted checker recomputes the
77+
example outputs; writing a desired score or asserting that examples pass has no effect.
78+
79+
This is a deterministic contract score, not an AI judgment of writing quality. During
80+
the rehearsal, the facilitator will separately discuss clarity, contradictions, and
81+
whether Claude follows the intent. A machine score cannot certify those qualities.
82+
83+
Only `intent.md` may change from the starter files. Changed scaffolding, symlinks,
84+
oversized input, invalid UTF-8 or an unreadable submission cannot earn an official
85+
passing result. No student code is executed by the checker.

‎fixtures/sample.csv‎

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,3 @@
1+
title,priority
2+
Printer issue,urgent
3+
"Question about billing, October",normal

‎intent.md‎

Lines changed: 19 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,19 @@
1+
# Intent
2+
3+
## Goal
4+
TODO: describe the outcome and the user who needs it.
5+
6+
## Scope
7+
TODO: identify the allowed changes and the work deliberately excluded.
8+
9+
## Constraints
10+
TODO: state the project and data constraints the implementation must preserve.
11+
12+
## Plan
13+
TODO: give Claude a short, ordered implementation plan.
14+
15+
## Acceptance
16+
TODO: specify useful positive and negative examples; add the JSON contract described in the brief.
17+
18+
## Verification
19+
TODO: explain how to verify the result and when to ask the user for approval.

‎package.json‎

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,8 @@
1+
{
2+
"name": "tensorlearn-intent-lab",
3+
"version": "1.0.0",
4+
"private": true,
5+
"type": "module",
6+
"scripts": { "test": "node --test tests/*.test.mjs" },
7+
"engines": { "node": ">=22" }
8+
}

‎src/tickets.mjs‎

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,5 @@
1+
export function ticket(title, priority = 'normal') {
2+
if (typeof title !== 'string' || !title.trim()) throw new Error('empty-title')
3+
if (!['low', 'normal', 'urgent'].includes(priority)) throw new Error('invalid-priority')
4+
return { title: title.trim(), priority }
5+
}

‎tests/tickets.test.mjs‎

Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,11 @@
1+
import test from 'node:test'
2+
import assert from 'node:assert/strict'
3+
import { ticket } from '../src/tickets.mjs'
4+
5+
test('a ticket trims its title and defaults to normal priority', () => {
6+
assert.deepEqual(ticket(' Printer issue '), { title: 'Printer issue', priority: 'normal' })
7+
})
8+
test('a ticket rejects a blank title and unsupported priority', () => {
9+
assert.throws(() => ticket(' '), /empty-title/)
10+
assert.throws(() => ticket('Printer issue', 'critical'), /invalid-priority/)
11+
})

0 commit comments

Comments
 (0)