ek9_create_requirement
Writes the requirement nodes as flat markdown files under .ek9-ai/requirements/ (one atomic batch, each keyed by its frozen slug) and answers the editor envelope: status (applied | ready | conflicts), written, edits[] and summary naming the ids created.
When to use it
'Record a new requirement' is one call: {nodes:[{slug, title, body}]} for a root, add parentId:'REQ:x' for a child; several nodes naming each other make a whole subtree.
When not to use it
- Editing an existing node's body/title/position, or retiring or deleting it - use
ek9_update_requirement(it cannot rename a slug: create a replacement here, then retire the old node with supersededBy). - Anchoring an EXISTING @Test program to a requirement - use
ek9_anchor_test(ek9_add_program's requirementId covers only a freshly-scaffolded test).
Details
Slug is FROZEN at creation ([a-z0-9-]+) and is the key every @Test and parentId joins on; a collision against the derived id-set is REFUSED, never auto-suffixed — pick a distinctive slug and re-call. prefix is the closed set REQ/CTRL/CAP/CON, immutable once set; timestamps, version and changelog are server-stamped, never caller-supplied. Atomic: one bad node (invalid-slug, slug-collision, duplicate-in-batch, parent-not-found, parent-retired, batch-cycle) blocks the whole batch, and only the child file is ever written — parents are never edited.
Arguments
| Argument | Type | Required | What it is |
|---|---|---|---|
dryRun | boolean | When true nothing is written; the response shows the would-be edits with status:'ready'. | |
nodes | array of object | yes | The requirements to create, in intended order. A member's parentId may name an existing requirement OR another member of this same batch, which is what lets a whole subtree be created in one call. |
terse | boolean | Retained boolean alias for verbosity:'summary'. | |
verbosity | string: full | summary | none | Response size: full (default) carries each edit's full content; summary drops the edit bodies; none collapses edits[] to a count. |
Recorded calls
Real calls, recorded against small projects and checked on every build - a changed answer fails it. 3 of the 4 recorded are shown.
Create requirement conflicts
Request
{
"nodes" : [ {
"authorKind" : "human",
"authorName" : "Steve Limb",
"body" : "# Intent\n\nFine.",
"slug" : "perfectly-fine",
"title" : "Fine"
}, {
"authorKind" : "human",
"authorName" : "Steve Limb",
"body" : "# Intent\n\nBad.",
"slug" : "Not A Slug",
"title" : "Bad"
} ]
}
Response
{
"conflicts" : [ {
"detail" : "a slug must match [a-z0-9-]+ and the prefix must be from the closed registry",
"kind" : "invalid-slug",
"subject" : "Not A Slug"
} ],
"edits" : [ ],
"meta" : {
"serverMs" : "<timing>"
},
"risk" : {
"crossesModuleBoundary" : false,
"estimatedSeverity" : "trivial",
"fileCount" : 0,
"lineCount" : 0,
"touchesPublicApi" : false,
"touchesTests" : false
},
"status" : "conflicts",
"summary" : "Would create nothing — 1 conflict(s); a create is atomic",
"wouldBeDiagnostics" : [ ],
"written" : false
}
Create requirement dry run
Request
{
"dryRun" : true,
"nodes" : [ {
"authorKind" : "human",
"authorName" : "Steve Limb",
"body" : "# Intent\n\nWhy.",
"slug" : "fraud-screening",
"title" : "Screen payments"
} ]
}
Response
{
"conflicts" : [ ],
"edits" : [ {
"after" : "---\nreq_id: REQ:fraud-screening\ntitle: Screen payments\nretired: false\nversion: 0.1.0\nparent_ref: null\nrank_key: V\nsuperseded_by: null\nconfirmed_at: null\ncreated_at: <instant>\nupdated_at: <instant>\nrule_anchors: []\nown_anchors: []\nabout_concepts: []\nmeta: {}\nauthors:\n - {kind: human, name: Steve Limb}\nchangelog:\n - {at: <instant>, by: human::Steve Limb, action: create}\n---\n\n# Intent\n\nWhy.\n",
"file" : ".ek9-ai/requirements/REQ-fraud-screening.md",
"type" : "create"
} ],
"meta" : {
"serverMs" : "<timing>"
},
"risk" : {
"crossesModuleBoundary" : false,
"estimatedSeverity" : "trivial",
"fileCount" : 1,
"lineCount" : 0,
"touchesPublicApi" : false,
"touchesTests" : false
},
"status" : "ready",
"summary" : "Would create 1 requirement (REQ:fraud-screening)",
"wouldBeDiagnostics" : [ ],
"written" : false
}
Create requirement root apply
Request
{
"nodes" : [ {
"authorKind" : "human",
"authorName" : "Steve Limb",
"body" : "# Intent\n\nEvery payment is screened.",
"slug" : "fraud-screening",
"title" : "Screen inbound payments for fraud"
} ]
}
Response
{
"conflicts" : [ ],
"edits" : [ {
"after" : "---\nreq_id: REQ:fraud-screening\ntitle: Screen inbound payments for fraud\nretired: false\nversion: 0.1.0\nparent_ref: null\nrank_key: V\nsuperseded_by: null\nconfirmed_at: null\ncreated_at: <instant>\nupdated_at: <instant>\nrule_anchors: []\nown_anchors: []\nabout_concepts: []\nmeta: {}\nauthors:\n - {kind: human, name: Steve Limb}\nchangelog:\n - {at: <instant>, by: human::Steve Limb, action: create}\n---\n\n# Intent\n\nEvery payment is screened.\n",
"file" : ".ek9-ai/requirements/REQ-fraud-screening.md",
"type" : "create"
} ],
"meta" : {
"serverMs" : "<timing>"
},
"risk" : {
"crossesModuleBoundary" : false,
"estimatedSeverity" : "trivial",
"fileCount" : 1,
"lineCount" : 0,
"touchesPublicApi" : false,
"touchesTests" : false
},
"status" : "applied",
"summary" : "Created 1 requirement (REQ:fraud-screening)",
"wouldBeDiagnostics" : [ ],
"written" : true
}