@metaobjectsdev/sdk 0.22.1 → 0.23.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.
|
@@ -976,7 +976,28 @@ mapping).
|
|
|
976
976
|
|
|
977
977
|
## Requirements — capability ledger (opt-in)
|
|
978
978
|
|
|
979
|
-
|
|
979
|
+
**This capability exists whether or not the project uses it yet.** `requirement.functional` and `requirement.architectural` are registered metadata types, declared in `metaobjects/` beside the entities they describe and loaded by the same loader — no side file, no bespoke parser. They record *why* each part of the model exists, so a field with no reason to exist becomes visible as one.
|
|
980
|
+
|
|
981
|
+
Reach for it when the project needs to answer any of:
|
|
982
|
+
|
|
983
|
+
- **"Why is this field here?"** — an L5 requirement binds a claim to a specific member. Authoring these exhaustively is what surfaces columns nothing reads and vocabularies nobody documented.
|
|
984
|
+
- **"What is broken but known?"** — `@status: partial` plus `@disposition: accepted | deferred`. Absent disposition means *undecided*, and `meta verify` counts those: the gaps nobody has ruled on.
|
|
985
|
+
- **"What did we build and then retire?"** — `@status: abandoned` is the one status where a dangling `@implementedBy` is *correct*, so the record survives the deletion.
|
|
986
|
+
- **"What have we committed to build?"** — `@status: planned`. Its references may dangle, and it never counts toward object coverage.
|
|
987
|
+
- **"Which ticket covers this?"** — `@trackedBy`.
|
|
988
|
+
|
|
989
|
+
Every requirement must be **violable**: if you cannot say what breaking it looks like, it is a description, not a requirement.
|
|
990
|
+
|
|
991
|
+
If the project declares any `requirement.*` node, `references/requirements.md` is installed with the full authoring rules. If it does not and you are adding the first one, the shape is:
|
|
992
|
+
|
|
993
|
+
```yaml
|
|
994
|
+
- requirement.architectural:
|
|
995
|
+
name: everyStoredRowIsAddressable
|
|
996
|
+
status: live
|
|
997
|
+
statement: Every persisted row declares the identity by which it is addressed.
|
|
998
|
+
violation: A row that can be inserted but never pointed at.
|
|
999
|
+
implementedBy: [acme::shop::Order]
|
|
1000
|
+
```
|
|
980
1001
|
|
|
981
1002
|
---
|
|
982
1003
|
|
|
@@ -27,19 +27,63 @@ key. *"Things are persisted"* is not, and is a description rather than a require
|
|
|
27
27
|
rule kills *"the system is reliable"*. If you cannot say what breaking it looks like,
|
|
28
28
|
delete it.
|
|
29
29
|
|
|
30
|
-
**
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
Regrouping *moves* a node; it does not edit a parent string.
|
|
30
|
+
**Four prose slots, and `statement` is the one that means "description".** A requirement can
|
|
31
|
+
also carry the common `title`, `description` and `notes`, and they overlap badly unless you
|
|
32
|
+
decide the split before writing any of them:
|
|
34
33
|
|
|
35
|
-
|
|
36
|
-
|
|
34
|
+
- `title` — a short **noun-phrase** label (`name` is an identifier; this is what an index shows)
|
|
35
|
+
- `statement` — **the claim**. This IS the description of what the requirement is
|
|
36
|
+
- `violation` — **the counterexample** that makes the claim checkable
|
|
37
|
+
- `description` — **the scope**: what the claim covers, what it deliberately does not, and
|
|
38
|
+
which sibling entry owns the rest
|
|
39
|
+
- `notes` — **the evidence**: how you know the `status` is true — citations, vocabularies, the
|
|
40
|
+
control you ran to prove an absence was real
|
|
41
|
+
|
|
42
|
+
Two failure modes, both of which look like diligence. A `description` that **paraphrases the
|
|
43
|
+
statement** is padding, and it makes every later reader trust the ledger less — leave it off
|
|
44
|
+
instead, it is optional. A `description` that **narrates the evidence** belongs in `notes`;
|
|
45
|
+
the tell is a fact you had to read the implementation to learn. Mechanical test for the last
|
|
46
|
+
line: *would this sentence have to change if the code changed but the model did not?* Then it
|
|
47
|
+
is `notes`.
|
|
48
|
+
|
|
49
|
+
**Hierarchy is nesting, and links live at the bottom.** L1 solution, L2 segment, L3
|
|
50
|
+
service — these never reference the model. **L4** binds an object, **L5** binds a field,
|
|
51
|
+
view or identity. `implementedBy` above L4 is an error. Regrouping *moves* a node; it does
|
|
52
|
+
not edit a parent string.
|
|
53
|
+
|
|
54
|
+
**L1–L3 are levels of abstraction and ownership in the problem domain** — whose need is
|
|
55
|
+
this, and at what altitude — and are NEVER a directory, package, deployable or module.
|
|
56
|
+
Technical constructs appear only at L4/L5, which is the allocation step. Test every node:
|
|
57
|
+
*if a refactor that changes no behaviour would force it to move, its level is wrong.*
|
|
58
|
+
|
|
59
|
+
**Architectural requirements are the other kind.** `requirement.architectural` is flat by
|
|
60
|
+
default — a uuid-PK rule, change attribution, tenant scoping. Its check is *universality*
|
|
37
61
|
rather than existence, so one that is `live` and claimed by nothing fails: a policy
|
|
38
|
-
declared and applied to nothing.
|
|
62
|
+
declared and applied to nothing. A `@level` is OPTIONAL here and opts the node into a tree
|
|
63
|
+
(for organising non-functional requirements under a quality taxonomy); once levelled, the
|
|
64
|
+
same nesting and link-floor rules apply as to a functional node.
|
|
39
65
|
|
|
40
66
|
`@status` is a closed enum enforced by the loader, so a typo fails the load rather than
|
|
41
67
|
silently disabling the entry.
|
|
42
68
|
|
|
69
|
+
**Record gaps rather than rounding them off.** `partial` says *this works and here is what
|
|
70
|
+
is wrong with it*, and it is the most useful status in the enum — a ledger with none is
|
|
71
|
+
usually one nobody read carefully. Then say what was DECIDED, which is a separate question:
|
|
72
|
+
|
|
73
|
+
- `@disposition: accepted` — understood, deliberately not being closed
|
|
74
|
+
- `@disposition: deferred` — will be closed, not now (name a ticket in `@trackedBy`, or
|
|
75
|
+
`verify` warns; deferring without one is how a known problem becomes an unknown one)
|
|
76
|
+
- **absent** — undecided, and that is a real state. `verify` counts these, because
|
|
77
|
+
*"which gaps has nobody ruled on?"* is the question a review exists to answer.
|
|
78
|
+
|
|
79
|
+
A `partial` nobody intends to finish is usually `abandoned` — built then deliberately
|
|
80
|
+
retired, the one status where a dangling reference is correct.
|
|
81
|
+
|
|
82
|
+
**`status: planned` locks in work you have not started.** Its references may dangle (write
|
|
83
|
+
the requirement before the entity), and it never counts toward object coverage — otherwise
|
|
84
|
+
declaring an intention would clear the unclaimed-entity warning and the gate would measure
|
|
85
|
+
ambition rather than work.
|
|
86
|
+
|
|
43
87
|
```yaml
|
|
44
88
|
- requirement.functional:
|
|
45
89
|
name: Pacing
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@metaobjectsdev/sdk",
|
|
3
|
-
"version": "0.
|
|
3
|
+
"version": "0.23.0",
|
|
4
4
|
"description": "Workspace helpers and agent-docs utilities for MetaObjects projects.",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"main": "./dist/index.js",
|
|
@@ -56,7 +56,7 @@
|
|
|
56
56
|
"access": "public"
|
|
57
57
|
},
|
|
58
58
|
"dependencies": {
|
|
59
|
-
"@metaobjectsdev/metadata": "0.
|
|
59
|
+
"@metaobjectsdev/metadata": "0.23.0",
|
|
60
60
|
"zod": "^3.23.0"
|
|
61
61
|
},
|
|
62
62
|
"devDependencies": {
|