@pikku/skills 0.12.33 → 0.12.34

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/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@pikku/skills",
3
- "version": "0.12.33",
3
+ "version": "0.12.34",
4
4
  "repository": {
5
5
  "type": "git",
6
6
  "url": "git+https://github.com/pikkujs/pikku.git",
@@ -3,9 +3,9 @@ name: pikku-architect
3
3
  description: >-
4
4
  Use to turn one settled milestone note into the technical plan the build is measured against —
5
5
  the tables, functions, wires, roles, scopes, screens and scenarios it owes, split into passes and
6
- written through `pikku knowledge plan set`. This is a SEPARATE SEAT from the build: the plan is
7
- the denominator `pikku knowledge plan progress` divides by, so whoever writes it must not be the
8
- one grading themselves against it. TRIGGER when: a milestone note is settled and the next step is
6
+ written through `pikku knowledge plan set`. The plan is the denominator
7
+ `pikku knowledge plan progress` divides by, so it is written BEFORE any of the milestone's code
8
+ exists and never edited afterwards to match what got built. TRIGGER when: a milestone note is settled and the next step is
9
9
  planning it, the user asks to plan or architect a milestone, `pikku knowledge plan progress` says
10
10
  a milestone has no plan, or pikku-build's App mode reaches a milestone with nothing planned. DO
11
11
  NOT TRIGGER when: the milestone notes themselves are still being written (use pikku-knowledge),
@@ -17,18 +17,19 @@ installGroups: [core]
17
17
  # Plan one milestone
18
18
 
19
19
  A milestone note says what the app must DO and how it must feel for the person using it. It
20
- deliberately does not say how. You are the seat that decides how, once, in writing, before anyone
21
- builds it.
20
+ deliberately does not say how. This is where how gets decided, once, in writing, before any of
21
+ it is built.
22
22
 
23
- **Why this is a separate seat.** The build agent used to write its own plan. That makes one party
24
- both author and examiner: it can build a fraction, plan only that fraction, and certify itself
25
- complete — and `pikku knowledge plan progress` then divides by a denominator the builder chose
26
- after seeing its own answer. A plan written here, against the note, by someone who is not going to
27
- build it, is the denominator the builder does not own.
23
+ **Why the plan comes first and stays fixed.** A builder who plans after seeing its own work can
24
+ build a fraction, plan only that fraction, and certify itself complete — `pikku knowledge plan
25
+ progress` then divides by a denominator chosen after the answer. The defence is the ORDER: the plan
26
+ is written against the note, in its own turn, before a single migration for it exists, and is never
27
+ edited afterwards. An item that will not land is deferred with its reason through `plan defer`,
28
+ not rewritten out of the plan. The same agent plans and then builds; nothing hands off.
28
29
 
29
- **One milestone, one plan, then stop.** Do not build in this session. Do not plan the next
30
- milestone "while you are here" — the notes after this one are still allowed to change, and a plan
31
- written against a note that later moves is worse than no plan.
30
+ **One milestone, one plan, then build it.** Do not plan the next milestone "while you are here" —
31
+ the notes after this one are still allowed to change, and a plan written against a note that later
32
+ moves is worse than no plan.
32
33
 
33
34
  ---
34
35
 
@@ -38,6 +39,11 @@ The plan reaches disk through `pikku knowledge plan set <milestone> <file>` and
38
39
  validates first and names the field that is wrong if it refuses; a plan file written with an editor
39
40
  is a plan nothing checked, and the place that discovers that is a finished build.
40
41
 
42
+ It is also written ONCE. `plan set` refuses a milestone that already has a plan: the plan is the
43
+ order the build is measured against, and an order that can be rewritten measures nothing. The one
44
+ way down from a written plan is `pikku knowledge plan defer <milestone> <item> --reason <why>`,
45
+ which records what was left out and why.
46
+
41
47
  It is JSON rather than a note on purpose. Everything else under `knowledge/` is prose a human
42
48
  reads; this one is consumed field-by-field, and a markdown parser is one more place a misspelt
43
49
  heading silently passes. It cannot live INSIDE the milestone note either: that note is frozen once
@@ -260,6 +266,7 @@ cover it — so a role × resource cross product there costs the milestone nothi
260
266
 
261
267
  ## When you are done
262
268
 
263
- The accepted `plan set` is the end of the seat. Hand the milestone to `pikku-build`, which reads the
264
- plan with `plan show --for-build`, builds it, and closes the milestone only when
265
- `pikku knowledge plan progress` is clean. What you wrote is what it is measured against.
269
+ The accepted `plan set` is the end of planning. Go straight on to the build in `pikku-build` §6:
270
+ read the plan with `plan show --for-build`, build it, and close the milestone only when
271
+ `pikku knowledge plan progress` is clean. What you wrote is what you are measured against, so do
272
+ not touch it once the first migration is open.
@@ -19,13 +19,13 @@ installGroups: [core]
19
19
 
20
20
  ## Which mode
21
21
 
22
- | The situation | Read |
23
- | --- | --- |
24
- | A template was just cloned or scaffolded, and the tree still looks like one | `references/post-clone.md` first, then come back |
25
- | A real product, meant to be picked up by someone else | `references/app.md` — the default |
26
- | A spike, a throwaway demo, an idea nobody has committed to | `references/quick.md` |
27
- | A showcase meant to exercise every Pikku surface | `references/platform.md`, which is a delta on top of `references/app.md` |
28
- | A feature added to an app that already has its knowledge base and milestones | `references/feature.md` |
22
+ | The situation | Read |
23
+ | ---------------------------------------------------------------------------- | ------------------------------------------------------------------------ |
24
+ | A template was just cloned or scaffolded, and the tree still looks like one | `references/post-clone.md` first, then come back |
25
+ | A real product, meant to be picked up by someone else | `references/app.md` — the default |
26
+ | A spike, a throwaway demo, an idea nobody has committed to | `references/quick.md` |
27
+ | A showcase meant to exercise every Pikku surface | `references/platform.md`, which is a delta on top of `references/app.md` |
28
+ | A feature added to an app that already has its knowledge base and milestones | `references/feature.md` |
29
29
 
30
30
  **App is the default.** A small or toy-sounding app does not make it Quick;
31
31
  only an explicit signal of speed or throwaway-ness does. Platform is not "App
@@ -53,9 +53,10 @@ while still planning. Those failures look alarming and are nothing but this.
53
53
 
54
54
  ## What holds in every mode
55
55
 
56
- - **The branch and the diff are the contract.** There is no plan JSON. A
57
- reviewer sees real, compiled, working code: apply is a merge, reject is a
58
- `git branch -D`.
56
+ - **The branch and the diff are the contract.** A reviewer sees real, compiled,
57
+ working code: apply is a merge, reject is a `git branch -D`. The milestone's
58
+ plan is your own denominator, measured by `pikku knowledge plan progress` —
59
+ never something a reviewer is handed instead of the code.
59
60
  - **Discover before editing.** `yarn pikku meta context --json` returns
60
61
  functions, wires, middleware, permissions, workflows, `capabilities` and
61
62
  `layout` in one call. Fall back to targeted `meta` commands only for a full
@@ -66,11 +67,13 @@ while still planning. Those failures look alarming and are nothing but this.
66
67
  lives in `messages/*.json`.
67
68
  - **`pikku all` is the gate.** Run it after touching functions, wirings or
68
69
  schemas, and treat its criticals as real.
69
- - **A milestone is planned by a different seat than the one that builds it.**
70
+ - **A milestone is planned before it is built, and the plan then stays fixed.**
70
71
  The plan — tables, functions, wires, roles, scopes, screens, scenarios, in
71
- passes — is written through `pikku knowledge plan set` by `pikku-architect`,
72
- and `pikku knowledge plan progress` measures the build against it from the
73
- generated meta. A builder who writes its own plan is grading itself.
72
+ passes — is written through `pikku knowledge plan set` (how: `pikku-architect`)
73
+ in its own turn before any of that milestone's code exists, and
74
+ `pikku knowledge plan progress` measures the build against it from the
75
+ generated meta. You plan it and you build it; what you never do is edit the
76
+ plan afterwards to match what you built — that is grading yourself.
74
77
 
75
78
  ## What NOT to do
76
79
 
@@ -81,11 +81,11 @@ A brief saying "the entire UI is German" is about **one** of these. Getting this
81
81
  wrong has already shipped a project that can never add a second language, so
82
82
  settle all three explicitly before you write code.
83
83
 
84
- | Axis | What it covers | Where it goes |
85
- | --------------- | -------------------------------------------------------------------------------------------------------------------------------------- | ----------------------------------------------------------------------------------- |
86
- | **Identifiers** | Function, component, type, variable and file names. Database tables and columns. Commit messages. | Nowhere — **always English**, no setting, not negotiable |
87
- | **Meta** | `description` on functions and steps, `name`/`title` on features and scenarios, step `template`, role and persona descriptions | `metaLocale` in `pikku.config.json`, default `en` |
88
- | **Product UI** | Every string the app shows a user | `messages/<locale>.json`, and `defaultLocale` for what a first-time visitor opens in |
84
+ | Axis | What it covers | Where it goes |
85
+ | --------------- | ------------------------------------------------------------------------------------------------------------------------------ | ------------------------------------------------------------------------------------ |
86
+ | **Identifiers** | Function, component, type, variable and file names. Database tables and columns. Commit messages. | Nowhere — **always English**, no setting, not negotiable |
87
+ | **Meta** | `description` on functions and steps, `name`/`title` on features and scenarios, step `template`, role and persona descriptions | `metaLocale` in `pikku.config.json`, default `en` |
88
+ | **Product UI** | Every string the app shows a user | `messages/<locale>.json`, and `defaultLocale` for what a first-time visitor opens in |
89
89
 
90
90
  **Identifiers are English.** The product's market does not change this and
91
91
  neither does `metaLocale`. Identifiers are the surface the generated `#pikku/*`
@@ -218,7 +218,11 @@ defineSystemRole({
218
218
  })
219
219
 
220
220
  definePersonas({
221
- visitor: { name: 'Visitor', jobTitle: 'Synthetic health-check user', account: {} },
221
+ visitor: {
222
+ name: 'Visitor',
223
+ jobTitle: 'Synthetic health-check user',
224
+ account: {},
225
+ },
222
226
  amina: {
223
227
  name: 'Amina',
224
228
  jobTitle: 'Property owner',
@@ -229,7 +233,8 @@ definePersonas({
229
233
  bilal: {
230
234
  name: 'Bilal',
231
235
  jobTitle: 'Property owner',
232
- personality: 'A second owner — exists so "you see yours, not theirs" is testable',
236
+ personality:
237
+ 'A second owner — exists so "you see yours, not theirs" is testable',
233
238
  roles: ['owner'],
234
239
  account: {},
235
240
  },
@@ -369,10 +374,10 @@ scenarios, split into passes. It is JSON, it lives beside the note, and
369
374
  `pikku knowledge plan progress` measures the finished build against it.
370
375
 
371
376
  **Read `pikku-architect` and follow it.** The plan is the denominator the
372
- completion check divides by, so a builder who writes their own plan can build a
373
- fraction, plan only that fraction, and certify itself complete. Fabric answers
374
- that by giving the plan its own seat; here the defence is the ORDER, and it only
375
- holds if you keep it: the plan is written against the note in its own turn,
377
+ completion check divides by, so a builder who plans after seeing their own work
378
+ can build a fraction, plan only that fraction, and certify itself complete. The
379
+ defence is the ORDER, and it only holds if you keep it: the plan is written
380
+ against the note in its own turn,
376
381
  before any of the code it measures exists, and is never edited afterwards to
377
382
  match what you ended up building. An item that will not land is deferred with
378
383
  its reason — `plan defer` — not quietly rewritten. Write it before you open a
@@ -396,8 +401,8 @@ no plan, and everything after the current milestone is still allowed to move.
396
401
 
397
402
  **Per milestone** — plan it (§5a), set its note to `status: dispatched`, do the
398
403
  six steps, close it out (§6a), set it to `built`. Do not start the next one
399
- until §6a passes, §7 is green for this one *and §7a shows its functions
400
- covered*. A stack of half-milestones cannot be reviewed and cannot be handed
404
+ until §6a passes, §7 is green for this one _and §7a shows its functions
405
+ covered_. A stack of half-milestones cannot be reviewed and cannot be handed
401
406
  over, and an uncovered function is a half-milestone whether or not the note says
402
407
  `built`.
403
408
 
@@ -416,7 +421,7 @@ over, and an uncovered function is a half-milestone whether or not the note says
416
421
  Do this generously and do it now: an empty app demos badly and critiques
417
422
  badly, and you cannot judge a screen's hierarchy, overflow, or truncation
418
423
  against zero rows. Seed rows each persona sees differently — with an ownership
419
- rule that means seeding rows for the *second* owner too.
424
+ rule that means seeding rows for the _second_ owner too.
420
425
  3. **Functions.** One `pikkuFunc` per `*.function.ts`. Mark it `expose: true` and
421
426
  Pikku generates the typed RPC client and the React Query hooks the UI calls;
422
427
  you do NOT write an HTTP route for it. Add `wireHTTP` only for a real REST
@@ -443,8 +448,10 @@ over, and an uncovered function is a half-milestone whether or not the note says
443
448
  same as the scenario: a milestone whose screens nobody has seen is not built,
444
449
  it is unproven at the one layer scenarios cannot reach. `references/design.md`
445
450
  carries how to take the shot when no browser tool is wired up, and what to
446
- look for. Then `status: built`, and say in the note what you looked at and
447
- what it made you change.
451
+ look for. Then close it against its plan (§6a) — `pikku knowledge plan
452
+ progress` has to exit zero before anything is `built` — and only then set
453
+ `status: built`, saying in the note what you looked at and what it made you
454
+ change.
448
455
 
449
456
  Rules that are not optional:
450
457
 
@@ -464,8 +471,8 @@ Rules that are not optional:
464
471
  ```typescript
465
472
  export const classifications = {
466
473
  payment: {
467
- paid_at: { kind: 'date' }, // -> Date, not an ISO string
468
- metadata: { kind: 'json', tsType: 'PaymentMeta' }, // -> parsed object, not unknown
474
+ paid_at: { kind: 'date' }, // -> Date, not an ISO string
475
+ metadata: { kind: 'json', tsType: 'PaymentMeta' }, // -> parsed object, not unknown
469
476
  },
470
477
  }
471
478
  ```
@@ -474,6 +481,7 @@ Rules that are not optional:
474
481
  `JSON` column with no entry types as `unknown` (the CLI warns PKU481). Add the
475
482
  annotation rather than casting around the generated type. Once the file carries
476
483
  manual fields, `db migrate` stops overwriting it.
484
+
477
485
  - A `z.date()` on a function's **input** arrives over RPC as an ISO string, not a
478
486
  `Date`. Normalise before calling date methods on it (`new Date(value)`), or it
479
487
  throws `.getTime is not a function` at runtime — schema validation accepts the
@@ -542,6 +550,7 @@ Three things it says, and what each one asks of you:
542
550
  milestone is two milestones — say so to the user rather than deferring again.
543
551
  What you may never do is drop the item silently: the plan is what the next
544
552
  person reads to know what this milestone was for.
553
+
545
554
  - **PROBLEMS** — something exists but does not do what was planned. A function
546
555
  planned as restricted whose meta says `auth: false`; a `cascade` no migration
547
556
  declares; a browser scenario that opens a page and asserts it is still on it.
@@ -550,8 +559,9 @@ Three things it says, and what each one asks of you:
550
559
  visible, never blocking.
551
560
 
552
561
  **Do not set the note to `built` while this exits non-zero**, and do not edit the
553
- plan to match what you built — `plan set` is the architect's seat, and a builder
554
- rewriting its own denominator is exactly what the split exists to stop.
562
+ plan to match what you built — the plan was written before the code on purpose,
563
+ and rewriting your own denominator afterwards is exactly what that order exists
564
+ to stop.
555
565
 
556
566
  ## 7. Prove it — scenarios
557
567
 
@@ -566,26 +576,27 @@ import { pikkuScenario } from '#pikku/scenarios'
566
576
 
567
577
  export const tenantReportsAFaultScenario = pikkuScenario<void, { id: string }>({
568
578
  title: 'A tenant reports a fault and the owner sees it',
569
- description: 'The report lands on the owning landlord’s queue, and nobody else’s',
579
+ description:
580
+ 'The report lands on the owning landlord’s queue, and nobody else’s',
570
581
  tags: ['scenario', 'maintenance'],
571
582
  func: async (_services, _data, { scenario, actors }) => {
572
583
  const report = await scenario.do(
573
584
  'reports a broken boiler',
574
585
  'createMaintenanceReport',
575
586
  { summary: 'No hot water' },
576
- { actor: actors.chidi },
587
+ { actor: actors.chidi }
577
588
  )
578
589
  await scenario.then(
579
590
  'appears on the owner’s queue',
580
591
  'reportShowsOnQueue',
581
592
  { id: report.id },
582
- { actor: actors.amina },
593
+ { actor: actors.amina }
583
594
  )
584
595
  await scenario.then(
585
596
  'is invisible to the other owner',
586
597
  'reportIsNotVisible',
587
598
  { id: report.id },
588
- { actor: actors.bilal },
599
+ { actor: actors.bilal }
589
600
  )
590
601
  return { id: report.id }
591
602
  },
@@ -266,7 +266,7 @@ Two things about the output matter if you are driving it:
266
266
  `options` is empty when the answer is free text, and an empty list means offer free
267
267
  text — never invent choices to fill it.
268
268
 
269
- `hold` means a profile's own gate is holding the milestone and no seat this loop knows
269
+ `hold` means a profile's own gate is holding the milestone and nothing this loop knows
270
270
  about can clear it. It names the hold and the notes it is about; what to do then
271
271
  belongs to that profile, not here.
272
272
 
@@ -282,7 +282,7 @@ pikku knowledge plan progress <milestone> # what it still owes, read fr
282
282
  pikku knowledge plan defer <milestone> <item> -r "<why>"
283
283
  ```
284
284
 
285
- `progress` reconciles the plan against pikku's generated meta — set membership, never anyone's status — and exits non-zero while the first pass is short, or while anything already built contradicts the plan. Unbuilt work in a later pass is reported, not blocked; a function that shipped wide open against a planned permission rule blocks from any pass, because that is a hole rather than a backlog. Writing a plan is its own seat: read `pikku-architect`. Building against one is `pikku-build`.
285
+ `progress` reconciles the plan against pikku's generated meta — set membership, never anyone's status — and exits non-zero while the first pass is short, or while anything already built contradicts the plan. Unbuilt work in a later pass is reported, not blocked; a function that shipped wide open against a planned permission rule blocks from any pass, because that is a hole rather than a backlog. How a plan is written is `pikku-architect`; building against one, and the order plan-then-build, is `pikku-build`.
286
286
 
287
287
  ### A finished milestone is a tombstone
288
288