@haus-tech/haus-workflow 4.3.0 → 4.5.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/CHANGELOG.md +20 -0
- package/README.md +13 -15
- package/dist/cli.js +14 -1
- package/library/global/skills/haus-workflow/SKILL.md +162 -185
- package/library/global/skills/haus-workflow/references/clone.md +191 -0
- package/library/global/skills/haus-workflow/references/new.md +15 -0
- package/library/global/skills/request-assess-impact/SKILL.md +45 -1
- package/library/global/skills/request-score/SKILL.md +285 -0
- package/library/global/skills/request-score/references/poangskala.md +1288 -0
- package/library/global/skills/request-sync/SKILL.md +169 -57
- package/package.json +1 -1
- package/library/global/skills/haus-workflow/references/cloneandsetup.md +0 -172
|
@@ -14,6 +14,13 @@ whenever this procedure is reached with **no name** — whether from the no-arg
|
|
|
14
14
|
no argument — do **not** silently fall through to Mode B (workspace); ask first, via
|
|
15
15
|
`AskUserQuestion`:
|
|
16
16
|
|
|
17
|
+
**Skip this question when `SKILL.md`'s Step 1.5 already determined the cwd is Workspace
|
|
18
|
+
scope** (a `haus.workspace.yaml`/`repos.manifest.json` already exists at the git root) —
|
|
19
|
+
in that case go straight to Mode B (unless a `name` was already given, in which case Mode
|
|
20
|
+
A takes over as usual). Asking "single repo or whole workspace?" again here would
|
|
21
|
+
contradict a scope Step 1.5 already resolved. Only ask below when Step 1.5 found Project
|
|
22
|
+
or Not-set-up scope (or no scope check ran, e.g. reached from an older caller).
|
|
23
|
+
|
|
17
24
|
```
|
|
18
25
|
"Clone a single repo, or a whole workspace?"
|
|
19
26
|
Options:
|
|
@@ -63,3 +70,187 @@ Clone a whole **workspace** from its manifest. Workspace-only (a `repos.manifest
|
|
|
63
70
|
**Transport fallback.** Manifest URLs may be SSH (`git@github.com:org/repo.git` or `ssh://…`). Probe SSH connectivity once up front (`ssh -T git@github.com`); if it fails, **auto-fall back to the HTTPS URL** (`https://github.com/org/repo.git`) using your `gh auth` credentials, clone over HTTPS, and **report that you switched transport** so the user knows their SSH is down. Don't halt the run for an SSH outage when HTTPS works.
|
|
64
71
|
|
|
65
72
|
7. After the loop, report which repos were cloned, reused (local), skipped (already present), and failed. Remind the user that installing dependencies and configuring each repo (`.env`, services) is still a manual step for now.
|
|
73
|
+
|
|
74
|
+
## Local-dev setup (optional)
|
|
75
|
+
|
|
76
|
+
**Always ask before doing this work — never assume.** Everything from here through Step 4
|
|
77
|
+
hits the network, needs auth, and can touch databases; confirm before each phase, and
|
|
78
|
+
respect repos the user already has.
|
|
79
|
+
|
|
80
|
+
Use `AskUserQuestion`:
|
|
81
|
+
|
|
82
|
+
```
|
|
83
|
+
"Set the cloned repo(s) up for local dev too?"
|
|
84
|
+
Options:
|
|
85
|
+
1. Yes
|
|
86
|
+
2. No
|
|
87
|
+
```
|
|
88
|
+
|
|
89
|
+
The `cloneandsetup` and `project:cloneandsetup` aliases pre-answer **Yes** — when reached
|
|
90
|
+
via one of those aliases, **skip this `AskUserQuestion` call entirely** and carry the
|
|
91
|
+
resulting repo list straight into Step 1 below. On a bare **No** answer (not via one of
|
|
92
|
+
those aliases), stop after the clone report. On a manual **Yes**, carry the resulting repo
|
|
93
|
+
list into the setup phases below.
|
|
94
|
+
|
|
95
|
+
### Step 1 — Prerequisite gate (one consolidated check)
|
|
96
|
+
|
|
97
|
+
Before any setup work, probe **everything** the workspace will need and surface **all** gaps in a single prompt — never discover them piecemeal mid-flow. For the repos being set up, check:
|
|
98
|
+
|
|
99
|
+
- **Auth tokens** — `NODE_AUTH_TOKEN` exported (private `@`-scoped npm packages fail without it); `~/.composer/auth.json` (or a repo-local `auth.json`) present if any repo has private composer deps.
|
|
100
|
+
- **Docker daemon** — running (`docker info`); required for any repo's `needs:` services.
|
|
101
|
+
- **PHP environment** — `valet`, `herd`, `ddev`, or `php` on PATH, if any repo is a PHP/WordPress site.
|
|
102
|
+
- **WP-CLI** — `wp --version`, if any repo's `seed:` pulls a WordPress DB.
|
|
103
|
+
- **Node versions** — the versions named in each repo's `.nvmrc` / `engines.node` are installable via `nvm`.
|
|
104
|
+
- **Data-access preflight** — for every data load the workspace will run (each repo's `seed` **and** the workspace `seeds`), check up front that the user can actually reach the source, so nobody ends up with a half-set-up environment that only fails at the seed step. See below.
|
|
105
|
+
|
|
106
|
+
#### Data-access preflight
|
|
107
|
+
|
|
108
|
+
The single most common way cloneAndSetup leaves a **half-completed environment** is discovering at the `seed:` step — after cloning, installing, and bringing up services — that the user lacks the AWS/SSH/etc. access to pull the data. Catch it **here**, before any heavy work, and make the data outcome a deliberate choice.
|
|
109
|
+
|
|
110
|
+
1. **Collect every seed:** each repo's `seed` plus the workspace `seeds`. For each, determine its required access:
|
|
111
|
+
- If `seed` is an **object with `access`**, run each entry's `check` (a read-only probe; exit 0 = reachable).
|
|
112
|
+
- If `seed` is a **bare string**, infer the channel and probe generically: `aws …`/SSM → `aws sts get-caller-identity`; `dep db:pull …` / `ssh`/`scp`/`rsync <user@host>` → `ssh -o BatchMode=yes -o ConnectTimeout=5 <host> true`; `northflank …` → `northflank whoami`. A purely local seed (no remote) needs nothing.
|
|
113
|
+
2. **Report one table** alongside the rest of the gate — per data source: its `label`, the access it needs, and ✓ reachable / ✗ + the `login` remedy (verbatim).
|
|
114
|
+
3. **Resolve every ✗ with one consolidated choice**, then remember it for the run:
|
|
115
|
+
- **Set up access now** → print the `login` text, let the user do it, **re-check**, then seed normally.
|
|
116
|
+
- **Create that DB EMPTY for now** (only when `empty-ok` is true — the default) → the datastore comes up empty (schema via migrations/`needs:`), the app still boots, and the user can run that one seed later. Name the exact command to fill it.
|
|
117
|
+
- **Abort.**
|
|
118
|
+
4. **Only a gap on a seed with `empty-ok: false` is a HARD STOP** (the repo is genuinely broken without data — log in or abort). Every other gap offers the empty path; one source's missing access never blocks another's.
|
|
119
|
+
|
|
120
|
+
This is the one prompt the "no half-completed environment" goal justifies. The two valid end-states are **seeded** or **deliberately empty** — never a third "did the expensive work then died at seed."
|
|
121
|
+
|
|
122
|
+
Then list the repos and what each will run (node, deps, localdev steps, **data sources + the chosen seed/empty plan**), **report every gap at once**, and get a single go-ahead. For **reused** local clones, ask whether to re-run setup. For each gap, name what it blocks; the user decides whether to fix it now (**ask before any global/system install**) or proceed and skip the affected steps. Don't begin per-repo work until this gate is acknowledged.
|
|
123
|
+
|
|
124
|
+
### Step 2 — Per-repo dependency pass
|
|
125
|
+
|
|
126
|
+
For each repo, in its own directory, detect and install from the repo's own files (read its `docs/setup.md` / `CLAUDE.md` / `README.md` first — they win). Select node from `.nvmrc`/`engines.node` (`nvm install`), enable the pinned package manager (`corepack enable`), install JS deps (`yarn`/`pnpm`/`npm` by lockfile), composer deps if `composer.json` + `composer` present. Run each repo's steps in one login shell so the node version stays active. Per-repo failure is reported and skipped, not fatal.
|
|
127
|
+
|
|
128
|
+
**Leave `.env` to Step 3 → "Env".** The dependency pass installs only; the env phase writes each repo's `.env` deterministically once services, links, and values are in place.
|
|
129
|
+
|
|
130
|
+
### Step 3 — Local-dev orchestration
|
|
131
|
+
|
|
132
|
+
This is the phase that takes the workspace from "installed" to "ready to run." It is driven by `localdev.yml` files; a repo with none is set up by Step 2 only.
|
|
133
|
+
|
|
134
|
+
#### House conventions (the "how", so repos specify only the "what")
|
|
135
|
+
|
|
136
|
+
Specify the least. Infer the rest from the repo's stack + these conventions, and work out the concrete commands at run time:
|
|
137
|
+
|
|
138
|
+
- **IMPORTANT — never install anything without asking first; global/system tools especially** (Homebrew, Docker, Laravel Herd, global `npm`/`composer` packages). Detect what's already present; if something required is missing, name it, say why it's needed, and get an explicit **yes** before installing. Prefer the least-invasive option, and don't switch or override tools the dev already has.
|
|
139
|
+
- **PHP / WordPress sites are served by the developer's own PHP environment.** If they already have one — detect `valet`, `herd`, `ddev`, or `php` on PATH — **use it**: just satisfy the env contract (docroot → the repo's `web/`, HTTPS) and report the URL; never override what they already run. **Only when no local PHP environment exists** (a completely fresh machine) suggest installing **[Laravel Herd](https://herd.laravel.com)** as the default (asking first) and point its docroot at `web/` + `herd secure`.
|
|
140
|
+
- **Databases and other services (a repo's `needs:`) run in Docker as a shared, workspace-owned `docker-compose` project** — grouped and self-contained (`up`/`down` together, named volumes), namespaced per workspace instance via `COMPOSE_PROJECT_NAME` + its own host ports so the workspace can run multiple times side by side. Image/port/env per the house convention (`mysql:8`, `postgres:16`, …). Don't reuse a repo's own compose that bind-mounts repo-relative init files (`seed.sql`) — author the service in the workspace compose. Services come up **empty** (seeding is the separate `seed:` step); record chosen host ports in the workspace `localdev.yml` `env` map.
|
|
141
|
+
- **Dependencies** install from the lockfile (Step 2).
|
|
142
|
+
- A repo's `localdev.yml` carries **only what can't be inferred** — its `needs`, repo-specific `build`/`seed` commands, env keys, and URL. Detect the stack (e.g. Bedrock = `composer.json` + `web/` docroot + `wp-cli.yml`; Vendure/Node = `docker-compose.yml` + `@vendure/*`) and apply the matching convention.
|
|
143
|
+
|
|
144
|
+
#### The `localdev.yml` format
|
|
145
|
+
|
|
146
|
+
**Per-repo — `<repo>/.haus-workflow/localdev.yml`** (how to set up THAT repo alone; sibling-agnostic):
|
|
147
|
+
|
|
148
|
+
All fields optional. **Prefer intent (`needs`/`build`/`seed`/`serve`) over explicit `steps`** —
|
|
149
|
+
the conventions above turn intent into commands.
|
|
150
|
+
|
|
151
|
+
```yaml
|
|
152
|
+
needs: [mysql] # services this repo requires; provisioned in Docker, env wired to them
|
|
153
|
+
needsEnv: [WP_HOME, DB_NAME] # env keys that must be present to run/serve
|
|
154
|
+
build: 'yarn build' # optional: the build command (run after deps)
|
|
155
|
+
seed: 'dep db:pull staging-oderland' # optional: how to load data; remote/destructive → confirm first
|
|
156
|
+
# `seed` may also be an OBJECT when the load needs external access (AWS, SSH, …) so the
|
|
157
|
+
# Step-1 data-access preflight can check it up front and offer an empty-DB fallback:
|
|
158
|
+
seed:
|
|
159
|
+
run: './scripts/pull-aws-db.sh --yes' # the seed command
|
|
160
|
+
empty-ok: true # default true: skipping yields a coherent EMPTY DB (schema via migrations).
|
|
161
|
+
# # false = the repo is broken without data → a missing-access gap HARD-STOPS.
|
|
162
|
+
access: # what the user must have to run `run`; each entry probed in the Step-1 preflight
|
|
163
|
+
- label: 'AWS CLI credentials — eu-north-1 / 842675986884'
|
|
164
|
+
check: 'aws sts get-caller-identity --region eu-north-1' # read-only probe; exit 0 = OK
|
|
165
|
+
login: 'Set up the AWS CLI (brew install awscli; aws configure …) — or pick empty DB.'
|
|
166
|
+
serve: # optional: how it runs (printed as a next-step, never auto-started)
|
|
167
|
+
via: herd # herd | valet | docker | command — for PHP envs, bring-your-own (don't install)
|
|
168
|
+
url: 'https://example.test'
|
|
169
|
+
start: 'yarn dev'
|
|
170
|
+
steps: # optional escape hatch: explicit ordered shell steps when intent isn't enough
|
|
171
|
+
- run: 'composer install'
|
|
172
|
+
node: 10 # nvm version for THIS step
|
|
173
|
+
remote: true # SSH → confirm first
|
|
174
|
+
destructive: true # overwrites data → confirm first
|
|
175
|
+
optional: true # failure is non-fatal, continue
|
|
176
|
+
```
|
|
177
|
+
|
|
178
|
+
**Workspace — `<workspace>/.haus-workflow/localdev.yml`** (the glue BETWEEN repos):
|
|
179
|
+
|
|
180
|
+
The workspace `env` map is the **single source of truth for cross-repo values** — DB names, ports, host URLs are chosen once and recorded here as literals. The env phase reads values **from here** and writes them into each repo's `.env`. Recording them here (not only in a repo's `.env`) means a later `seed:` / `db:pull` step can find them without depending on env-file load order.
|
|
181
|
+
|
|
182
|
+
```yaml
|
|
183
|
+
order: [repo-a, repo-b] # setup/startup order, by manifest id
|
|
184
|
+
links:
|
|
185
|
+
- { type: symlink, from: <repo-folder>, to: <repo-folder>/path/to/link }
|
|
186
|
+
- { type: composer-path, in: <repo>, dep: <sibling-repo> }
|
|
187
|
+
- { type: yarn-link, in: [<repo>, ...], dep: <sibling-package-repo> }
|
|
188
|
+
env:
|
|
189
|
+
- value: 'app_local' # a chosen literal — the recorded source of truth, OR …
|
|
190
|
+
# source: { repo: <repo>, provides: '<value>' } # … a value produced by another repo
|
|
191
|
+
sinks:
|
|
192
|
+
- { repo: <repo>, key: DB_NAME } # written under `key` into each sink's .env
|
|
193
|
+
seeds: # optional: data sources NOT owned by a manifest repo (e.g. a shared WordPress host
|
|
194
|
+
# pulled by a workspace script). Same shape as a per-repo `seed` object; included in
|
|
195
|
+
# the Step-1 data-access preflight.
|
|
196
|
+
- label: 'WordPress host (example.se)'
|
|
197
|
+
run: './scripts/pull-wp-example.sh'
|
|
198
|
+
empty-ok: true
|
|
199
|
+
access:
|
|
200
|
+
- label: 'SSH user@host'
|
|
201
|
+
check: 'ssh -o BatchMode=yes -o ConnectTimeout=5 user@host true'
|
|
202
|
+
login: 'Add your SSH key to the host (ssh-add …) / request access — or skip the pull.'
|
|
203
|
+
```
|
|
204
|
+
|
|
205
|
+
#### Run order
|
|
206
|
+
|
|
207
|
+
1. **Discover** `.haus-workflow/localdev.yml` in the workspace root and each repo.
|
|
208
|
+
2. **Resolve order** from the workspace `order` (repos not listed run last, in manifest order). No workspace file → manifest order.
|
|
209
|
+
3. **Per repo, in order**, apply intent via the conventions:
|
|
210
|
+
- **`needs`** → add the service to the **workspace compose project** and `docker compose up -d` if not already running (namespaced by `COMPOSE_PROJECT_NAME`, free host ports per instance; not the repo's own bind-mounting compose). Comes up **empty**; record host ports in the workspace `localdev.yml` `env` map — data lands in `seed:`.
|
|
211
|
+
- **`build`** → run it (honor any node version the repo's docs note).
|
|
212
|
+
- **`serve`** → for `via: herd` / PHP envs, install nothing — verify the dev's environment serves `web/`, and report the URL.
|
|
213
|
+
- **`seed`** → populate the empty datastore (`seed.run`, or the bare-string form). **Always a distinct, confirm-gated step, separate from `needs:` bring-up** (don't conflate "DB up" with "DB has data"). **Honor the data plan chosen in the Step-1 data-access preflight** — don't re-discover access here: if the user chose _empty_ for this source, skip it (the DB stays empty, schema via migrations) and print the command to fill it later; if they chose _seed_, run it. Still verify the run-time prerequisites the preflight couldn't (the target repo's **`.env` written** — done in the Env step above; WP-CLI present for `wp`/`db:pull` seeds) and **confirm first** for every remote (SSH/AWS) or destructive (overwrites data) seed — every run, even on re-run. Missing prerequisite → skip with a clear message, don't guess.
|
|
214
|
+
- **`steps`** (escape hatch) → run in order, selecting `node:` per step, `optional:` failures continue, **confirming before any `remote:`/`destructive:` step** — every run, even on re-run.
|
|
215
|
+
4. **Links** (workspace-owned, performed generically — do NOT call a repo's own `setup-dev-mode.sh`, which is deprecated):
|
|
216
|
+
- `symlink` → `ln -s <from> <to>`; replace an existing symlink, but never clobber a real directory without confirmation.
|
|
217
|
+
- `composer-path` → in `in`'s `composer.json`, set the `dep`'s require to `{ "type": "path", "url": "../<dep-folder>", "options": { "symlink": true } }`, then `composer update <vendor/dep>`.
|
|
218
|
+
- `yarn-link` → `yarn link` in the `dep` repo, then `yarn link <pkg-name>` in each `in` repo (read `<pkg-name>` from the dep's `package.json`).
|
|
219
|
+
5. **Env (deterministic):** write each repo's `.env` from known values — no improvising.
|
|
220
|
+
1. **Compute** each repo's values, in this precedence: the workspace `localdev.yml` `env` map (chosen literals + cross-repo `source` values — the single source of truth) → generated secrets (DB passwords/tokens minted this run) → **a value already present locally** in a sibling repo's `.env.example` / `.env` (matched by key, or by the same value under a framework-prefix swap `MIX_` ↔ `VITE_` ↔ `NEXT_PUBLIC_` ↔ `REACT_APP_`) — reuse it: it is already on the machine, so copying it into this repo's local (gitignored) `.env` adds nothing new to git → the **dev-defaults table** below for anything still unset.
|
|
221
|
+
2. **Write** them into each repo's `.env` (create it if absent; **upsert** keys, never clobbering a value the user already set). These are local dev files — write them directly.
|
|
222
|
+
3. **Secrets that exist nowhere locally** (third-party API keys, prod credentials, license keys the machine doesn't already have — §1 reuse only applies when the value is present locally) can't be invented, so the flow **explicitly tells the user it needs them** — never silently leaving a blank and proceeding as if set up. Put each in as a clearly-marked `KEY=` blank and report it, naming **which key**, **what it unlocks** (the step or feature that fails without it), and **how to get it manually**: from the provider's own account/dashboard (e.g. the Laravel Nova licence page, the Mediaflow API account), by copying it from the deployed environment's env vars (the server / hosting config), or by asking a colleague who already has it. **NEVER write a secret value into a git-tracked file:** `.env` writes are local and gitignored (fine — reuse freely), but the workspace `localdev.yml` `env` map is committed, so it carries non-secret cross-repo literals only (DB names, ports, host URLs), never credentials. Report all blanks together as one actionable list, not piecemeal.
|
|
223
|
+
|
|
224
|
+
**Dev-defaults table** — used only when neither `localdev.yml` nor a generated secret supplies the value:
|
|
225
|
+
|
|
226
|
+
| Key | Default |
|
|
227
|
+
| -------------------------------- | ------------------------------------------------------------------- |
|
|
228
|
+
| `DB_HOST` | `127.0.0.1` |
|
|
229
|
+
| `DB_PORT` | `3306` (mysql) / `5432` (postgres) — or the port chosen on conflict |
|
|
230
|
+
| `DB_USER` / `DB_PASSWORD` | `root` / a generated secret |
|
|
231
|
+
| `WP_HOME`, `WP_SITEURL`, `*_URL` | the repo's `serve.url` |
|
|
232
|
+
| `WP_ENV` / `APP_ENV` | `development` |
|
|
233
|
+
|
|
234
|
+
6. **Report, then offer to start.** Give the per-repo summary, then **ask the user whether to start everything now.**
|
|
235
|
+
- **Yes** → start each repo in the workspace `order` (its `serve.start`, e.g. `yarn dev`; bring up any remaining foreground services), run any follow-ups (e.g. `wp sync-products sync`), then **print the live URLs** (each repo's `serve.url`).
|
|
236
|
+
- **No** → just print the ordered start commands + follow-ups as next steps; start nothing.
|
|
237
|
+
|
|
238
|
+
**Default is "ready to run" (D2):** the preparation — datastores up (workspace `docker compose` project), seeds applied (confirm-gated), links, builds, each repo's `.env` written — always happens. Starting the **foreground** dev servers and the initial product sync happen **only if the user says yes** to the start prompt above; otherwise they're printed, not run.
|
|
239
|
+
|
|
240
|
+
### Step 4 — Report and define "done"
|
|
241
|
+
|
|
242
|
+
**"Done" is an explicit terminal state**, not "looks set up". The preparation reaches:
|
|
243
|
+
|
|
244
|
+
- datastores up (workspace `docker compose` project),
|
|
245
|
+
- dependencies installed and builds green,
|
|
246
|
+
- links wired,
|
|
247
|
+
- each repo's `.env` written from known values.
|
|
248
|
+
|
|
249
|
+
From there, **live URLs are reachable only if** every required secret is satisfiable **and** the user starts the servers. If a secret can't be minted (a third-party key, a prod credential), say exactly which keys are still blank and what the user must fill — don't imply links a missing secret will quietly break.
|
|
250
|
+
|
|
251
|
+
Summarise per repo (node, deps, localdev steps, links, env). Then **ask whether to start everything now**:
|
|
252
|
+
|
|
253
|
+
- **Yes** → start the dev servers in workspace `order`, run any follow-ups, and **print the live URLs** so the user can open the running app.
|
|
254
|
+
- **No** → print the ordered start commands + follow-ups instead, and start nothing.
|
|
255
|
+
|
|
256
|
+
Never start the app without that explicit yes.
|
|
@@ -10,6 +10,21 @@ the agent; collect answers with AskUserQuestion and pass everything as flags.
|
|
|
10
10
|
|
|
11
11
|
## Phase 0 — Entry
|
|
12
12
|
|
|
13
|
+
**Scope check first.** If `SKILL.md`'s Step 1.5 found the cwd is **Workspace** scope (or
|
|
14
|
+
**Member repo of a workspace** resolved to "Whole workspace"), ask via `AskUserQuestion`
|
|
15
|
+
before anything else: "Add the new project as a member of this workspace, or scaffold it
|
|
16
|
+
standalone elsewhere?"
|
|
17
|
+
|
|
18
|
+
- **Add as workspace member** — scaffold under the workspace root (default folder: the
|
|
19
|
+
project name, sibling to the other member repos) instead of the cwd. After Phase 3
|
|
20
|
+
creates the repo, tell the user to add an entry for it to `haus.workspace.yaml` /
|
|
21
|
+
`repos.manifest.json` themselves — this flow only scaffolds and does not write either
|
|
22
|
+
file (no CLI command mutates them yet).
|
|
23
|
+
- **Standalone** — proceed exactly as below, unaffected by the workspace.
|
|
24
|
+
|
|
25
|
+
Skip this ask entirely when Step 1.5 found Project or Not-set-up scope — proceed straight
|
|
26
|
+
to the rest of Phase 0.
|
|
27
|
+
|
|
13
28
|
A description argument ("a frontend app for shopping") goes straight to Phase 1.
|
|
14
29
|
No-argument invocation: ask "What do you want to build?" as free text. Do not present
|
|
15
30
|
a stack menu.
|
|
@@ -41,6 +41,11 @@ Befintligt mönster som återanvänds, eller något som inte finns idag. Namnge
|
|
|
41
41
|
**Verifiering**
|
|
42
42
|
Vad som kan bevisas automatiskt, och vad som kräver att en människa kör igenom det — i hur många scenarier, på hur många enheter, i hur många miljöer. Endast bygget. Kundens acceptanstest hör inte hit; skriv det inte ens som notering.
|
|
43
43
|
|
|
44
|
+
Skriv dessutom ut **om den berörda ytan har automatiska tester i dag**, och exakt vilken del som saknar dem. Det avgör om posten ska få en egen testpost, byggd före ändringen. Blanda inte ihop det med sådant som kräver en människa av sin natur — kontroll mot en extern tjänsts testläge, visuell granskning, flera enheter eller miljöer — det står kvar oavsett testsvit.
|
|
45
|
+
|
|
46
|
+
**Delbarhet**
|
|
47
|
+
Faller arbetet i delar som var för sig går att uppskatta? Ett kort svar räcker normalt: ja med delarna uppräknade i en mening, eller nej med skälet. Begär poängsättningen en uppdelning skrivs delarna ut fullständigt, se nedan.
|
|
48
|
+
|
|
44
49
|
**Konsekvens av fel**
|
|
45
50
|
Vad som händer i värsta fall om posten blir fel. Konkret, inte kategoriskt: "en notis visas i fel ordning" respektive "en användare ser en annan kunds order" är olika saker. Återanvänds befintlig säkerhets- eller behörighetsmekanik enligt etablerat mönster — skriv det, och skriv att det är etablerat.
|
|
46
51
|
|
|
@@ -55,6 +60,25 @@ Vad som måste vara klart först — andra poster, ramverk, tredje part.
|
|
|
55
60
|
|
|
56
61
|
Varje påstående ska vara belagt i koden eller specen. Kan du inte belägga något: skriv ordagrant att du inte kunnat verifiera det, och varför. Det är ett bättre utfall än en rad som ser säker ut — klassaren läser osäkerheten och eskalerar, och det är rätt.
|
|
57
62
|
|
|
63
|
+
## När poängsättningen begär en uppdelning
|
|
64
|
+
|
|
65
|
+
Kommer posten tillbaka med utfallet `DELA_UPP` gick den inte att ringa in mot skalan som helhet. Din uppgift är då att peka ut delarna. Poängsättningen får varken läsa repot eller skriva underlag, så den kan inte göra det själv.
|
|
66
|
+
|
|
67
|
+
**Skriv ut varje del med tre saker:** vad den omfattar, uttryckt som vilken del av specen den täcker; om den går att driftsätta och lämna i produktion på egen hand; och vad den delar med de övriga i fråga om manuell genomgång.
|
|
68
|
+
|
|
69
|
+
Den sista punkten avgör om uppdelningen är värd något. Kräver alla delar samma manuella genomgång av samma flöden i samma miljöer, så multipliceras det tyngsta arbetet av uppdelningen i stället för att delas. Skriv i så fall ut det.
|
|
70
|
+
|
|
71
|
+
**Två sorters delar, och de hamnar olika:**
|
|
72
|
+
|
|
73
|
+
- Går delen att leverera på egen hand blir den en **egen request**, med egen spec och egen leverans. Skriv det, men skriv inte specen — det är `request-write-spec` som gör det.
|
|
74
|
+
- Går den inte att leverera på egen hand blir den en **del av samma post**, som levereras tillsammans med resten.
|
|
75
|
+
|
|
76
|
+
**Delarna ärver postens spec och den här analysen.** Skriv ingen egen spec och ingen egen analys per del. Varje del får en omfattningsrad som säger vilken del av specen den täcker, och poängsätts mot det gemensamma underlaget. Kunden har beställt en sak; uppdelningen är intern struktur.
|
|
77
|
+
|
|
78
|
+
**Dela ett steg.** Kommer en del tillbaka och inte går att ringa in heller, ska den offereras — inte delas vidare. Delar man tills varje bit får plats under skalans tak blir summan för hög av skäl som inte har med arbetet att göra.
|
|
79
|
+
|
|
80
|
+
**Minst två delar.** Blir det bara en har posten inte delats, och då är svaret att den inte är delbar.
|
|
81
|
+
|
|
58
82
|
## Vägval
|
|
59
83
|
|
|
60
84
|
**Du beslutar, du frågar inte.** Ett vägval är en gaffel där båda vägarna fungerar. Du väljer och redovisar valet — det är därför steget klarar sig utan en människa, och det är också vad kunden betalar oss för.
|
|
@@ -90,9 +114,29 @@ Analysen som ett dokument, en sida. Sedan ett kort block till granskaren:
|
|
|
90
114
|
## Till granskaren
|
|
91
115
|
|
|
92
116
|
**Ej verifierat:** [vad du inte kunnat belägga i koden, och varför]
|
|
93
|
-
**Avvikelse mot specen:** [om koden säger något annat än specen förutsätter
|
|
117
|
+
**Avvikelse mot specen:** [om koden säger något annat än specen förutsätter]
|
|
118
|
+
**Obesvarade utfallsval:** [ett stycke per val — se nedan]
|
|
94
119
|
```
|
|
95
120
|
|
|
121
|
+
### Obesvarade utfallsval
|
|
122
|
+
|
|
123
|
+
Ett utfallsval som specen lämnat öppet skrivs ut med tre saker, och alla tre behövs:
|
|
124
|
+
|
|
125
|
+
1. **Vilka alternativen är.** Namnge dem, och var i koden vart och ett finns om de
|
|
126
|
+
bygger på något befintligt.
|
|
127
|
+
2. **Om alternativen skiljer sig i vad som måste byggas.** Skriv rakt ut "båda mönstren
|
|
128
|
+
finns redan, samma arbete oavsett" eller "det ena kräver att X också ändras". Det är
|
|
129
|
+
en observation om koden, inte en bedömning av omfattning — du skriver aldrig att
|
|
130
|
+
något är stort, litet, enkelt eller dyrt.
|
|
131
|
+
3. **Vilket alternativ analysen är skriven utifrån.** Du måste utgå från något för att
|
|
132
|
+
kunna beskriva systemet. Skriv "beskriven utifrån X", aldrig "vi väljer X" — valet
|
|
133
|
+
är inte ditt.
|
|
134
|
+
|
|
135
|
+
Skälet till punkt 2: den som poängsätter posten har inte repot och kan inte se om
|
|
136
|
+
alternativen kostar olika. Utan din rad måste den anta det värsta och stoppa posten,
|
|
137
|
+
även när båda vägarna är samma arbete. Det är den vanligaste orsaken till att en post
|
|
138
|
+
studsar tillbaka till specen i onödan.
|
|
139
|
+
|
|
96
140
|
Sista raden är den viktigaste. Förutsätter specen något som inte stämmer i systemet är det ett fel som ska tillbaka till specen, inte något som ska klassas.
|
|
97
141
|
|
|
98
142
|
## Vad du aldrig gör
|
|
@@ -0,0 +1,285 @@
|
|
|
1
|
+
---
|
|
2
|
+
name: request-score
|
|
3
|
+
description: Sätter poäng på en spec plus påverkansanalys genom att jämföra uppdraget mot en skala av sjutton referensuppdrag. Använd alltid när användaren vill "sätt poäng", "poängsätt", "kör poängen", "vad landar det här på", "var på skalan ligger det", eller när en spec har en påverkansanalys och ska prissättas. Används även som grind på en fullständig implementationsplan före första kodraden — "kör guarden", "stämmer poängen fortfarande". Använd den även när poängsättning bara antyds, t.ex. när någon klistrar in en spec med underlag och frågar hur stort det är. Output är JSON med poäng och belägg, aldrig ett pris.
|
|
4
|
+
---
|
|
5
|
+
|
|
6
|
+
# request-score
|
|
7
|
+
|
|
8
|
+
Du sätter poäng på en post genom att jämföra den mot referensuppdragen i
|
|
9
|
+
`references/poangskala.md`. Läs skalan innan du poängsätter första posten i en session.
|
|
10
|
+
|
|
11
|
+
**Går filen inte att läsa: poängsätt inte.** Säg att `references/poangskala.md` saknas
|
|
12
|
+
och att skillen inte kan köras utan den. Sätt aldrig en poäng på minnet av hur skalan
|
|
13
|
+
brukar se ut. Skalan ändras när nya referensuppdrag läggs till, och en poäng satt på
|
|
14
|
+
en gammal skala ser likadan ut som en satt på rätt skala.
|
|
15
|
+
|
|
16
|
+
**Du sätter aldrig pris.** Poäng blir pris genom en fast processavgift plus poängen
|
|
17
|
+
gånger en konverteringsfaktor, och det räknas någon annanstans. Ligger prislistan i
|
|
18
|
+
sammanhanget: använd den inte och säg till. Vet du vad poängen kostar drar du mot den
|
|
19
|
+
poäng som känns rimlig att ta betalt för, och då mäter du inte längre uppdraget.
|
|
20
|
+
|
|
21
|
+
**Du skriver aldrig underlaget.** Saknas spec eller påverkansanalys, avbryt med
|
|
22
|
+
`INPUT_SAKNAS`. Skriv inte en påverkansanalys själv — då jämför du din egen text mot
|
|
23
|
+
skalan, och belägget blir teater. `request-assess-impact` gör det, helst i en egen
|
|
24
|
+
körning.
|
|
25
|
+
|
|
26
|
+
**Ge inte dig själv repot i den här körningen.** Har du det börjar du verifiera saker
|
|
27
|
+
vid sidan av underlaget, och då poängsätter du inte längre det du fått. Saknas något i
|
|
28
|
+
underlaget är svaret låg konfidens, inte en egen efterforskning.
|
|
29
|
+
|
|
30
|
+
## Stoppfrågorna först
|
|
31
|
+
|
|
32
|
+
Poäng sätts bara på en post som går att bygga. Fyra utfall stoppar poängsättningen:
|
|
33
|
+
|
|
34
|
+
| Utfall | När | Vad som ska hända |
|
|
35
|
+
| -------------------- | ----------------------------------------------------------------------------------------------------- | ------------------------------------------------------------------- |
|
|
36
|
+
| `KONCEPT` | Formen är okänd — designfråga, oavgjort vägval, flera lösningsvägar utan beslut | Egen post som levererar ett förslag och en poäng på bygget |
|
|
37
|
+
| `DIAGNOS` | Orsaken är okänd och går att undersöka. Gäller framför allt fel där ingen vet varför något är trasigt | Tidsboxad undersökning som levererar besked och en poängsatt åtgärd |
|
|
38
|
+
| `TILLBAKA_TILL_SPEC` | Specen lämnar ett utfallsval obesvarat **och valet ändrar arbetsmängden** | Specen kompletteras, sedan ny körning |
|
|
39
|
+
| `DELA_UPP` | Posten går inte att ringa in på egen hand — se nedan | Ny analysrunda som pekar ut delarna, sedan en körning per del |
|
|
40
|
+
|
|
41
|
+
### När posten inte går att ringa in
|
|
42
|
+
|
|
43
|
+
Två lägen ger `DELA_UPP`:
|
|
44
|
+
|
|
45
|
+
- Du hittar inget tak, alltså inget referensuppdrag som posten säkert är mindre än.
|
|
46
|
+
- Golv och tak ligger långt isär och inget referensuppdrag finns emellan, alltså det
|
|
47
|
+
läge som annars bara hade gett `confidence: lag`.
|
|
48
|
+
|
|
49
|
+
Skriv i `notes` vilket av lägena det var, och vilka delar av påverkansanalysen som
|
|
50
|
+
pekar mot att posten rymmer flera skilda arbeten. **Peka inte ut delarna själv.** Du
|
|
51
|
+
får varken läsa repot eller skriva underlaget, och att avgöra vad som går att leverera
|
|
52
|
+
för sig kräver båda. `request-assess-impact` gör uppdelningen; du säger bara att den
|
|
53
|
+
behövs.
|
|
54
|
+
|
|
55
|
+
Delningen görs ett steg. Kommer en del tillbaka och inte går att ringa in heller, blir
|
|
56
|
+
den `OVER_SKALAN` och offereras — den delas inte vidare.
|
|
57
|
+
|
|
58
|
+
**En post som redan har poängsatta delar poängsätts aldrig som helhet.** Föräldern bär
|
|
59
|
+
summan av sina delar, inte en egen siffra.
|
|
60
|
+
|
|
61
|
+
### Obesvarade utfallsval
|
|
62
|
+
|
|
63
|
+
Påverkansanalysens granskarblock listar under _Obesvarade utfallsval_ de val specen
|
|
64
|
+
lämnat öppna, var och en med alternativen, om de skiljer sig i vad som måste byggas,
|
|
65
|
+
och vilket alternativ analysen är skriven utifrån.
|
|
66
|
+
|
|
67
|
+
En post stoppas nästan aldrig för ett sådant val. Gå igenom dem i fyra steg.
|
|
68
|
+
|
|
69
|
+
**Steg 1 — stryk det som inte löser problemet.** Läs specens rubrik _Problem_. Ett
|
|
70
|
+
alternativ som inte löser det problemet är inget alternativ, det är en otillräcklig
|
|
71
|
+
lösning, och det ska varken väljas eller presenteras. Att prissätta det vore att sälja
|
|
72
|
+
något som inte gör det kunden bett om.
|
|
73
|
+
|
|
74
|
+
Testet är specens egna ord, inte din uppfattning om vad kunden borde vilja. Löser
|
|
75
|
+
alternativet problemet som det är beskrivet? Delvis räcker inte.
|
|
76
|
+
|
|
77
|
+
**Steg 2 — återstår ingenting, stoppa.** Då motsäger specen sig själv: problemet går
|
|
78
|
+
inte att lösa inom det den beskriver. Sätt `outcome` till `TILLBAKA_TILL_SPEC` och
|
|
79
|
+
skriv i `customer_rationale` vad som behöver avgöras, i kundens språk.
|
|
80
|
+
|
|
81
|
+
**Steg 3 — ändrar valet arbetsmängden?** Analysens rad om huruvida alternativen skiljer
|
|
82
|
+
sig i vad som måste byggas är svaret. Gör de inte det är valet en **förutsättning**:
|
|
83
|
+
välj det rimligaste, skriv in det i `assumptions_stated` med vad som valts och varför,
|
|
84
|
+
och poängsätt vidare. Kunden godkänner förutsättningen tillsammans med spec och pris.
|
|
85
|
+
|
|
86
|
+
Typexempel på förutsättning: vilket av två befintliga sätt att visa att något laddar som
|
|
87
|
+
används, vilken av två likvärdiga formuleringar en text får, var i en befintlig vy ett
|
|
88
|
+
fält placeras.
|
|
89
|
+
|
|
90
|
+
**Steg 4 — flera alternativ som alla löser problemet.** Poängsätt **det enklaste** som
|
|
91
|
+
postens poäng. Poängsätt varje övrigt alternativ för sig, med egen inringning, och lägg
|
|
92
|
+
dem i `alternatives`. De går till kund som alternativa lösningar med egna priser.
|
|
93
|
+
|
|
94
|
+
Saknas analysens rad om arbetsmängd — den kan vara skriven före den regeln — avgör
|
|
95
|
+
själv utifrån vad analysen beskriver, och skriv i `notes` att raden saknades.
|
|
96
|
+
|
|
97
|
+
Varje alternativ ringas in precis som huvudalternativet. Ett alternativ med en poäng
|
|
98
|
+
men utan inringning är lika ogiltigt som en post utan.
|
|
99
|
+
|
|
100
|
+
Ett antagande som inte går att undersöka är inget stopp. Det blir ett villkor på posten:
|
|
101
|
+
"bygger på att X; faller X tidigt avbryts posten utan debitering". Osäkerhet löses med
|
|
102
|
+
kunskap eller villkor, aldrig med högre poäng för säkerhets skull.
|
|
103
|
+
|
|
104
|
+
## Metoden: ringa in, aldrig skatta fritt
|
|
105
|
+
|
|
106
|
+
En siffra som kommer direkt ur en helhetsbedömning går inte att granska och blir olika
|
|
107
|
+
mellan två körningar. Ringa in i stället, i fyra steg. Alla fyra redovisas i utfallet.
|
|
108
|
+
|
|
109
|
+
**Steg 1 — hitta ett golv.** Läs skalan och hitta ett referensuppdrag som posten
|
|
110
|
+
**säkert är större än**. Skriv ut vilket och varför.
|
|
111
|
+
|
|
112
|
+
**Steg 2 — hitta ett tak.** Hitta ett referensuppdrag som posten **säkert är mindre
|
|
113
|
+
än**. Skriv ut vilket och varför.
|
|
114
|
+
|
|
115
|
+
Får du inget golv: posten är mindre än A1 och får A1:s poäng. Skalans nedre ände är
|
|
116
|
+
ändå dominerad av den fasta processavgiften.
|
|
117
|
+
|
|
118
|
+
Får du inget tak: posten är större än skalans högsta referensuppdrag. Sätt då `DELA_UPP`
|
|
119
|
+
och ingen poäng, så att posten först prövas i delar. Är detta redan en del av en delad
|
|
120
|
+
post sätter du i stället `OVER_SKALAN` — underlaget för den nivån är för tunt för att
|
|
121
|
+
jämföra mot, och posten ska offereras separat.
|
|
122
|
+
|
|
123
|
+
**Steg 3 — snäva in.** Gå igenom referensuppdragen mellan golv och tak. För varje: är
|
|
124
|
+
posten större eller mindre, och på vilken grund? Fortsätt tills du har två
|
|
125
|
+
angränsande referensuppdrag som posten ligger mellan.
|
|
126
|
+
|
|
127
|
+
**Steg 4 — placera.** Sätt poängen mellan de två. Ligger posten närmare det ena, säg
|
|
128
|
+
vilket och varför. Landar den på samma nivå som ett referensuppdrag, ge den det
|
|
129
|
+
ankarets poäng rakt av.
|
|
130
|
+
|
|
131
|
+
**Avrunda till skalans upplösning.** Under 3 poäng till närmaste 0,25, alltså 0,25,
|
|
132
|
+
0,5, 0,75, 1, 1,25 och så vidare. Från 3 poäng och uppåt till närmaste hela poäng. En
|
|
133
|
+
finare siffra än så låtsas om en noggrannhet som inte finns: två oberoende bedömare
|
|
134
|
+
hamnar i olika klass i en femtedel av fallen. Avrundningen är mekanisk och sker efter
|
|
135
|
+
placeringen, aldrig genom att du väljer ett rundare tal medan du jämför.
|
|
136
|
+
|
|
137
|
+
## Vad du jämför på
|
|
138
|
+
|
|
139
|
+
Jämför på vad ändringen **drar med sig**, inte på hur mycket kod som skrivs. Det som
|
|
140
|
+
skiljer referensuppdragen åt, i fallande ordning efter hur mycket de väger:
|
|
141
|
+
|
|
142
|
+
**Om en människa måste verifiera för hand, och i hur många fall.** Det är den tydligaste
|
|
143
|
+
skillnaden genom hela skalan. Ett uppdrag som täcks av automatiska tester ligger lågt.
|
|
144
|
+
Ett som kräver genomgång i flera scenarier, på flera enheter eller i flera miljöer
|
|
145
|
+
ligger högt.
|
|
146
|
+
|
|
147
|
+
**Förutsätt alltid att automatiska tester finns**, även när påverkansanalysen säger att
|
|
148
|
+
repot saknar testsvit. Räkna bara det manuella arbete som återstår när en fungerande
|
|
149
|
+
testsvit gjort sitt: det som kräver en människa av sin natur, alltså kontroll mot en
|
|
150
|
+
extern tjänsts testläge, visuell granskning, eller genomgång på flera enheter eller i
|
|
151
|
+
flera miljöer. Saknas testsviten är det inte en rabatt: täckningen byggs som en egen
|
|
152
|
+
post före ändringen och poängsätts för sig. Skriv en rad under `notes` om vilken yta
|
|
153
|
+
som saknar täckning, så att den posten går att skapa.
|
|
154
|
+
|
|
155
|
+
**Vad som händer om det blir fel.** Felaktig betalning, felaktig åtkomst till någon
|
|
156
|
+
annans uppgifter, förlorad data eller bruten befintlig funktion väger tungt. Fel text
|
|
157
|
+
eller fel sorteringsordning väger lätt.
|
|
158
|
+
|
|
159
|
+
**Om ändringen rör kod som flera kunder använder.** Då tillkommer migrering per
|
|
160
|
+
installation och en risk som når utanför beställaren. Se A9 och A10.
|
|
161
|
+
|
|
162
|
+
**Om ett externt system berörs**, och om kopplingen är ny eller befintlig.
|
|
163
|
+
|
|
164
|
+
**Om en sekvens som användaren passerar i ordning ändras**, och hur många steg.
|
|
165
|
+
|
|
166
|
+
**Om något ska formges som inte finns i systemet i dag.**
|
|
167
|
+
|
|
168
|
+
Antal filer och antal rader är **inte** jämförelsegrunder. Se noten sist i skalan: två
|
|
169
|
+
referensuppdrag med samma poäng skiljer sig med en tiopotens i filantal.
|
|
170
|
+
|
|
171
|
+
## Typen
|
|
172
|
+
|
|
173
|
+
Använd typen för att hitta jämförbara referensuppdrag snabbare, ingenting annat. Ett
|
|
174
|
+
uppdrag av en typ som saknas i skalan poängsätts mot de närmaste i storlek, inte mot
|
|
175
|
+
någon påhittad justering. Skriv ut vilken typ du bedömt posten som — den loggas för att
|
|
176
|
+
kunna mäta i efterhand om någon typ hamnar systematiskt fel.
|
|
177
|
+
|
|
178
|
+
## Grindläget
|
|
179
|
+
|
|
180
|
+
Körs skillen på en fullständig implementationsplan efter kundens godkännande, sätt
|
|
181
|
+
`mode` till `guard`. Samma skala, samma metod.
|
|
182
|
+
|
|
183
|
+
Endast ny strukturell information ur fullplanen får flytta poängen, aldrig en
|
|
184
|
+
omvärdering av samma fakta. Rapportera vilket jämförelsesteg som ändrades och citatet ur
|
|
185
|
+
fullplanen som orsakade det. Grinden är symmetrisk — en lägre poäng rapporteras lika
|
|
186
|
+
tydligt som en högre.
|
|
187
|
+
|
|
188
|
+
Bygger fullplanen ett annat vägval än det som såldes är det en händelse att rapportera
|
|
189
|
+
även när poängen blir densamma.
|
|
190
|
+
|
|
191
|
+
## Output
|
|
192
|
+
|
|
193
|
+
```json
|
|
194
|
+
{
|
|
195
|
+
"request_id": "",
|
|
196
|
+
"mode": "pricing | guard",
|
|
197
|
+
"outcome": "POANG | KONCEPT | DIAGNOS | TILLBAKA_TILL_SPEC | DELA_UPP | OVER_SKALAN | INPUT_SAKNAS",
|
|
198
|
+
"score": null,
|
|
199
|
+
"type": "",
|
|
200
|
+
"bracket": {
|
|
201
|
+
"floor": { "anchor": "", "score": null, "why": "" },
|
|
202
|
+
"ceiling": { "anchor": "", "score": null, "why": "" },
|
|
203
|
+
"between": ["", ""],
|
|
204
|
+
"steps": []
|
|
205
|
+
},
|
|
206
|
+
"drivers": [],
|
|
207
|
+
"confidence": "hog | medel | lag",
|
|
208
|
+
"conditions": [],
|
|
209
|
+
"assumptions_stated": [],
|
|
210
|
+
"alternatives": [],
|
|
211
|
+
"dependencies": [],
|
|
212
|
+
"notes": [],
|
|
213
|
+
"customer_rationale": "",
|
|
214
|
+
"guard_diff": []
|
|
215
|
+
}
|
|
216
|
+
```
|
|
217
|
+
|
|
218
|
+
`score` sätts bara när `outcome` är `POANG`, och alltid på skalans upplösning: steg om
|
|
219
|
+
0,25 under 3 poäng, hela poäng från 3 och uppåt.
|
|
220
|
+
|
|
221
|
+
`bracket.steps` är jämförelserna från steg 3, en per referensuppdrag du vägde mot, var
|
|
222
|
+
och en med ankarets id, om posten är större eller mindre, och på vilken grund. Det är
|
|
223
|
+
det som gör poängen granskbar. En poäng utan inringning är inte ett giltigt utfall.
|
|
224
|
+
|
|
225
|
+
`drivers` är de två eller tre faktorer som mest avgjorde placeringen, med citat ur
|
|
226
|
+
påverkansanalysen. Citat, inte parafras.
|
|
227
|
+
|
|
228
|
+
`assumptions_stated` är de utfallsval specen lämnat öppna som **inte** ändrar
|
|
229
|
+
arbetsmängden: vad du valt, och varför. De går med förslaget till kund som
|
|
230
|
+
förutsättningar och godkänns tillsammans med specen och priset.
|
|
231
|
+
|
|
232
|
+
`alternatives` är de övriga vägar som också löser problemet, en post var med `label`
|
|
233
|
+
(vad alternativet innebär, i kundens språk), `score`, `bracket` och `adds` (vad som
|
|
234
|
+
tillkommer jämfört med det valda). Alternativ som inte löser specens problem hör inte
|
|
235
|
+
hit och ska utelämnas helt. Är listan tom fanns bara en väg som löser problemet.
|
|
236
|
+
|
|
237
|
+
`notes` är iakttagelser som inte hör till poängen men som någon bör känna till, till
|
|
238
|
+
exempel att ett repo saknar testsvit.
|
|
239
|
+
|
|
240
|
+
**Ett antagande som analysen flaggat som overifierat ska alltid ut.** Går det att
|
|
241
|
+
undersöka hör det till `notes` med hur det undersöks. Går det inte att undersöka blir
|
|
242
|
+
det ett villkor i `conditions`, formulerat som "bygger på att X; faller X tidigt
|
|
243
|
+
avbryts posten utan debitering". Ett overifierat antagande som varken syns i det ena
|
|
244
|
+
eller det andra försvinner tyst, och då bär Haus en risk ingen beslutat om.
|
|
245
|
+
|
|
246
|
+
`confidence` sätts till `lag` när posten inte liknar något referensuppdrag, när golv och
|
|
247
|
+
tak ligger långt isär och inget referensuppdrag finns emellan, eller när
|
|
248
|
+
påverkansanalysen anger att något inte kunnat verifieras och det påverkar placeringen.
|
|
249
|
+
Låg konfidens är ett giltigt utfall och ska inte döljas genom att välja en poäng som
|
|
250
|
+
ser rimlig ut.
|
|
251
|
+
|
|
252
|
+
### Motiveringen till kund
|
|
253
|
+
|
|
254
|
+
`customer_rationale` skrivs i kundens språk och beskriver arbetet som ska göras, inte
|
|
255
|
+
hur skalan räknade. Nämn aldrig poäng, referensuppdrag, ankare eller skalan. Kunden ska
|
|
256
|
+
kunna invända mot omfattningen, inte mot modellen.
|
|
257
|
+
|
|
258
|
+
Finns alternativ: beskriv dem sist, som egna vägar med var sitt pris. En mening var
|
|
259
|
+
räcker — vad kunden får i stället, och vad som tillkommer. Priset räknas ur poängen
|
|
260
|
+
någon annanstans; skriv aldrig ut poängen.
|
|
261
|
+
|
|
262
|
+
Den ska vara förenlig med specens _Ingår inte_. Motiverar du poängen med arbete som
|
|
263
|
+
specen uttryckligen undantar har du poängsatt fel post.
|
|
264
|
+
|
|
265
|
+
## Efter körning
|
|
266
|
+
|
|
267
|
+
Granskaren läser inringningen, inte slutpoängen. En rimlig poäng med fel jämförelser är
|
|
268
|
+
en felkalibrering som råkade landa rätt, och den kommer tillbaka i en post där den inte
|
|
269
|
+
gör det.
|
|
270
|
+
|
|
271
|
+
Korrigeringar går till skalan, alltså till referensuppdragen eller till den här
|
|
272
|
+
instruktionen, och till kalibreringsloggen. Aldrig till priset på den enskilda posten.
|
|
273
|
+
|
|
274
|
+
Visar det sig återkommande att poster av ett visst slag är svåra att placera, är det ett
|
|
275
|
+
tecken på att skalan har ett hål och behöver ett referensuppdrag till. Rapportera det.
|
|
276
|
+
|
|
277
|
+
## Acceptanstestet — granskarens sak, inte din
|
|
278
|
+
|
|
279
|
+
Skillen verifieras genom att köras mot poster med känt utfall. Det underlaget ligger med
|
|
280
|
+
flit **inte** i den här mappen — en körning som kan läsa facit kan inte längre testas. Du
|
|
281
|
+
ska varken leta efter det eller rapportera det som saknat.
|
|
282
|
+
|
|
283
|
+
För granskaren gäller två mått: att två oberoende körningar av samma post ger samma
|
|
284
|
+
poäng, och att inringningen håller vid granskning. Det första är det som avgör om
|
|
285
|
+
kunderna får samma pris för samma arbete.
|