@nurix/etna 0.20.36 → 0.20.37
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/data/catalog/skills/nustack/SKILL.md +2 -2
- package/data/catalog/skills/nustack/references/cli-design.md +35 -35
- package/data/catalog/skills/nustack/references/monorepo-master-list.md +6 -6
- package/data/catalog/skills/nustack/references/monorepo-setup.md +13 -13
- package/data/catalog/skills/nustack/references/publishing.md +40 -39
- package/data/harness-index.json +1 -1
- package/data/harnesses/code/harness.json +1 -1
- package/data/harnesses/code/skills/boundary/SKILL.md +33 -22
- package/data/harnesses/code/skills/boundary/references/index.md +2 -4
- package/data/harnesses/code/skills/boundary/references/mechanisms.md +3 -10
- package/data/harnesses/code/skills/boundary/references/packs/frontend.md +17 -17
- package/data/harnesses/code/skills/boundary/references/packs/generic-tail.md +1 -1
- package/data/harnesses/code/skills/brainstorm/README.md +11 -13
- package/data/harnesses/code/skills/brainstorm/SKILL.md +150 -132
- package/data/harnesses/code/skills/brainstorm/references/doctrine.md +48 -51
- package/data/harnesses/code/skills/brainstorm/references/harvest.md +51 -56
- package/data/harnesses/code/skills/brainstorm/references/session-schema.md +48 -42
- package/data/harnesses/code/skills/design/SKILL.md +31 -35
- package/data/harnesses/code/skills/design/data/iconography.md +2 -2
- package/data/harnesses/code/skills/design/references/compose.md +14 -16
- package/data/harnesses/code/skills/design/references/foundations.md +5 -5
- package/data/harnesses/code/skills/design/references/intake.md +6 -6
- package/data/harnesses/code/skills/design/references/object-pass.md +1 -1
- package/data/harnesses/code/skills/design/references/ship-gate.md +5 -5
- package/data/harnesses/code/skills/design/references/ux-patterns/Readme.md +4 -4
- package/data/harnesses/code/skills/design/references/ux-patterns/ai-layer.md +1 -1
- package/data/harnesses/code/skills/design/references/ux-patterns/container-choice.md +1 -1
- package/data/harnesses/code/skills/design/references/ux-patterns/dashboards.md +1 -1
- package/data/harnesses/code/skills/design/references/ux-patterns/modes.md +1 -1
- package/data/harnesses/code/skills/design/references/ux-patterns/object-model.md +2 -2
- package/data/harnesses/code/skills/design/references/ux-patterns/promotion-demotion.md +1 -1
- package/data/harnesses/code/skills/design/references/ux-patterns/settings.md +1 -1
- package/data/harnesses/code/skills/design/references/ux-patterns/standard-pages.md +1 -1
- package/data/harnesses/code/skills/documentation/SKILL.md +5 -5
- package/data/harnesses/code/skills/documentation/references/examples.md +22 -22
- package/data/harnesses/code/skills/documentation/references/frontmatter.md +3 -3
- package/data/harnesses/code/skills/documentation/references/instruction-style.md +3 -3
- package/data/harnesses/code/skills/documentation/references/source-comments.md +3 -3
- package/data/harnesses/code/skills/documentation/references/style-guide.md +5 -5
- package/data/harnesses/code/skills/documentation/references/untemplated.md +8 -8
- package/data/harnesses/code/skills/documentation/scripts/doc-lint.mjs +3 -2
- package/data/harnesses/code/skills/documentation/templates/Readme.md +1 -1
- package/data/harnesses/code/skills/documentation/templates/acceptance-criteria.md +1 -1
- package/data/harnesses/code/skills/documentation/templates/api-reference.md +1 -1
- package/data/harnesses/code/skills/documentation/templates/architecture-decision.md +3 -7
- package/data/harnesses/code/skills/documentation/templates/behavioral-checklist.md +1 -1
- package/data/harnesses/code/skills/documentation/templates/changelog-entry.md +1 -1
- package/data/harnesses/code/skills/documentation/templates/changelog-index.md +1 -1
- package/data/harnesses/code/skills/documentation/templates/docs-readme.md +3 -3
- package/data/harnesses/code/skills/documentation/templates/doctrine.md +1 -1
- package/data/harnesses/code/skills/documentation/templates/domain-model.md +1 -1
- package/data/harnesses/code/skills/documentation/templates/environment-registry.md +1 -1
- package/data/harnesses/code/skills/documentation/templates/feature.md +3 -3
- package/data/harnesses/code/skills/documentation/templates/handover.md +2 -2
- package/data/harnesses/code/skills/documentation/templates/implementation-map.md +1 -1
- package/data/harnesses/code/skills/documentation/templates/migration-runbook.md +1 -1
- package/data/harnesses/code/skills/documentation/templates/non-goals.md +1 -1
- package/data/harnesses/code/skills/documentation/templates/operations-procedure.md +2 -2
- package/data/harnesses/code/skills/documentation/templates/package.md +1 -1
- package/data/harnesses/code/skills/documentation/templates/protected-files.md +1 -1
- package/data/harnesses/code/skills/documentation/templates/root-readme.md +1 -1
- package/data/harnesses/code/skills/documentation/templates/security-overview.md +1 -1
- package/data/harnesses/code/skills/documentation/templates/system-overview.md +1 -1
- package/data/harnesses/code/skills/documentation/templates/system.md +1 -1
- package/data/harnesses/code/skills/documentation/templates/testing-strategy.md +1 -1
- package/data/harnesses/code/skills/documentation/templates/ux-behavior.md +3 -5
- package/data/harnesses/code/skills/issue-bridge/SKILL.md +51 -16
- package/data/harnesses/code/skills/issue-bridge/references/trackers/github.md +5 -5
- package/data/harnesses/code/skills/issue-bridge/references/trackers/jira.md +11 -8
- package/data/harnesses/code/skills/issue-bridge/references/trackers/linear.md +16 -11
- package/data/harnesses/code/skills/nustack-graph/SKILL.md +38 -29
- package/data/harnesses/code/skills/polygraph/references/dispatch.md +31 -18
- package/data/harnesses/code/skills/polygraph/references/rows.md +11 -6
- package/data/harnesses/code/skills/schema-design/SKILL.md +39 -41
- package/data/harnesses/code/skills/test/SKILL.md +38 -42
- package/data/harnesses/code/skills/testing/SKILL.md +83 -73
- package/data/harnesses/code/skills/workflow-mapper/SKILL.md +156 -193
- package/data/harnesses/code/skills/workflow-mapper/references/patterns.md +15 -15
- package/data/harnesses/delivery/harness.json +1 -1
- package/data/harnesses/delivery/skills/brainstorm/README.md +11 -13
- package/data/harnesses/delivery/skills/brainstorm/SKILL.md +150 -132
- package/data/harnesses/delivery/skills/brainstorm/references/doctrine.md +48 -51
- package/data/harnesses/delivery/skills/brainstorm/references/harvest.md +51 -56
- package/data/harnesses/delivery/skills/brainstorm/references/session-schema.md +48 -42
- package/data/harnesses/delivery/skills/cost-report/SKILL.md +10 -10
- package/data/harnesses/delivery/skills/documentation/SKILL.md +5 -5
- package/data/harnesses/delivery/skills/documentation/references/examples.md +22 -22
- package/data/harnesses/delivery/skills/documentation/references/frontmatter.md +3 -3
- package/data/harnesses/delivery/skills/documentation/references/instruction-style.md +3 -3
- package/data/harnesses/delivery/skills/documentation/references/source-comments.md +3 -3
- package/data/harnesses/delivery/skills/documentation/references/style-guide.md +5 -5
- package/data/harnesses/delivery/skills/documentation/references/untemplated.md +8 -8
- package/data/harnesses/delivery/skills/documentation/scripts/doc-lint.mjs +3 -2
- package/data/harnesses/delivery/skills/documentation/templates/Readme.md +1 -1
- package/data/harnesses/delivery/skills/documentation/templates/acceptance-criteria.md +1 -1
- package/data/harnesses/delivery/skills/documentation/templates/api-reference.md +1 -1
- package/data/harnesses/delivery/skills/documentation/templates/architecture-decision.md +3 -7
- package/data/harnesses/delivery/skills/documentation/templates/behavioral-checklist.md +1 -1
- package/data/harnesses/delivery/skills/documentation/templates/changelog-entry.md +1 -1
- package/data/harnesses/delivery/skills/documentation/templates/changelog-index.md +1 -1
- package/data/harnesses/delivery/skills/documentation/templates/docs-readme.md +3 -3
- package/data/harnesses/delivery/skills/documentation/templates/doctrine.md +1 -1
- package/data/harnesses/delivery/skills/documentation/templates/domain-model.md +1 -1
- package/data/harnesses/delivery/skills/documentation/templates/environment-registry.md +1 -1
- package/data/harnesses/delivery/skills/documentation/templates/feature.md +3 -3
- package/data/harnesses/delivery/skills/documentation/templates/handover.md +2 -2
- package/data/harnesses/delivery/skills/documentation/templates/implementation-map.md +1 -1
- package/data/harnesses/delivery/skills/documentation/templates/migration-runbook.md +1 -1
- package/data/harnesses/delivery/skills/documentation/templates/non-goals.md +1 -1
- package/data/harnesses/delivery/skills/documentation/templates/operations-procedure.md +2 -2
- package/data/harnesses/delivery/skills/documentation/templates/package.md +1 -1
- package/data/harnesses/delivery/skills/documentation/templates/protected-files.md +1 -1
- package/data/harnesses/delivery/skills/documentation/templates/root-readme.md +1 -1
- package/data/harnesses/delivery/skills/documentation/templates/security-overview.md +1 -1
- package/data/harnesses/delivery/skills/documentation/templates/system-overview.md +1 -1
- package/data/harnesses/delivery/skills/documentation/templates/system.md +1 -1
- package/data/harnesses/delivery/skills/documentation/templates/testing-strategy.md +1 -1
- package/data/harnesses/delivery/skills/documentation/templates/ux-behavior.md +3 -5
- package/data/harnesses/delivery/skills/escalate/SKILL.md +11 -11
- package/data/harnesses/delivery/skills/prompt-eval/SKILL.md +8 -8
- package/data/harnesses/delivery/skills/prompt-library/SKILL.md +30 -9
- package/data/harnesses/delivery/skills/route/SKILL.md +8 -8
- package/data/harnesses/etna/harness.json +1 -1
- package/data/harnesses/etna/skills/boundary/SKILL.md +33 -22
- package/data/harnesses/etna/skills/boundary/references/index.md +2 -4
- package/data/harnesses/etna/skills/boundary/references/mechanisms.md +3 -10
- package/data/harnesses/etna/skills/boundary/references/packs/frontend.md +17 -17
- package/data/harnesses/etna/skills/boundary/references/packs/generic-tail.md +1 -1
- package/data/harnesses/etna/skills/brainstorm/README.md +11 -13
- package/data/harnesses/etna/skills/brainstorm/SKILL.md +150 -132
- package/data/harnesses/etna/skills/brainstorm/references/doctrine.md +48 -51
- package/data/harnesses/etna/skills/brainstorm/references/harvest.md +51 -56
- package/data/harnesses/etna/skills/brainstorm/references/session-schema.md +48 -42
- package/data/harnesses/etna/skills/documentation/SKILL.md +5 -5
- package/data/harnesses/etna/skills/documentation/references/examples.md +22 -22
- package/data/harnesses/etna/skills/documentation/references/frontmatter.md +3 -3
- package/data/harnesses/etna/skills/documentation/references/instruction-style.md +3 -3
- package/data/harnesses/etna/skills/documentation/references/source-comments.md +3 -3
- package/data/harnesses/etna/skills/documentation/references/style-guide.md +5 -5
- package/data/harnesses/etna/skills/documentation/references/untemplated.md +8 -8
- package/data/harnesses/etna/skills/documentation/scripts/doc-lint.mjs +3 -2
- package/data/harnesses/etna/skills/documentation/templates/Readme.md +1 -1
- package/data/harnesses/etna/skills/documentation/templates/acceptance-criteria.md +1 -1
- package/data/harnesses/etna/skills/documentation/templates/api-reference.md +1 -1
- package/data/harnesses/etna/skills/documentation/templates/architecture-decision.md +3 -7
- package/data/harnesses/etna/skills/documentation/templates/behavioral-checklist.md +1 -1
- package/data/harnesses/etna/skills/documentation/templates/changelog-entry.md +1 -1
- package/data/harnesses/etna/skills/documentation/templates/changelog-index.md +1 -1
- package/data/harnesses/etna/skills/documentation/templates/docs-readme.md +3 -3
- package/data/harnesses/etna/skills/documentation/templates/doctrine.md +1 -1
- package/data/harnesses/etna/skills/documentation/templates/domain-model.md +1 -1
- package/data/harnesses/etna/skills/documentation/templates/environment-registry.md +1 -1
- package/data/harnesses/etna/skills/documentation/templates/feature.md +3 -3
- package/data/harnesses/etna/skills/documentation/templates/handover.md +2 -2
- package/data/harnesses/etna/skills/documentation/templates/implementation-map.md +1 -1
- package/data/harnesses/etna/skills/documentation/templates/migration-runbook.md +1 -1
- package/data/harnesses/etna/skills/documentation/templates/non-goals.md +1 -1
- package/data/harnesses/etna/skills/documentation/templates/operations-procedure.md +2 -2
- package/data/harnesses/etna/skills/documentation/templates/package.md +1 -1
- package/data/harnesses/etna/skills/documentation/templates/protected-files.md +1 -1
- package/data/harnesses/etna/skills/documentation/templates/root-readme.md +1 -1
- package/data/harnesses/etna/skills/documentation/templates/security-overview.md +1 -1
- package/data/harnesses/etna/skills/documentation/templates/system-overview.md +1 -1
- package/data/harnesses/etna/skills/documentation/templates/system.md +1 -1
- package/data/harnesses/etna/skills/documentation/templates/testing-strategy.md +1 -1
- package/data/harnesses/etna/skills/documentation/templates/ux-behavior.md +3 -5
- package/data/harnesses/etna/skills/workflow-mapper/SKILL.md +156 -193
- package/data/harnesses/etna/skills/workflow-mapper/references/patterns.md +15 -15
- package/data/harnesses/hr/harness.json +1 -1
- package/data/harnesses/hr/skills/evaluator/SKILL.md +71 -73
- package/data/harnesses/hr/skills/evaluator/criteria/code-quality.md +28 -47
- package/data/harnesses/hr/skills/evaluator/criteria/deployment-readiness.md +33 -43
- package/data/harnesses/hr/skills/evaluator/criteria/maintainability.md +34 -46
- package/data/harnesses/hr/skills/evaluator/criteria/mechanical-ambition.md +13 -13
- package/data/harnesses/hr/skills/evaluator/criteria/problem-substantiveness.md +7 -7
- package/data/harnesses/hr/skills/evaluator/criteria/testing.md +36 -41
- package/data/harnesses/hr/skills/evaluator/criteria/ux-mechanics.md +25 -11
- package/data/harnesses/hr/skills/evaluator/criteria/value-articulation.md +7 -7
- package/data/harnesses/hr/skills/evaluator/preflight.md +27 -46
- package/data/harnesses/hr/skills/interview-eval/SKILL.md +37 -42
- package/data/harnesses/hr/skills/interview-eval/rubric.md +21 -23
- package/package.json +2 -2
|
@@ -5,13 +5,13 @@ description: "Use when designing or altering a relational schema — a new table
|
|
|
5
5
|
|
|
6
6
|
# Schema Design — the doctrine
|
|
7
7
|
|
|
8
|
-
You decide **what earns a table and where a fact lives**
|
|
8
|
+
You decide **what earns a table and where a fact lives** for every Nurix relational schema — written for SQLite / Cloudflare D1 + Drizzle; a Postgres project keeps the same names and semantics with native types. Naming, the `id`/`slug`/`label` vocabulary, and column types are the `database.md` rule; this skill never restates them.
|
|
9
9
|
|
|
10
|
-
Apply the sections below to the change in hand; when reviewing, report
|
|
10
|
+
Apply the sections below to the change in hand; when reviewing, report each violation with the section that names it.
|
|
11
11
|
|
|
12
12
|
## What earns a table
|
|
13
13
|
|
|
14
|
-
A table
|
|
14
|
+
A table costs a migration to reshape, a join to read, a mirror to keep in sync. Default to **not** a table — a concept earns one **only** with at least one property in the left column.
|
|
15
15
|
|
|
16
16
|
| A table is earned by… | Lacking all of these, the data belongs in… |
|
|
17
17
|
| -------------------------------------------------------------------------- | ------------------------------------------------------- |
|
|
@@ -27,15 +27,14 @@ A table is the most expensive home for data — a migration to change its shape,
|
|
|
27
27
|
|
|
28
28
|
Each right-column route is one test: process state — would a product feature break if this vanished the instant the request finished?; derived output — exactly recomputable from other rows + code?; un-addressed detail — is the row ever `SELECT`ed / `JOIN`ed / FK'd alone?; another system's record — does a specialized service (chat, telemetry, object store) already own it?
|
|
29
29
|
|
|
30
|
-
- **Static vocabulary or a fixed graph → config, not a table** — HTTP status labels, a fixed onboarding funnel. Surface it in code as a constant
|
|
31
|
-
- **History → one immutable log + a mutable head.** Never shatter versioning into per-entity `*_revisions` / `*_revision_sections` tables — snapshot the coherent set into one append-only versions table; current state is a projection of the newest entry. A table that is just "old rows of another table" collapses into the snapshot.
|
|
30
|
+
- **Static vocabulary or a fixed graph → config, not a table** — HTTP status labels, a fixed onboarding funnel. Surface it in code as a constant or type; reifying it into tables plus a seed makes the file and the tables a two-copy sync problem. The refined boundary is § Vocabulary / lookup tables.
|
|
31
|
+
- **History → one immutable log + a mutable head.** **Never** shatter versioning into per-entity `*_revisions` / `*_revision_sections` tables — snapshot the coherent set into one append-only versions table; current state is a projection of the newest entry. A table that is just "old rows of another table" collapses into the snapshot.
|
|
32
32
|
- **A surviving table names the invariant it buys** — content-addressed immutable rows buy reproducibility, a monotonic sequence buys ordering/sync, an atomic write boundary buys multi-row atomicity. Drop the requirement and the table drops with it.
|
|
33
|
-
|
|
34
|
-
Table count tracks **requirements, not domain richness** — a rich domain is not entitled to a table per noun.
|
|
33
|
+
- **Table count tracks requirements, not domain richness** — a rich domain is not entitled to a table per noun.
|
|
35
34
|
|
|
36
35
|
## State, rules, and history
|
|
37
36
|
|
|
38
|
-
**One fact has one home, chosen by what kind of fact it is.**
|
|
37
|
+
**One fact has one home, chosen by what kind of fact it is.**
|
|
39
38
|
|
|
40
39
|
| The fact | Home | Example |
|
|
41
40
|
| --- | --- | --- |
|
|
@@ -45,7 +44,7 @@ Table count tracks **requirements, not domain richness** — a rich domain is no
|
|
|
45
44
|
| What a consumer must **replay in order** | the **sequence log** | an `app_events` row keyed `(app_id, sequence)` |
|
|
46
45
|
|
|
47
46
|
- **State becomes a column the moment anything selects on it.** `WHERE state = 'blocked'` takes an index; `WHERE json_extract(metadata, '$.state') = 'blocked'` scans the table and is invisible to every schema check. JSON keeps only what § What earns a table leaves it — detail nothing addresses alone.
|
|
48
|
-
- **A pending-work table mirroring row state is the anti-pattern** — `*_actions`, `*_inbox`, `*_flags
|
|
47
|
+
- **A pending-work table mirroring row state is the anti-pattern** — `*_actions`, `*_inbox`, `*_flags`; it is the most common redundant table in a schema. The tell: resolving one of its rows also updates the entity, so two rows answer one question and are free to disagree. The *open question* is a column beside the state (at most one per row ⇒ a column, § A junction spells many-to-many); the *answer given* is an audit-log row.
|
|
49
48
|
- **Legal transitions live in code, never as rows** — a `status_transitions` table is a state machine the database cannot enforce and the code must re-implement anyway to use.
|
|
50
49
|
|
|
51
50
|
**The two logs are not substitutes**, and no one table serves both:
|
|
@@ -58,36 +57,36 @@ Table count tracks **requirements, not domain richness** — a rich domain is no
|
|
|
58
57
|
| Records | only what **happened** | **attempts too** — `denied`, `failure` |
|
|
59
58
|
| Read by | cursors replaying forward | investigations, at any age |
|
|
60
59
|
|
|
61
|
-
The
|
|
60
|
+
The Scope and Records rows are why neither can hold the other's rows: an event at a scope with no entity has no sequence to take, and a refused attempt in a replay stream would have consumers apply something that never happened.
|
|
62
61
|
|
|
63
62
|
### The audit log's own shape
|
|
64
63
|
|
|
65
|
-
**An audit log outlives every row it names, so it stores what it needs to stay readable without them.**
|
|
64
|
+
**An audit log outlives every row it names, so it stores what it needs to stay readable without them.**
|
|
66
65
|
|
|
67
|
-
- **Denormalize the display at write time** — `actor_label`, `target_label` beside `actor_id` / `target_id`. Ids alone leave the log intact but unreadable once the person or record is deleted
|
|
66
|
+
- **Denormalize the display at write time** — `actor_label`, `target_label` beside `actor_id` / `target_id`. Ids alone leave the log intact but unreadable once the person or record is deleted.
|
|
68
67
|
- **Record the attempt, not the success** — `outcome` (`success | failure | denied`) plus a `reason`. Refused sign-ins and permission denials are most of what anyone opens an audit log for; without the column they cannot be written at all.
|
|
69
68
|
- **Keep the columns product-neutral** — `actor_*` · `action` · `outcome` · `target_*` · `scope_path` · `channel` · `source_ip` · `correlation_id` · `changes_json` serve any domain. Per-level tenancy columns tie the log to today's model; a materialized `scope_path` (`workspace:abc/app:def`) makes "everything under this tenant" one prefix scan and survives a new level appearing — at the price of enforcing the hierarchy in code rather than a `CHECK`.
|
|
70
69
|
|
|
71
70
|
## Scope, not parallel tables
|
|
72
71
|
|
|
73
|
-
One entity that exists at several scopes is **one table with a nullable scope column** — never one table per scope, and never one table shared across entity families.
|
|
72
|
+
One entity that exists at several scopes is **one table with a nullable scope column** — **never** one table per scope, and **never** one table shared across entity families.
|
|
74
73
|
|
|
75
74
|
- **A table shared by several families carries the union of their columns** — one `settings` table for users, apps, and workspaces. Almost nothing can be `NOT NULL`, the payload lands in JSON beyond every constraint, index, and FK, and a new family widens a table other features already depend on. One table per family.
|
|
76
75
|
- **Two tables declared to have "the same columns" are two schemas maintained by hand** — the drift is silent, surfacing as an incomplete copy, never as an error. Collapse them and discriminate by column.
|
|
77
76
|
- **The scope column is the discriminator** (`app_id IS NULL` = parent scope, set = child scope). Copying a scope is then `INSERT … SELECT` over one table with one column rewritten, so source and target cannot disagree about shape.
|
|
78
|
-
- **A nullable owner column
|
|
79
|
-
- **A reserved row can own the shipped defaults.** A fixed-id "system" parent makes the defaults and a tenant's copy the same kind of row, through the same code. It must then be excluded from every tenant-scoped query — state that invariant where the id is defined.
|
|
77
|
+
- **A nullable owner column lets a row exist before its owner does** — a pending enrolment or unclaimed record is creatable before the owner is known, which collapses a `pending_*` / `*_requests` table into the real one.
|
|
78
|
+
- **A reserved row can own the shipped defaults.** A fixed-id "system" parent makes the defaults and a tenant's copy the same kind of row, through the same code. It **must** then be excluded from every tenant-scoped query — state that invariant where the id is defined.
|
|
80
79
|
|
|
81
80
|
## Copying rows between scopes
|
|
82
81
|
|
|
83
|
-
- **A copied junction row is already correct with no remapping** — its endpoints are `slug` references (§ Keys & the shared vocabulary), and a slug means the same thing in every scope. Rewriting ids through a source→copy map is the most error-prone step in a multi-level copy, and a partial failure leaves wiring pointed into another scope rather than raising.
|
|
82
|
+
- **A copied junction row is already correct with no remapping** — its endpoints are `slug` references (the `database.md` rule § Keys & the shared vocabulary), and a slug means the same thing in every scope. Rewriting ids through a source→copy map is the most error-prone step in a multi-level copy, and a partial failure leaves wiring pointed into another scope rather than raising.
|
|
84
83
|
- **Provenance is a soft reference — no FK.** `source_id` must outlive its referent; an FK would either block the source's deletion or erase the lineage.
|
|
85
84
|
- **Store the source's version at copy time** — `version` + `source_version` make "is an upgrade available" a comparison of two stored values, not a content diff.
|
|
86
|
-
- **A copy is a row, never a live read.** Nothing at the child scope reads the parent's row at runtime; propagation happens only through an explicit re-copy, so a local edit is never silently overwritten.
|
|
85
|
+
- **A copy is a row, never a live read.** Nothing at the child scope reads the parent's row at runtime; propagation happens **only** through an explicit re-copy, so a local edit is never silently overwritten.
|
|
87
86
|
|
|
88
87
|
## A junction spells many-to-many — nothing else
|
|
89
88
|
|
|
90
|
-
**A `_map` table is the schema's notation for M:N. Using it for 1:M is a category error** — the junction's own uniqueness admits many parents per child, so the "one parent" rule
|
|
89
|
+
**A `_map` table is the schema's notation for M:N. Using it for 1:M is a category error** — the junction's own uniqueness admits many parents per child, so the "one parent" rule is unenforced from the moment it is written. Cardinality decides between the only two shapes:
|
|
91
90
|
|
|
92
91
|
| Relationship | Shape |
|
|
93
92
|
| --- | --- |
|
|
@@ -95,7 +94,7 @@ One entity that exists at several scopes is **one table with a nullable scope co
|
|
|
95
94
|
| **M:N** — both sides have many | a **`<a>_<b>_map` junction** with a composite unique |
|
|
96
95
|
|
|
97
96
|
- **The test is one question about the child**: can this row ever belong to two parents at once? No ⇒ column. A junction "in case it becomes M:N later" ships the unenforced model today to buy a migration you may never run.
|
|
98
|
-
- **A
|
|
97
|
+
- **A 1:M junction also** makes the association a row that can go missing independently of the child — the child exists correctly while its wiring does not — and forces a join onto the most common read in the system.
|
|
99
98
|
- **A junction carrying only its two endpoints and timestamps is the tell** — a real M:N junction usually earns its own columns (a role, an order, a status); one that never does is a 1:M waiting to be collapsed into a column.
|
|
100
99
|
- **Collapsing deletes a copy step** — the association travels inside the row it belongs to: no second pass to remap, no copy landing with its wiring half-applied.
|
|
101
100
|
- **A pair already recorded elsewhere needs no table at all.** If an append-only log stores `(parent, child)` on every write, the association table is `SELECT DISTINCT` over that log — a cache free to disagree with the log it derives from (§ What earns a table).
|
|
@@ -107,13 +106,13 @@ One entity that exists at several scopes is **one table with a nullable scope co
|
|
|
107
106
|
| Action | Why it fails on an append-only table |
|
|
108
107
|
| --- | --- |
|
|
109
108
|
| `SET NULL` | It is an **UPDATE**. An append-only trigger aborts it, so the parent's deletion fails — with an error naming the trigger, not the constraint. |
|
|
110
|
-
| `CASCADE` | Deletes history to delete a person. The log exists
|
|
111
|
-
| `NO ACTION` | Makes anyone who ever appeared in the log undeletable — the hub defect
|
|
109
|
+
| `CASCADE` | Deletes history to delete a person. The log exists to outlive its subjects. |
|
|
110
|
+
| `NO ACTION` | Makes anyone who ever appeared in the log undeletable — the hub-table defect of the `database.md` rule § Keys & the shared vocabulary. |
|
|
112
111
|
|
|
113
112
|
- **`SET NULL` is the trap** — it reads like a safe relaxation of `NO ACTION` and passes review as one.
|
|
114
|
-
- **Record the actor as a plain column** — the same soft-reference treatment provenance gets (`source_id`, `thread_id`)
|
|
115
|
-
- **`CASCADE` from the append-only side's own parent is
|
|
116
|
-
- **State the exemption where it exists.** A catalog whose rows must not disappear under a referencing row (a service definition, a vocabulary) keeps `NO ACTION` deliberately —
|
|
113
|
+
- **Record the actor as a plain column** — the same soft-reference treatment provenance gets (`source_id`, `thread_id`), so the log keeps naming who acted after the account is gone.
|
|
114
|
+
- **`CASCADE` from the append-only side's own parent is fine** — a cascade is a DELETE, so a `BEFORE UPDATE` trigger never sees it: an App's log dying with the App is legitimate, distinct from erasing a log to delete a person.
|
|
115
|
+
- **State the exemption where it exists.** A catalog whose rows must not disappear under a referencing row (a service definition, a vocabulary) keeps `NO ACTION` deliberately — one line saying so.
|
|
117
116
|
|
|
118
117
|
## Uniqueness with a nullable column
|
|
119
118
|
|
|
@@ -128,28 +127,27 @@ CREATE UNIQUE INDEX <t>_child_slug_unique ON <t> (child_id, slug) WHERE child_
|
|
|
128
127
|
|
|
129
128
|
## Vocabulary / lookup tables
|
|
130
129
|
|
|
131
|
-
A controlled vocabulary earns a **table** only when a user row FKs into it and reads its `label` / `description` at runtime — a service catalog rendered in a picker
|
|
130
|
+
A controlled vocabulary earns a **table** **only** when a user row FKs into it and reads its `label` / `description` at runtime — a service catalog rendered in a picker. Static dev-authored config nobody references by FK stays **config** (§ What earns a table) — a `doc_type` value list. Enumerable is not tabular: a `type`-style column validated against the constants file beats an FK to a seeded mirror. An earned table has a fixed shape: `id` (UUID) · `slug` (UNIQUE) · `label` · optional `description` · `status` · timestamps.
|
|
132
131
|
|
|
133
|
-
- **Seeds are generated, never hand-written** — the source of truth is an authored tree
|
|
132
|
+
- **Seeds are generated, never hand-written** — the source of truth is an authored tree or a shared package, compiled and loaded per § Seeding.
|
|
134
133
|
|
|
135
134
|
## Seeding — authored source, compiled artifact, loaded rows
|
|
136
135
|
|
|
137
136
|
Curated data that ships with the product — vocabularies, catalogs, reference profiles — is **authored in a tree, compiled to SQL, and loaded**. The compiled artifact is build output, not source.
|
|
138
137
|
|
|
139
|
-
|
|
140
|
-
|
|
141
|
-
|
|
142
|
-
seed/sql/*.seed.sql
|
|
143
|
-
|
|
144
|
-
```
|
|
138
|
+
| Stage | Where | Rule |
|
|
139
|
+
| --- | --- | --- |
|
|
140
|
+
| Author | `seed/<data>/**` | committed — the only thing a human edits |
|
|
141
|
+
| Compile | emits `seed/sql/*.seed.sql` | mechanical — parse, validate, emit; no judgment, no network. Output is gitignored and rebuilt on every run |
|
|
142
|
+
| Load | the engine's own client — `wrangler d1 execute`, `psql -f` | idempotent |
|
|
145
143
|
|
|
146
|
-
- **Never commit the compiled artifact.** Rebuilt seconds before it is applied, it cannot go stale
|
|
144
|
+
- **Never commit the compiled artifact.** Rebuilt seconds before it is applied, it cannot go stale, so it owes no drift check and no freshness test; a committed `.sql` would owe both. **Never hand-edit seed SQL** — regenerate it.
|
|
147
145
|
- **The load is idempotent**: UUIDv5 ids derived from the natural key plus `ON CONFLICT(slug) DO UPDATE`, preserving live counts and admin-tuned columns. Re-seeding is a no-op, never a duplicate.
|
|
148
|
-
- **A build step that reads the artifact runs the compiler first
|
|
146
|
+
- **A build step that reads the artifact runs the compiler first** — wire `pretest` / `prebuild`. Bundlers resolve imports at *build* time, so a gitignored artifact breaks a fresh clone with a resolution error rather than a test failure.
|
|
149
147
|
|
|
150
148
|
### Choosing the authoring format
|
|
151
149
|
|
|
152
|
-
**Choose by what the payload is, not by where it lands.**
|
|
150
|
+
**Choose by what the payload is, not by where it lands.** A relational destination argues nothing about the source: rows routinely carry document-valued columns, and the compiler exists to bridge the two shapes. The litmus is one question per field — **is this a scalar a human scans in a table, or prose a human reads in paragraphs?**
|
|
153
151
|
|
|
154
152
|
| Payload | Format | Why |
|
|
155
153
|
| --- | --- | --- |
|
|
@@ -164,7 +162,7 @@ seed/sql/*.seed.sql build output, GITIGNORED — rebuilt on every run
|
|
|
164
162
|
|
|
165
163
|
### Rigidity comes from validators, never from containers
|
|
166
164
|
|
|
167
|
-
**No file format enforces a shape.** CSV checks no types, no required fields, no nesting — not even column count
|
|
165
|
+
**No file format enforces a shape.** CSV checks no types, no required fields, no nesting — not even column count; YAML and JSON check only that the syntax parses. The shape is enforced by a schema or not at all, so a format migration undertaken to gain rigidity buys none.
|
|
168
166
|
|
|
169
167
|
- **Validate at the compile boundary and fail the build**, naming the file and the reason. A compiler that checks only *parseability* ships a typo'd key or a missing map straight to production, where it is served with full authority.
|
|
170
168
|
- **Declare the shape as a schema and share it** between the compiler that writes the column and the code that reads it — one definition, so compile-time and read-time cannot disagree. A `values_json`-style column is opaque to the database; that schema is the only thing standing between it and `unknown` at the read site.
|
|
@@ -173,24 +171,24 @@ seed/sql/*.seed.sql build output, GITIGNORED — rebuilt on every run
|
|
|
173
171
|
|
|
174
172
|
### Canonicalize, never repair
|
|
175
173
|
|
|
176
|
-
Two operations get called "cleaning the data"
|
|
174
|
+
Two operations get called "cleaning the data"; only one is safe:
|
|
177
175
|
|
|
178
176
|
| Operation | Verdict | Why |
|
|
179
177
|
| --- | --- | --- |
|
|
180
178
|
| **Canonicalization** — deterministic and information-preserving: slug folding, diacritic normalization, key and unit ordering | ✅ belongs in the compiler | The same input always yields the same output, and nothing is invented |
|
|
181
179
|
| **Repair** — filling, clamping, defaulting, or dropping content that failed validation | ❌ reject loudly instead | Deciding what the author meant *is* judgment; a repaired row is then served indistinguishably from a curated one |
|
|
182
180
|
|
|
183
|
-
**
|
|
181
|
+
**Never guess at malformed input** — a guessing pipeline swaps a loud rejection for a quiet wrong answer, and for curated data, whose whole value is that a human judged it, that is corruption. Reject with a report: the producer retries, or a human triages.
|
|
184
182
|
|
|
185
183
|
### Ingesting scraped or generated data
|
|
186
184
|
|
|
187
|
-
Automated sources produce **candidate raw material, not rows.** Publish the compile-boundary schema as the ingestion contract and run scraped output through it unchanged — validate, reject loudly on mismatch, queue the survivors for curation. A curator promotes a candidate by adding the judgment the source could not supply: the rationale, the caveat, the editorial line.
|
|
185
|
+
Automated sources produce **candidate raw material, not rows.** Publish the compile-boundary schema as the ingestion contract and run scraped output through it unchanged — validate, reject loudly on mismatch, queue the survivors for curation. A curator promotes a candidate by adding the judgment the source could not supply: the rationale, the caveat, the editorial line. **Never** let an unreviewed extract land directly as a catalog row — that swaps a curated corpus for a scraped one.
|
|
188
186
|
|
|
189
187
|
## Run
|
|
190
188
|
|
|
191
189
|
1. **Route every new fact through § What earns a table** — default to *not* a table; name the left-column property that earns one, or the right-column home it takes instead.
|
|
192
190
|
2. **Classify every fact by § State, rules, and history** — now-state → entity column; rules → code; what-was-done → audit log; replayable → sequence log.
|
|
193
|
-
3. **Check cardinality before any junction** (§ A junction spells many-to-many) and every FK's `ON DELETE`
|
|
194
|
-
4. **Prove uniqueness
|
|
191
|
+
3. **Check cardinality before any junction** (§ A junction spells many-to-many) and every FK's `ON DELETE` — hub edges per the `database.md` rule § Keys & the shared vocabulary, append-only edges per § Foreign keys into and out of append-only tables.
|
|
192
|
+
4. **Prove every uniqueness claim by inserting the forbidden duplicate** (§ Uniqueness with a nullable column).
|
|
195
193
|
5. **For a seed pipeline, walk § Seeding** — format chosen by payload rather than by destination, shape enforced by a schema at the compile boundary, artifact gitignored, correction limited to canonicalization.
|
|
196
194
|
6. **Report as a findings list** — one line per violation: the section, the table/column, the fix.
|
|
@@ -1,65 +1,59 @@
|
|
|
1
1
|
---
|
|
2
2
|
name: test
|
|
3
|
-
description:
|
|
3
|
+
description: "Run markdown UI tests against the running app over Chrome DevTools Protocol (Claude-in-Chrome), recording pass/fail per assertion in a results file. Use for `/test <name>` or 'run my UI tests', 'run the browser tests'."
|
|
4
4
|
argument-hint: [test-name]
|
|
5
5
|
---
|
|
6
6
|
|
|
7
|
-
# Test
|
|
7
|
+
# Test runner (CDP)
|
|
8
8
|
|
|
9
|
-
Run UI
|
|
9
|
+
Run a markdown UI test against the running app through Claude-in-Chrome browser automation, and record each assertion's outcome in a results file.
|
|
10
10
|
|
|
11
11
|
## Prerequisites
|
|
12
12
|
|
|
13
|
-
Complete these steps before executing
|
|
13
|
+
Complete these steps before executing any assertion.
|
|
14
14
|
|
|
15
|
-
### 1. Load
|
|
15
|
+
### 1. Load credentials
|
|
16
16
|
|
|
17
|
-
Read `tests/.env
|
|
17
|
+
Read `tests/.env`:
|
|
18
18
|
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
19
|
+
| Variable | Use |
|
|
20
|
+
| --- | --- |
|
|
21
|
+
| `TEST_USER_EMAIL` / `TEST_USER_PASSWORD` | Login credentials for browser setup |
|
|
22
|
+
| `TEST_BASE_URL` | The root URL the browser opens, e.g. `http://localhost:3000` |
|
|
23
|
+
| `TEST_APP_ID` *(optional)* | The app or workspace instance a test targets; unset, tests run against the default one the base URL serves |
|
|
22
24
|
|
|
23
|
-
If
|
|
25
|
+
If `tests/.env` is missing, stop and tell the user to copy `tests/.env.example` to `tests/.env`.
|
|
24
26
|
|
|
25
27
|
### 2. Connect to Chrome
|
|
26
28
|
|
|
27
|
-
|
|
28
|
-
mcp__claude-in-chrome__tabs_context_mcp with createIfEmpty: true
|
|
29
|
-
```
|
|
30
|
-
|
|
31
|
-
If connection fails: Install Claude-in-Chrome extension, ensure Chrome is running.
|
|
29
|
+
Call `mcp__claude-in-chrome__tabs_context_mcp` with `createIfEmpty: true`. If the connection fails, stop and tell the user to install the Claude-in-Chrome extension and start Chrome.
|
|
32
30
|
|
|
33
|
-
### 3.
|
|
34
|
-
|
|
35
|
-
```
|
|
36
|
-
mcp__claude-in-chrome__tabs_create_mcp
|
|
37
|
-
```
|
|
31
|
+
### 3. Set up the browser
|
|
38
32
|
|
|
39
|
-
|
|
33
|
+
Open a tab with `mcp__claude-in-chrome__tabs_create_mcp`, navigate to `${TEST_BASE_URL}`, and log in with the step 1 credentials if the app asks.
|
|
40
34
|
|
|
41
|
-
### 4. Verify
|
|
35
|
+
### 4. Verify ready state
|
|
42
36
|
|
|
43
|
-
|
|
37
|
+
**Never** run an assertion until the main dashboard is visible.
|
|
44
38
|
|
|
45
39
|
## Execution
|
|
46
40
|
|
|
47
|
-
1.
|
|
48
|
-
2.
|
|
49
|
-
3.
|
|
50
|
-
4.
|
|
51
|
-
5.
|
|
41
|
+
1. Locate the test file at `.github/docs/tests/<test-name>.md`.
|
|
42
|
+
2. If it is not there, list the tests in `.github/docs/tests/`. If that directory does not exist, find how the repo runs its tests: search for `*.test.*`, `*.spec.*`, and `__tests__/`, `test/`, `tests/` directories, and check `package.json` for a `test` script.
|
|
43
|
+
3. Create the results file at `tests/claude-runs/<test-name>-<YYYY-MM-DD-HHmmss>.md`.
|
|
44
|
+
4. Execute the assertions in order, updating each checkbox as you go.
|
|
45
|
+
5. Save the completed results file with the summary header from § Results template.
|
|
52
46
|
|
|
53
|
-
## Checkbox
|
|
47
|
+
## Checkbox markers
|
|
54
48
|
|
|
55
|
-
| Marker | Meaning
|
|
56
|
-
|
|
|
57
|
-
| `[x]`
|
|
58
|
-
| `[!]`
|
|
59
|
-
| `[-]`
|
|
60
|
-
| `[ ]`
|
|
49
|
+
| Marker | Meaning |
|
|
50
|
+
| --- | --- |
|
|
51
|
+
| `[x]` | Passed |
|
|
52
|
+
| `[!]` | Failed — add `**FAILED**: <reason>` |
|
|
53
|
+
| `[-]` | Skipped |
|
|
54
|
+
| `[ ]` | Not run |
|
|
61
55
|
|
|
62
|
-
## Results
|
|
56
|
+
## Results template
|
|
63
57
|
|
|
64
58
|
```markdown
|
|
65
59
|
# Test Results: <Test Name>
|
|
@@ -92,13 +86,15 @@ Confirm main dashboard is visible before proceeding.
|
|
|
92
86
|
... (test content with updated checkboxes)
|
|
93
87
|
```
|
|
94
88
|
|
|
95
|
-
## Error
|
|
89
|
+
## Error handling
|
|
96
90
|
|
|
97
|
-
|
|
98
|
-
|
|
99
|
-
|
|
100
|
-
|
|
91
|
+
| Error | Action |
|
|
92
|
+
| --- | --- |
|
|
93
|
+
| Network error | Retry once, then mark failed |
|
|
94
|
+
| Timeout | Mark failed with a timeout note |
|
|
95
|
+
| Element not found | Screenshot, mark failed, continue |
|
|
96
|
+
| Browser disconnect | Stop, save partial results, tell the user |
|
|
101
97
|
|
|
102
98
|
## Screenshots
|
|
103
99
|
|
|
104
|
-
Take
|
|
100
|
+
Take a screenshot before each major section, on every failure, and after completion.
|