style(no-slop): remove every em-dash + banned words across all modules + capstone

Apply the no-ai-slop standard (now binding in AGENTS.md): the em-dash character is
banned outright (restructured, not blind-replaced), plus the banned word/phrase
list (delve, leverage, robust, seamless, truly, unlock, etc.). 0 em-dashes remain
in modules + capstone; the only "robust" left is the planted M10 ai-change.patch
trap. Module H1 titles use a colon separator.

All deliberate teaching devices preserved; labs compile/parse (py/sh/yaml/json);
no junk. AGENTS.md updated with the hard no-slop rules.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01TfzV5QvtPDz8LJS3Pu5VLT
This commit is contained in:
2026-06-22 23:21:09 -04:00
parent 513d7e7ac8
commit 389ac2e460
99 changed files with 1324 additions and 1315 deletions
+53 -53
View File
@@ -1,4 +1,4 @@
# Module 9 Issues and the Task Layer
# Module 9: Issues and the Task Layer
> **An issue is how you hand a piece of work to someone else, and "someone else" is now a mix of
> humans and agents.** A well-formed issue is the one interface that works for both, which makes
@@ -8,14 +8,14 @@
## Prerequisites
- **Module 8** you have a repo on a remote forge (GitHub or any alternative). Issues live on the
- **Module 8**: you have a repo on a remote forge (GitHub or any alternative). Issues live on the
forge, alongside the code, so this module needs the remote you set up there. Everything here is
provider-neutral: issues exist on every forge.
- **Module 5** you committed your AI instructions file. That file plus a good issue is what gives
- **Module 5**: you committed your AI instructions file. That file plus a good issue is what gives
an agent enough context to attempt a task; this module puts that pairing to work.
- **Module 2** the repo-as-durable-memory reframe. Issues are the team-scale version of the same
- **Module 2**: the repo-as-durable-memory reframe. Issues are the team-scale version of the same
idea: shared memory for the work that *hasn't happened yet*.
- **Module 1** the `tasks-app` project. The lab writes issues against it.
- **Module 1**: the `tasks-app` project. The lab writes issues against it.
You do **not** yet need pull requests (Module 10) or the full collaboration loop (Module 11). This
module produces the *input* to that loop. We'll point forward to it, not teach it here.
@@ -26,12 +26,12 @@ module produces the *input* to that loop. We'll point forward to it, not teach i
By the end of this module you can:
1. Write a well-formed issue title, context, acceptance criteria, scope that a human *or* an
1. Write a well-formed issue (title, context, acceptance criteria, scope) that a human *or* an
agent can pick up and act on without a follow-up conversation.
2. Use labels and assignment to route, prioritize, and find work across a backlog.
3. Decide which work to route to a human and which to hand to an agent, and articulate the heuristic
behind that call.
4. Use issues as durable, shared task memory the part of the project's state that lives outside
4. Use issues as durable, shared task memory: the part of the project's state that lives outside
the code.
---
@@ -45,19 +45,19 @@ someone's head, a Slack thread, or a chat tab.** The project-management vocabula
that core doesn't. It has a title, a body, and metadata (labels, an assignee, a status). It gets a stable number. You
can link to it, search it, and close it.
You already know this shape it's a ticket. Jira, Linear, ServiceNow, a help-desk queue: same idea.
You already know this shape; it's a ticket. Jira, Linear, ServiceNow, a help-desk queue: same idea.
What matters for this course is that **every git forge has issues built in**, sitting in the same
place as the repo. GitHub Issues, GitLab Issues, Gitea/Forgejo Issues, Bitbucket, Azure Boards
place as the repo. GitHub Issues, GitLab Issues, Gitea/Forgejo Issues, Bitbucket, Azure Boards:
the feature set varies, the concept does not. Because they're attached to the repo, an issue can
reference a commit, a file, or a line, and the work that resolves it can reference the issue back.
That tight coupling is the whole point: the *description* of the work and the *code* that does it
live one click apart.
### Reframe issues are shared task memory
### Reframe: issues are shared task memory
Module 2 reframed the repo as **durable memory the AI can read**: a fresh session reconstructs
"where were we?" from `git log`, `git status`, and `git diff`. But notice what git can only ever
tell you what *happened*. Settled history and in-flight edits. It is silent on the work that
tell you: what *happened*. Settled history and in-flight edits. It is silent on the work that
*hasn't started yet*: the bug someone reported, the feature you promised, the cleanup you keep
deferring.
@@ -70,7 +70,7 @@ and they divide the timeline cleanly:
| The repo (Module 2) | "What happened / what's in flight right now?" | commits, working tree |
| The issue tracker (this module) | "What still needs to happen, and who has it?" | issues, labels, assignees |
A teammate joining tomorrow or an agent that has never seen the project reads the repo to learn
A teammate joining tomorrow, or an agent that has never seen the project, reads the repo to learn
the code and reads the open issues to learn the *work*. Both are ground truth you can hand to a
human or a machine. Neither depends on anyone remembering anything.
@@ -81,18 +81,18 @@ context. A good issue is written for **a stranger**, because increasingly the th
up *is* one: a teammate you've never met, future-you who's forgotten, or an agent with no memory at
all. Four parts carry the weight:
1. **Title** a specific, scannable summary. Someone reading a list of forty titles should know
1. **Title**: a specific, scannable summary. Someone reading a list of forty titles should know
what each one is. `done command crashes on a bad index` beats `bug in cli`.
2. **Context / problem** what's wrong or missing, and *why it matters*. Include how to reproduce a
2. **Context / problem**: what's wrong or missing, and *why it matters*. Include how to reproduce a
bug (the exact command and what happened), or the motivation for a feature. This is the part a
vague issue skips and then nobody can act on it.
3. **Acceptance criteria** the checklist that defines *done*. Concrete, verifiable statements:
3. **Acceptance criteria**: the checklist that defines *done*. Concrete, verifiable statements:
"`done 99` prints an error and exits non-zero instead of a traceback." This is the single most
valuable part of the issue, for reasons the AI angle makes sharp.
4. **Scope / out of scope** what this issue does *not* cover, so the work doesn't sprawl. "Not
4. **Scope / out of scope**: what this issue does *not* cover, so the work doesn't sprawl. "Not
changing the storage format" keeps a one-line fix from becoming a refactor.
A proposed approach is optional and often helpful, but keep it as a suggestion, not a spec the
A proposed approach is optional and often helpful, but keep it as a suggestion, not a spec; the
person or agent doing the work may know a better one.
Compare. A bad issue:
@@ -100,7 +100,7 @@ Compare. A bad issue:
> **Title:** fix the done thing
> the done command is broken, please fix
Nobody human or agent can act on that without coming back to ask you three questions. A
Nobody, human or agent, can act on that without coming back to ask you three questions. A
well-formed version of the same bug:
> **Title:** `done` command crashes on an out-of-range or non-integer index
@@ -119,44 +119,44 @@ well-formed version of the same bug:
That second version is pickup-ready. It is also, not coincidentally, the format an agent needs.
### Labels the cross-cutting axes
### Labels: the cross-cutting axes
A title says what one issue is. **Labels** are how you slice the whole backlog. Keep the taxonomy
small and orthogonal a handful of axes, not forty decorative tags:
small and orthogonal, a handful of axes, not forty decorative tags:
- **Type** `bug`, `feature`, `chore`/`docs`. What kind of work.
- **Priority** `p1`/`p2`/`p3` or `high`/`med`/`low`. How much it matters.
- **Area** `cli`, `storage`, `docs`. Which part of the system, for routing to whoever (or whatever)
- **Type**: `bug`, `feature`, `chore`/`docs`. What kind of work.
- **Priority**: `p1`/`p2`/`p3` or `high`/`med`/`low`. How much it matters.
- **Area**: `cli`, `storage`, `docs`. Which part of the system, for routing to whoever (or whatever)
owns it.
- **Readiness** a single label like `ready` meaning "well-formed enough to start." This one matters
- **Readiness**: a single label like `ready` meaning "well-formed enough to start." This one matters
most in the AI era: it's the signal that an issue has clear acceptance criteria and can be handed
off, to a person *or* an agent, without more discussion.
Resist label sprawl. If a label never changes how you filter or who picks up the work, delete it.
Five well-chosen labels beat thirty that no one trusts.
### Assignment routing the work to one owner
### Assignment: routing the work to one owner
Labels describe; **assignment routes.** Assigning an issue puts one name on it: the owner, the
person (or agent) the rest of the team can assume is handling it. The discipline that matters is
*one* owner an issue assigned to three people is assigned to no one. Unassigned-but-`ready` is a
*one* owner; an issue assigned to three people is assigned to no one. Unassigned-but-`ready` is a
fine state too; it means "available, anyone can grab this."
This is the mechanic that turns a pile of issues into coordinated work, and it leads straight to the
point this module turns on.
### The roster is mixed now humans and agents
### The roster is mixed now: humans and agents
Here's the shift. The list of things you can assign an issue to used to be "the people on the team."
It increasingly includes **agents**. An issue can be routed to a person, or handed to an
issue-to-PR agent that reads the issue, makes the change on a branch, and opens it up for review.
(That agent is its own module **Module 25** and we are not building it here. The point now is
(That agent is its own module, **Module 25**, and we are not building it here. The point now is
only that it's a possible *assignee*, which changes how you write the issue.)
The exact mechanism varies and is still settling across forges: some let you assign an agent like a
user, some trigger it with a label, some kick it off from a comment or an external runner. Don't
anchor on the plumbing. Anchor on this: **the well-formed issue is the one interface that works for
every assignee on the roster.** A human and an agent need the same things from an issue a clear
every assignee on the roster.** A human and an agent need the same things from an issue: a clear
title, real context, and acceptance criteria that define done. Write it well and you've written it
for both.
@@ -174,7 +174,7 @@ reproducible, testable.
risk.** "Add due dates" sounds small but isn't: what date format does the user type? Does the list
re-sort by date? How are overdue tasks shown, and in whose timezone? Those are product decisions an
agent will *answer confidently and probably wrongly*, because nothing in the issue tells it the
right call. A human resolves the ambiguity first (often by splitting it into clear sub-issues at
right call. A human resolves the ambiguity first (often by splitting it into clear sub-issues, at
which point the pieces may become agent-ready).
Notice the heuristic doesn't ask how smart the model is. It asks how well-specified the *work* is.
@@ -187,7 +187,7 @@ matching the clarity of the issue to the autonomy of the assignee.
This module produces the input to a loop you'll complete later. An issue is the start; the rest is:
- An assignee (human or agent) takes the issue, branches (Module 6), does the work, and opens it for
review as a pull request (**Module 10**), which gets merged and **closes the issue** the full
review as a pull request (**Module 10**), which gets merged and **closes the issue**; the full
coordination loop is **Module 11**.
- Agents can also work the *intake* side: triaging, labeling, and routing incoming issues with a
human still deciding (**Module 24**), or taking an assigned issue all the way to a PR (**Module
@@ -203,7 +203,7 @@ The issue tracker itself isn't new. What's changed is that **the issue is now an
specification**, and that raises the stakes on writing it well in three concrete ways:
- **Acceptance criteria are the agent's definition of done.** A human reads fuzzy criteria and fills
the gaps with judgment. An agent reads them literally and stops when they're satisfied so vague
the gaps with judgment. An agent reads them literally and stops when they're satisfied, so vague
criteria produce work that's technically complete and actually wrong. The same criteria also become
the basis for the test you'll write (Module 13) and the thing you check in review (Module 10). One
well-written checklist pays out three times.
@@ -212,7 +212,7 @@ specification**, and that raises the stakes on writing it well in three concrete
confident, plausible, wrong PR that costs more to review than the work would have taken. The cheap
insurance is the clarity you put in *before* assigning.
- **Your committed config plus the issue is the whole brief.** Module 5's instructions file carries
the standing context conventions, build and test commands, what not to touch. The issue carries
the standing context: conventions, build and test commands, what not to touch. The issue carries
the specific task. Together they're enough for an agent to attempt the work with no live
conversation at all. That's the pairing that makes routing-to-an-agent viable, and it's why both
artifacts have to be good.
@@ -234,32 +234,32 @@ part that matters, separate from the mechanical step of turning a draft into a f
**You'll need:**
- Your `tasks-app` repo on a forge (Module 8), with its issue tracker enabled. Most forges turn
issues on by default, but not all of them do consistent with the "the feature set varies" caveat
issues on by default, but not all of them do, consistent with the "the feature set varies" caveat
above. Bitbucket Cloud's tracker is off until you enable it, Azure DevOps uses Boards/Work Items
rather than an Issues tab, and SourceHut uses a separately provisioned `todo.sr.ht` tracker. If you
took the forge-agnostic path, confirm yours has issues available before Part C.
- The starter files in this module's `lab/` folder:
- `issue-template.md` the well-formed-issue skeleton to copy for each issue.
- `example-issues.md` three worked issues for `tasks-app`, as a reference/answer key.
- `issue-template.md`: the well-formed-issue skeleton to copy for each issue.
- `example-issues.md`: three worked issues for `tasks-app`, as a reference/answer key.
- Claude Code (or your own CLI/in-editor agent from Module 4), pointed at the `tasks-app` repo. It
can read the code directly to ground each issue's context, and create the issues on your forge once
you've drafted them.
### Part A Find the work
### Part A: Find the work
Look at the `tasks-app` and find three real pieces of work. The app is deliberately thin, so there's
plenty it still can't do. Because it's carried forward across modules, skip anything you may have
already built (a `delete` command, task priorities) and pick work that's genuinely still missing.
Good candidates:
1. **A bug** `python cli.py done 99` (an out-of-range index) and `python cli.py done abc` (a
1. **A bug**: `python cli.py done 99` (an out-of-range index) and `python cli.py done abc` (a
non-integer) both crash with an uncaught traceback. Run them and watch.
2. **A small, patterned feature** an `undone <index>` command that clears a task's done flag,
2. **A small, patterned feature**: an `undone <index>` command that clears a task's done flag,
mirroring the existing `done` command (it's the inverse).
3. **A judgment-heavy feature** due dates on tasks (date format? sorting? overdue display?
3. **A judgment-heavy feature**: due dates on tasks (date format? sorting? overdue display?
storage?).
### Part B Draft three well-formed issues
### Part B: Draft three well-formed issues
For each, copy `lab/issue-template.md` to its own file (say `issue-bug.md`, `issue-undone.md`,
`issue-due-dates.md`) and fill every section: title, context (with repro steps for the bug),
@@ -270,7 +270,7 @@ criteria against the actual code, then **edit them down**. The model tends to ov
tightening its draft is exactly the skill. Check your drafts against `lab/example-issues.md` only
after you've written your own.
### Part C Create, label, and route
### Part C: Create, label, and route
You've done the thinking; turning three Markdown drafts into real issues with labels is mechanical
forge work, so hand it to the agent and verify the result. From the repo, ask Claude Code (or your
@@ -296,25 +296,25 @@ the mechanical work, you confirm it landed.
Write one sentence in each issue, or a scratch note, explaining **why** it went where it went, in
terms of the issue's clarity rather than the model's smarts. That sentence is the routing skill.
### Part D Read the backlog cold
### Part D: Read the backlog cold
Open your forge's issue list and filter by your `ready` label. You should be looking at exactly the
work that's pickable right now, by anyone or anything. That filtered view is the shared task memory
from the reframe the thing a new teammate or a fresh agent reads to learn the work, with no one
from the reframe: the thing a new teammate or a fresh agent reads to learn the work, with no one
explaining anything.
---
## Where it breaks
The honest caveats issues are not the repo, and they don't behave like it:
The honest caveats: issues are not the repo, and they don't behave like it:
- **Issues lie when they go stale; git doesn't.** The repo is ground truth by construction it *is*
- **Issues lie when they go stale; git doesn't.** The repo is ground truth by construction; it *is*
the code. An issue is a *claim* about work, and a claim rots. A backlog full of issues that were
fixed months ago, or describe a version of the app that no longer exists, is worse than no backlog,
because people (and agents) trust it. Closing issues is as much a discipline as opening them.
- **Acceptance criteria can't capture genuine ambiguity.** The whole "agent-ready vs. human" split
assumes you *can* write clear criteria. For real design problems you can't yet that's not a
assumes you *can* write clear criteria. For real design problems you can't yet; that's not a
writing failure, it's the nature of the work. Forcing crisp criteria onto an open question just
hides the question. Those issues stay with a human until the ambiguity is resolved.
- **Routing to an agent is delegation, not abdication.** Handing an issue to an agent doesn't mean
@@ -325,7 +325,7 @@ The honest caveats — issues are not the repo, and they don't behave like it:
- **Label and assignment models differ across forges.** There's no cross-forge standard. Some allow
multiple assignees, some one; label and permission systems vary; "assign an issue to an agent" is
an emerging capability implemented differently everywhere it exists at all. Keep your taxonomy
small and portable so it survives a forge change don't build a workflow that depends on one
small and portable so it survives a forge change; don't build a workflow that depends on one
vendor's exact issue fields.
- **Over-tooling a tiny project is its own failure.** A solo throwaway script does not need a labeled,
prioritized backlog. Issues pay off when work is shared: across people, across agents, or across
@@ -338,23 +338,23 @@ The honest caveats — issues are not the repo, and they don't behave like it:
**You're done when:**
- You have **three well-formed issues** on your forge for `tasks-app`, each with a title, context,
and concrete acceptance criteria not a one-line "fix the thing."
and concrete acceptance criteria, not a one-line "fix the thing."
- Each issue carries a small, sensible label set, and at least one is marked `ready`.
- At least one issue is **routed to a human** and at least one is **earmarked for an agent**, and you
can state the routing reason in terms of the issue's clarity and scope not the model's
can state the routing reason in terms of the issue's clarity and scope, not the model's
intelligence.
- You can explain why issues are *shared task memory* and how that complements (rather than
duplicates) the repo-as-memory idea from Module 2.
When a stranger could pick up any of your `ready` issues and start without asking you a single
question, you've written them well and that's exactly what Module 10 (reviewing the resulting
question, you've written them well, and that's exactly what Module 10 (reviewing the resulting
change) and Module 11 (closing the loop) are about to build on.
---
## Verify-before-publish
Mostly durable issues are a stable concept on every forge but one part of this module sits on
Mostly durable (issues are a stable concept on every forge), but one part of this module sits on
moving ground:
- [ ] **Agent-as-assignee mechanics.** How you route an issue to an agent (native agent assignee,
@@ -362,5 +362,5 @@ moving ground:
that the lab's "earmark for an agent" step still matches what at least one mainstream forge
actually offers, and keep the wording mechanism-agnostic if it's still in flux.
- [ ] **Forge issue terminology and label/assignee limits** (single vs. multiple assignees, built-in
vs. custom labels) — confirm the neutral descriptions still hold across the forges named in
vs. custom labels). Confirm the neutral descriptions still hold across the forges named in
Module 8.
@@ -1,8 +1,8 @@
<!--
Worked example issues for the tasks-app Module 9 of "The Workflow".
Worked example issues for the tasks-app, Module 9 of "The Workflow".
These are a reference / answer key. Write your OWN three issues from issue-template.md FIRST, then
compare. Yours don't need to match word for word check that each has a specific title, real
compare. Yours don't need to match word for word; check that each has a specific title, real
context (with repro for the bug), concrete acceptance criteria, and a stated scope.
Note how the routing call is a property of the ISSUE (clear vs. ambiguous), not the model.
@@ -12,7 +12,7 @@
deliberately target work the app does NOT have yet, so each reads as a genuine open issue.
-->
# Issue 1 bug route to AGENT
# Issue 1: bug, route to AGENT
# Title: `done` command crashes on an out-of-range or non-integer index
@@ -33,8 +33,8 @@ python cli.py done abc # ValueError traceback
## Acceptance criteria
- [ ] `done <index>` with an out-of-range index prints a clear message (e.g. `no task at index 99`)
and exits non-zero no traceback.
- [ ] `done <non-integer>` prints a clear message and exits non-zero no traceback.
and exits non-zero, with no traceback.
- [ ] `done <non-integer>` prints a clear message and exits non-zero, with no traceback.
- [ ] A valid `done <index>` still marks the task done exactly as before.
## Out of scope
@@ -45,17 +45,17 @@ Changing how tasks are stored, numbered, or displayed.
- **Type:** bug
- **Priority:** high
- **Ready:** yes
- **Route to:** agent — contained, reproducible, and verifiable in seconds; clear acceptance criteria
- **Route to:** agent. Contained, reproducible, and verifiable in seconds; clear acceptance criteria
mean an agent's first pass is very likely correct.
# Issue 2 feature route to AGENT
# Issue 2: feature, route to AGENT
# Title: Add an `undone <index>` command to mark a completed task as not done
## Context / problem
You can mark a task `done`, but there's no way to undo it flag the wrong index by mistake and the
You can mark a task `done`, but there's no way to undo it; flag the wrong index by mistake and the
only "fix" is to delete the task and re-add it. The command should mirror the existing `done <index>`
command, which already takes an index and flips a task's state; this is simply its inverse.
@@ -73,38 +73,38 @@ A general multi-step undo / command history (separate concern). Changing the sto
## Proposed approach (optional)
Add a `reopen(index)` method on `TaskList` in `tasks.py` the inverse of the existing `complete`
Add a `reopen(index)` method on `TaskList` in `tasks.py` (the inverse of the existing `complete`)
and wire an `undone` branch in `cli.py`, parallel to the existing `done` handling.
---
- **Type:** feature
- **Priority:** med
- **Ready:** yes
- **Route to:** agent — well-scoped and patterned directly on existing code (the inverse of `done`);
- **Route to:** agent. Well-scoped and patterned directly on existing code (the inverse of `done`);
low ambiguity, easy to verify.
# Issue 3 feature route to HUMAN
# Issue 3: feature, route to HUMAN
# Title: Support due dates on tasks
## Context / problem
Users want to attach a due date to a task so the list can reflect what's coming up, not just what
exists. Today a task is only a title and a done flag. This is desirable but underspecified several
exists. Today a task is only a title and a done flag. This is desirable but underspecified; several
product decisions have to be made before any code is written.
Open questions (resolve before this is `ready`):
- What date format does the user type, and how forgiving is parsing? (ISO `2026-06-30` only, or
relative like `tomorrow` / `friday`?)
- Does `list` re-sort by due date, group by it, or just display it inline?
- How is a due date set at `add` time (a flag?) or with a separate command? Can it be cleared?
- How are overdue tasks surfaced highlighted, flagged, sorted to the top and in whose timezone?
- How is a due date set: at `add` time (a flag?) or with a separate command? Can it be cleared?
- How are overdue tasks surfaced (highlighted, flagged, sorted to the top), and in whose timezone?
- How is it stored, and what's the default for the existing tasks that have none?
## Acceptance criteria
- [ ] (Cannot be written yet depends on the decisions above. Likely splits into 23 smaller,
- [ ] (Cannot be written yet; depends on the decisions above. Likely splits into 2-3 smaller,
agent-ready issues once the design is settled.)
## Out of scope
@@ -115,6 +115,6 @@ TBD until the design questions are answered.
- **Type:** feature
- **Priority:** low
- **Ready:** no
- **Route to:** human — genuine design ambiguity. An agent would answer these questions confidently
- **Route to:** human. Genuine design ambiguity. An agent would answer these questions confidently
and probably wrongly. A person decides the design, then splits this into clear sub-issues (which
may then be agent-ready).
@@ -1,5 +1,5 @@
<!--
Well-formed issue skeleton Module 9 of "The Workflow".
Well-formed issue skeleton for Module 9 of "The Workflow".
Copy this for each issue you draft. Fill every section. Write it for a STRANGER: a teammate you've
never met, future-you who's forgotten, or an agent with no memory. Delete these comments as you go.
@@ -9,17 +9,17 @@
below is what matters and ports anywhere.
-->
# Title: <specific, scannable someone reading 40 titles should know what this is>
# Title: <specific, scannable; someone reading 40 titles should know what this is>
## Context / problem
<What is wrong or missing, and WHY it matters.
- For a bug: the exact command you ran, what happened, and what you expected.
- For a feature: the motivation what the user can't do today.>
- For a feature: the motivation, i.e. what the user can't do today.>
## Acceptance criteria
<The checklist that defines DONE. Concrete and verifiable. This is the most important section
<The checklist that defines DONE. Concrete and verifiable. This is the most important section:
it is the definition of done for a human AND the spec for an agent.>
- [ ] <verifiable statement, e.g. "`done 99` prints a clear error and exits non-zero">
@@ -41,4 +41,4 @@
- **Type:** bug | feature | chore
- **Priority:** high | med | low
- **Ready:** yes/no (acceptance criteria solid enough to start?)
- **Route to:** human | agent — and one sentence on WHY (in terms of the issue's clarity/scope)
- **Route to:** human | agent, plus one sentence on WHY (in terms of the issue's clarity/scope)