@nurix/etna 0.19.67 → 0.19.68
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/harness-index.json +1 -1
- package/data/harnesses/code/agents/maintenance.md +1 -0
- package/data/harnesses/code/harness.json +2 -2
- package/data/harnesses/code/hooks/awareness.mjs +69 -0
- package/data/harnesses/code/hooks/compliance.mjs +1 -14
- package/data/harnesses/code/hooks/lib/approved.mjs +30 -0
- package/data/harnesses/code/skills/documentation/references/frontmatter.md +1 -1
- package/data/harnesses/code/skills/documentation/templates/Readme.md +2 -0
- package/data/harnesses/code/skills/documentation/templates/structure.md +1 -0
- package/data/harnesses/delivery/agents/maintenance.md +1 -0
- package/data/harnesses/delivery/harness.json +2 -2
- package/data/harnesses/delivery/skills/documentation/references/frontmatter.md +1 -1
- package/data/harnesses/delivery/skills/documentation/templates/Readme.md +2 -0
- package/data/harnesses/delivery/skills/documentation/templates/structure.md +1 -0
- package/data/harnesses/etna/agents/maintenance.md +1 -0
- package/data/harnesses/etna/harness.json +2 -2
- package/data/harnesses/etna/skills/documentation/references/frontmatter.md +1 -1
- package/data/harnesses/etna/skills/documentation/templates/Readme.md +2 -0
- package/data/harnesses/etna/skills/documentation/templates/structure.md +1 -0
- package/package.json +2 -2
package/data/harness-index.json
CHANGED
|
@@ -149,6 +149,7 @@ docs/
|
|
|
149
149
|
│ ├── plans/ # Implementation plans (Status field required)
|
|
150
150
|
│ ├── migrations/ # One-shot migration/upgrade runbooks (YYYY-MM-DD-{slug}.md; outcome-stamped then frozen)
|
|
151
151
|
│ ├── journal.md # Append-only mid-execution knowledge capture (one line per fact; resolves by landing in its owning doc) — author-created, never scaffolded
|
|
152
|
+
│ ├── sessions/ # Per-session gate logs (YYYY-MM-DD-{sid}.md) — machinery-written records, never drained, never edited down; created by the first gate event, never scaffolded
|
|
152
153
|
│ ├── brainstorms/ # Harvested brainstorm sessions ({topic}/) — user decides kept (committed) or deleted; Readme.md is the index
|
|
153
154
|
│ ├── research/ # Deep-research records ({topic}/ — README.md synthesis + findings.md + sources.md); frozen, cited, owns no code
|
|
154
155
|
│ └── backlog.md ✱ # Tracked work items by priority (P0-P3)
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
{
|
|
2
2
|
"harness": "code",
|
|
3
3
|
"name": "code",
|
|
4
|
-
"version": "3.8.
|
|
4
|
+
"version": "3.8.2",
|
|
5
5
|
"files": [
|
|
6
6
|
".prettierignore",
|
|
7
7
|
".prettierrc.json",
|
|
@@ -15,5 +15,5 @@
|
|
|
15
15
|
"docs/memory/main.md",
|
|
16
16
|
".mcp.json"
|
|
17
17
|
],
|
|
18
|
-
"digest": "
|
|
18
|
+
"digest": "2dcea7420200"
|
|
19
19
|
}
|
|
@@ -30,6 +30,8 @@ import {
|
|
|
30
30
|
stateDir,
|
|
31
31
|
recordTouched,
|
|
32
32
|
} from "./lib/state.mjs";
|
|
33
|
+
import { frozenStatus } from "./lib/frozen.mjs";
|
|
34
|
+
import { approvedPackages } from "./lib/approved.mjs";
|
|
33
35
|
|
|
34
36
|
const today = () => new Date().toISOString().slice(0, 10);
|
|
35
37
|
|
|
@@ -360,6 +362,68 @@ function detectRenames(projectDir, command, meta, rows) {
|
|
|
360
362
|
}
|
|
361
363
|
}
|
|
362
364
|
|
|
365
|
+
// Working-tree paths git sees as changed or untracked — the outcome detector's ground truth.
|
|
366
|
+
// Fails open: no git, or a git error, reads as an empty list.
|
|
367
|
+
function dirtyPaths(projectDir) {
|
|
368
|
+
const res = spawnSync("git", ["status", "--porcelain"], { cwd: projectDir, encoding: "utf8", timeout: 5000 });
|
|
369
|
+
if (res.status !== 0) return [];
|
|
370
|
+
return (res.stdout || "")
|
|
371
|
+
.split("\n")
|
|
372
|
+
.filter(Boolean)
|
|
373
|
+
.map((line) => {
|
|
374
|
+
const p = line.slice(3);
|
|
375
|
+
return p.includes(" -> ") ? p.split(" -> ")[1] : p; // a rename reports both sides; the new path is the live one
|
|
376
|
+
})
|
|
377
|
+
.map((p) => p.replace(/^"|"$/g, ""));
|
|
378
|
+
}
|
|
379
|
+
|
|
380
|
+
// OUTCOME RECOMPUTATION — the gates deny wrong actions, but an action can be routed around by
|
|
381
|
+
// any tool that writes bytes (a manifest written by a script, a frozen record touched by sed).
|
|
382
|
+
// State cannot be routed around: recompute the two outcomes the gates guard and raise what
|
|
383
|
+
// changed as rows. Dedupe against the queue so a retry loop raises one row, not ten.
|
|
384
|
+
function detectOutcomes(projectDir, meta, rows) {
|
|
385
|
+
const existing = readQueue(projectDir);
|
|
386
|
+
const raised = (needle) => existing.some((r) => r.body.includes(needle)) || rows.some((r) => r.includes(needle));
|
|
387
|
+
for (const rel of dirtyPaths(projectDir)) {
|
|
388
|
+
if (rel.includes("node_modules/") || rel.includes(".bkp.")) continue;
|
|
389
|
+
if (path.posix.basename(rel) === "package.json") {
|
|
390
|
+
const approved = approvedPackages(projectDir);
|
|
391
|
+
if (approved.size === 0) continue; // no table installed — nothing to enforce
|
|
392
|
+
let manifest;
|
|
393
|
+
try {
|
|
394
|
+
manifest = JSON.parse(readSafe(path.join(projectDir, rel)));
|
|
395
|
+
} catch (e) {
|
|
396
|
+
continue;
|
|
397
|
+
}
|
|
398
|
+
const names = [...Object.keys(manifest.dependencies || {}), ...Object.keys(manifest.devDependencies || {})];
|
|
399
|
+
for (const name of names) {
|
|
400
|
+
if (approved.has(name) || raised(`\`${name}\` (package-off-catalog`)) continue;
|
|
401
|
+
rows.push(
|
|
402
|
+
formatAutoRow({
|
|
403
|
+
...meta,
|
|
404
|
+
kind: "package-off-catalog",
|
|
405
|
+
description: `${rel} declares \`${name}\` (package-off-catalog), absent from the approved table`,
|
|
406
|
+
action: "remove the dependency, or add it to .claude/hooks/approved-packages.md by explicit user decision",
|
|
407
|
+
})
|
|
408
|
+
);
|
|
409
|
+
}
|
|
410
|
+
}
|
|
411
|
+
if (rel.startsWith("docs/history/")) {
|
|
412
|
+
const frozen = frozenStatus(projectDir, rel);
|
|
413
|
+
if (frozen.frozen && !raised(`${rel} is a frozen record`)) {
|
|
414
|
+
rows.push(
|
|
415
|
+
formatAutoRow({
|
|
416
|
+
...meta,
|
|
417
|
+
kind: "frozen-record-edited",
|
|
418
|
+
description: `${rel} is a frozen record and carries uncommitted modifications (${frozen.reason})`,
|
|
419
|
+
action: "revert the edit — a correction is a new dated entry that links back",
|
|
420
|
+
})
|
|
421
|
+
);
|
|
422
|
+
}
|
|
423
|
+
}
|
|
424
|
+
}
|
|
425
|
+
}
|
|
426
|
+
|
|
363
427
|
function postToolUse(projectDir, payload) {
|
|
364
428
|
const meta = {
|
|
365
429
|
date: today(),
|
|
@@ -371,11 +435,16 @@ function postToolUse(projectDir, payload) {
|
|
|
371
435
|
const rows = [];
|
|
372
436
|
if (payload.tool_name === "Bash") {
|
|
373
437
|
detectRenames(projectDir, input.command, meta, rows);
|
|
438
|
+
detectOutcomes(projectDir, meta, rows);
|
|
374
439
|
} else {
|
|
375
440
|
const rel = relIfInside(projectDir, input.file_path || input.notebook_path);
|
|
376
441
|
if (rel) detectorForFile(projectDir, rel, meta, rows);
|
|
377
442
|
// Editing a feature doc's frontmatter can orphan globs the same way a rename can.
|
|
378
443
|
if (rel && rel.startsWith("docs/features/")) detectRenames(projectDir, "git mv", meta, rows);
|
|
444
|
+
// A manifest or history file written by a non-Bash tool is the same evasion surface.
|
|
445
|
+
if (rel && (path.posix.basename(rel) === "package.json" || rel.startsWith("docs/history/"))) {
|
|
446
|
+
detectOutcomes(projectDir, meta, rows);
|
|
447
|
+
}
|
|
379
448
|
}
|
|
380
449
|
appendRows(projectDir, rows);
|
|
381
450
|
}
|
|
@@ -13,6 +13,7 @@ import { readQueue, countRows, askedThisSession, recordAsked } from "./lib/state
|
|
|
13
13
|
import { frozenStatus } from "./lib/frozen.mjs";
|
|
14
14
|
import { undischargedRows } from "./lib/ledger.mjs";
|
|
15
15
|
import { appendEvent, unresolvedDenials, sessionLogPath } from "./lib/session-log.mjs";
|
|
16
|
+
import { approvedPackages } from "./lib/approved.mjs";
|
|
16
17
|
|
|
17
18
|
function readSafe(file) {
|
|
18
19
|
try {
|
|
@@ -240,20 +241,6 @@ function commitGate(projectDir, sessionId) {
|
|
|
240
241
|
return null;
|
|
241
242
|
}
|
|
242
243
|
|
|
243
|
-
// Package names approved in .claude/hooks/approved-packages.md (plus testing.md frameworks and general.md).
|
|
244
|
-
function approvedPackages(projectDir) {
|
|
245
|
-
const names = new Set();
|
|
246
|
-
const sources = [
|
|
247
|
-
path.join(projectDir, ".claude", "hooks", "approved-packages.md"),
|
|
248
|
-
path.join(projectDir, ".claude", "rules", "general.md"),
|
|
249
|
-
path.join(projectDir, ".claude", "rules", "testing.md"),
|
|
250
|
-
];
|
|
251
|
-
for (const src of sources) {
|
|
252
|
-
const text = readSafe(src);
|
|
253
|
-
for (const m of text.matchAll(/`(@?[a-z0-9][\w./-]*)`/g)) names.add(m[1]);
|
|
254
|
-
}
|
|
255
|
-
return names;
|
|
256
|
-
}
|
|
257
244
|
|
|
258
245
|
// A token must parse as an npm package spec — name or @scope/name, optional @range tail —
|
|
259
246
|
// before it may be judged against the table. Everything else on an install line (redirections
|
|
@@ -0,0 +1,30 @@
|
|
|
1
|
+
// harness/code/hooks/lib/approved.mjs — the approved-package set, one reader shared by the
|
|
2
|
+
// PreToolUse install gate (compliance) and the PostToolUse outcome detector (awareness), so
|
|
3
|
+
// "blocked at install" and "flagged in the manifest" can never disagree about the table.
|
|
4
|
+
|
|
5
|
+
import fs from "node:fs";
|
|
6
|
+
import path from "node:path";
|
|
7
|
+
|
|
8
|
+
function readSafe(file) {
|
|
9
|
+
try {
|
|
10
|
+
return fs.readFileSync(file, "utf8");
|
|
11
|
+
} catch (e) {
|
|
12
|
+
return "";
|
|
13
|
+
}
|
|
14
|
+
}
|
|
15
|
+
|
|
16
|
+
// Package names approved in .claude/hooks/approved-packages.md (plus testing.md frameworks and
|
|
17
|
+
// general.md). Empty set ⇒ no rules installed ⇒ nothing to enforce.
|
|
18
|
+
export function approvedPackages(projectDir) {
|
|
19
|
+
const names = new Set();
|
|
20
|
+
const sources = [
|
|
21
|
+
path.join(projectDir, ".claude", "hooks", "approved-packages.md"),
|
|
22
|
+
path.join(projectDir, ".claude", "rules", "general.md"),
|
|
23
|
+
path.join(projectDir, ".claude", "rules", "testing.md"),
|
|
24
|
+
];
|
|
25
|
+
for (const src of sources) {
|
|
26
|
+
const text = readSafe(src);
|
|
27
|
+
for (const m of text.matchAll(/`(@?[a-z0-9][\w./-]*)`/g)) names.add(m[1]);
|
|
28
|
+
}
|
|
29
|
+
return names;
|
|
30
|
+
}
|
|
@@ -12,7 +12,7 @@ When creating or updating a feature doc, derive its **`owns:` frontmatter** —
|
|
|
12
12
|
|
|
13
13
|
## How to derive the frontmatter
|
|
14
14
|
|
|
15
|
-
A feature doc's ownership frontmatter is `owns:` (required), `module:` (optional), `keywords:` (required), and `status:` (required). An optional `last-reviewed:` date (stamped whenever the doc is substantively reviewed or updated) gives the `maintenance` agent a staleness signal to rank its audits by — it is tooling metadata, never narrated in the body. `type:` (required — the genre, enum = the template names) and `rev:` (generator-written generation stamp) are the same class: external tooling reads them, sessions **preserve them on edits** and never narrate or inject them. The `maintenance` agent stamps `type:` on docs that predate the key.
|
|
15
|
+
A feature doc's ownership frontmatter is `owns:` (required), `module:` (optional), `keywords:` (required), and `status:` (required). An optional `last-reviewed:` date (stamped whenever the doc is substantively reviewed or updated) gives the `maintenance` agent a staleness signal to rank its audits by — it is tooling metadata, never narrated in the body. `type:` (required — the genre, enum = the template names) and `rev:` (generator-written generation stamp) are the same class: external tooling reads them, sessions **preserve them on edits** and never narrate or inject them. The `maintenance` agent stamps `type:` on docs that predate the key. `slug:` completes the set on generated docs: the identity key, minted once at creation and never re-derived from a display name — in the repo the filename is the slug, and the `maintenance` agent re-aligns the two when they diverge.
|
|
16
16
|
|
|
17
17
|
**1. `owns:`** (the path scope)
|
|
18
18
|
|
|
@@ -30,6 +30,8 @@ One file per template. Every template is either a **truth document** (states cur
|
|
|
30
30
|
| Backlog | [backlog.md](backlog.md) | Record (append-only) |
|
|
31
31
|
| Memory (main agent) | [memory-main.md](memory-main.md) | Record (append-only ledger) |
|
|
32
32
|
|
|
33
|
+
**The `type:` enum lives here.** A doc's `type:` frontmatter takes its value from this table — one genre per template (`feature`, `architecture-decision`, `non-goals`, …). External generators consume this list rather than defining their own; a type this table does not name defaults to `docs/architecture/` placement and is never added to the protected-files list.
|
|
34
|
+
|
|
33
35
|
**Baseline scaffolds** — files that must exist after every baseline; the `maintenance` agent (baseline mode) creates any that are missing: [docs-readme.md](docs-readme.md), [structure.md](structure.md), [changelog-index.md](changelog-index.md), [backlog.md](backlog.md), [memory-main.md](memory-main.md), and [root-readme.md](root-readme.md) (never overwriting an existing root README).
|
|
34
36
|
|
|
35
37
|
**Ownership.** A feature doc is the canonical reference for the code paths in its **`owns:` frontmatter** — the only ownership key. To find what a doc owns, read its `owns:` globs; to find the doc for a path, match the path against the injected ownership index (the union of every feature's `owns:` globs), narrower glob wins. See [`../references/frontmatter.md`](../references/frontmatter.md) for turning code into `owns:` globs.
|
|
@@ -31,6 +31,7 @@ Each topic has one canonical location. Read from here, not from plans or changel
|
|
|
31
31
|
| Historical plans | `docs/history/plans/` | YYYY-MM-DD-name.md |
|
|
32
32
|
| Change records | `docs/history/changelog/` | `YYYY-MM-DD-{three-words}.md` — one per unit of work, written at commit time |
|
|
33
33
|
| Migration runbooks | `docs/history/migrations/` | YYYY-MM-DD-name.md |
|
|
34
|
+
| Session gate logs | `docs/history/sessions/` | `YYYY-MM-DD-{sid}.md` — machinery-written; denials and their resolutions, appended, never edited down |
|
|
34
35
|
| Deep-research artifacts | `docs/history/research/{topic}/` | README.md + findings.md + sources.md |
|
|
35
36
|
| Brainstorm design records | `docs/research/{topic}-brainstorm/` (active; legacy `-brainstorming/`) → `docs/history/brainstorms/{topic}/` (harvested; user deletes or commits) | thesis.md + forks.md + ledger.md + state.md |
|
|
36
37
|
| Backlog | `docs/history/` | backlog.md |
|
|
@@ -149,6 +149,7 @@ docs/
|
|
|
149
149
|
│ ├── plans/ # Implementation plans (Status field required)
|
|
150
150
|
│ ├── migrations/ # One-shot migration/upgrade runbooks (YYYY-MM-DD-{slug}.md; outcome-stamped then frozen)
|
|
151
151
|
│ ├── journal.md # Append-only mid-execution knowledge capture (one line per fact; resolves by landing in its owning doc) — author-created, never scaffolded
|
|
152
|
+
│ ├── sessions/ # Per-session gate logs (YYYY-MM-DD-{sid}.md) — machinery-written records, never drained, never edited down; created by the first gate event, never scaffolded
|
|
152
153
|
│ ├── brainstorms/ # Harvested brainstorm sessions ({topic}/) — user decides kept (committed) or deleted; Readme.md is the index
|
|
153
154
|
│ ├── research/ # Deep-research records ({topic}/ — README.md synthesis + findings.md + sources.md); frozen, cited, owns no code
|
|
154
155
|
│ └── backlog.md ✱ # Tracked work items by priority (P0-P3)
|
|
@@ -1,12 +1,12 @@
|
|
|
1
1
|
{
|
|
2
2
|
"harness": "delivery",
|
|
3
3
|
"name": "delivery",
|
|
4
|
-
"version": "0.2.
|
|
4
|
+
"version": "0.2.6",
|
|
5
5
|
"files": [
|
|
6
6
|
".prettierignore",
|
|
7
7
|
".prettierrc.json",
|
|
8
8
|
".vscode/settings.json"
|
|
9
9
|
],
|
|
10
10
|
"seeds": [],
|
|
11
|
-
"digest": "
|
|
11
|
+
"digest": "5f761b31c27a"
|
|
12
12
|
}
|
|
@@ -12,7 +12,7 @@ When creating or updating a feature doc, derive its **`owns:` frontmatter** —
|
|
|
12
12
|
|
|
13
13
|
## How to derive the frontmatter
|
|
14
14
|
|
|
15
|
-
A feature doc's ownership frontmatter is `owns:` (required), `module:` (optional), `keywords:` (required), and `status:` (required). An optional `last-reviewed:` date (stamped whenever the doc is substantively reviewed or updated) gives the `maintenance` agent a staleness signal to rank its audits by — it is tooling metadata, never narrated in the body. `type:` (required — the genre, enum = the template names) and `rev:` (generator-written generation stamp) are the same class: external tooling reads them, sessions **preserve them on edits** and never narrate or inject them. The `maintenance` agent stamps `type:` on docs that predate the key.
|
|
15
|
+
A feature doc's ownership frontmatter is `owns:` (required), `module:` (optional), `keywords:` (required), and `status:` (required). An optional `last-reviewed:` date (stamped whenever the doc is substantively reviewed or updated) gives the `maintenance` agent a staleness signal to rank its audits by — it is tooling metadata, never narrated in the body. `type:` (required — the genre, enum = the template names) and `rev:` (generator-written generation stamp) are the same class: external tooling reads them, sessions **preserve them on edits** and never narrate or inject them. The `maintenance` agent stamps `type:` on docs that predate the key. `slug:` completes the set on generated docs: the identity key, minted once at creation and never re-derived from a display name — in the repo the filename is the slug, and the `maintenance` agent re-aligns the two when they diverge.
|
|
16
16
|
|
|
17
17
|
**1. `owns:`** (the path scope)
|
|
18
18
|
|
|
@@ -30,6 +30,8 @@ One file per template. Every template is either a **truth document** (states cur
|
|
|
30
30
|
| Backlog | [backlog.md](backlog.md) | Record (append-only) |
|
|
31
31
|
| Memory (main agent) | [memory-main.md](memory-main.md) | Record (append-only ledger) |
|
|
32
32
|
|
|
33
|
+
**The `type:` enum lives here.** A doc's `type:` frontmatter takes its value from this table — one genre per template (`feature`, `architecture-decision`, `non-goals`, …). External generators consume this list rather than defining their own; a type this table does not name defaults to `docs/architecture/` placement and is never added to the protected-files list.
|
|
34
|
+
|
|
33
35
|
**Baseline scaffolds** — files that must exist after every baseline; the `maintenance` agent (baseline mode) creates any that are missing: [docs-readme.md](docs-readme.md), [structure.md](structure.md), [changelog-index.md](changelog-index.md), [backlog.md](backlog.md), [memory-main.md](memory-main.md), and [root-readme.md](root-readme.md) (never overwriting an existing root README).
|
|
34
36
|
|
|
35
37
|
**Ownership.** A feature doc is the canonical reference for the code paths in its **`owns:` frontmatter** — the only ownership key. To find what a doc owns, read its `owns:` globs; to find the doc for a path, match the path against the injected ownership index (the union of every feature's `owns:` globs), narrower glob wins. See [`../references/frontmatter.md`](../references/frontmatter.md) for turning code into `owns:` globs.
|
|
@@ -31,6 +31,7 @@ Each topic has one canonical location. Read from here, not from plans or changel
|
|
|
31
31
|
| Historical plans | `docs/history/plans/` | YYYY-MM-DD-name.md |
|
|
32
32
|
| Change records | `docs/history/changelog/` | `YYYY-MM-DD-{three-words}.md` — one per unit of work, written at commit time |
|
|
33
33
|
| Migration runbooks | `docs/history/migrations/` | YYYY-MM-DD-name.md |
|
|
34
|
+
| Session gate logs | `docs/history/sessions/` | `YYYY-MM-DD-{sid}.md` — machinery-written; denials and their resolutions, appended, never edited down |
|
|
34
35
|
| Deep-research artifacts | `docs/history/research/{topic}/` | README.md + findings.md + sources.md |
|
|
35
36
|
| Brainstorm design records | `docs/research/{topic}-brainstorm/` (active; legacy `-brainstorming/`) → `docs/history/brainstorms/{topic}/` (harvested; user deletes or commits) | thesis.md + forks.md + ledger.md + state.md |
|
|
36
37
|
| Backlog | `docs/history/` | backlog.md |
|
|
@@ -149,6 +149,7 @@ docs/
|
|
|
149
149
|
│ ├── plans/ # Implementation plans (Status field required)
|
|
150
150
|
│ ├── migrations/ # One-shot migration/upgrade runbooks (YYYY-MM-DD-{slug}.md; outcome-stamped then frozen)
|
|
151
151
|
│ ├── journal.md # Append-only mid-execution knowledge capture (one line per fact; resolves by landing in its owning doc) — author-created, never scaffolded
|
|
152
|
+
│ ├── sessions/ # Per-session gate logs (YYYY-MM-DD-{sid}.md) — machinery-written records, never drained, never edited down; created by the first gate event, never scaffolded
|
|
152
153
|
│ ├── brainstorms/ # Harvested brainstorm sessions ({topic}/) — user decides kept (committed) or deleted; Readme.md is the index
|
|
153
154
|
│ ├── research/ # Deep-research records ({topic}/ — README.md synthesis + findings.md + sources.md); frozen, cited, owns no code
|
|
154
155
|
│ └── backlog.md ✱ # Tracked work items by priority (P0-P3)
|
|
@@ -12,7 +12,7 @@ When creating or updating a feature doc, derive its **`owns:` frontmatter** —
|
|
|
12
12
|
|
|
13
13
|
## How to derive the frontmatter
|
|
14
14
|
|
|
15
|
-
A feature doc's ownership frontmatter is `owns:` (required), `module:` (optional), `keywords:` (required), and `status:` (required). An optional `last-reviewed:` date (stamped whenever the doc is substantively reviewed or updated) gives the `maintenance` agent a staleness signal to rank its audits by — it is tooling metadata, never narrated in the body. `type:` (required — the genre, enum = the template names) and `rev:` (generator-written generation stamp) are the same class: external tooling reads them, sessions **preserve them on edits** and never narrate or inject them. The `maintenance` agent stamps `type:` on docs that predate the key.
|
|
15
|
+
A feature doc's ownership frontmatter is `owns:` (required), `module:` (optional), `keywords:` (required), and `status:` (required). An optional `last-reviewed:` date (stamped whenever the doc is substantively reviewed or updated) gives the `maintenance` agent a staleness signal to rank its audits by — it is tooling metadata, never narrated in the body. `type:` (required — the genre, enum = the template names) and `rev:` (generator-written generation stamp) are the same class: external tooling reads them, sessions **preserve them on edits** and never narrate or inject them. The `maintenance` agent stamps `type:` on docs that predate the key. `slug:` completes the set on generated docs: the identity key, minted once at creation and never re-derived from a display name — in the repo the filename is the slug, and the `maintenance` agent re-aligns the two when they diverge.
|
|
16
16
|
|
|
17
17
|
**1. `owns:`** (the path scope)
|
|
18
18
|
|
|
@@ -30,6 +30,8 @@ One file per template. Every template is either a **truth document** (states cur
|
|
|
30
30
|
| Backlog | [backlog.md](backlog.md) | Record (append-only) |
|
|
31
31
|
| Memory (main agent) | [memory-main.md](memory-main.md) | Record (append-only ledger) |
|
|
32
32
|
|
|
33
|
+
**The `type:` enum lives here.** A doc's `type:` frontmatter takes its value from this table — one genre per template (`feature`, `architecture-decision`, `non-goals`, …). External generators consume this list rather than defining their own; a type this table does not name defaults to `docs/architecture/` placement and is never added to the protected-files list.
|
|
34
|
+
|
|
33
35
|
**Baseline scaffolds** — files that must exist after every baseline; the `maintenance` agent (baseline mode) creates any that are missing: [docs-readme.md](docs-readme.md), [structure.md](structure.md), [changelog-index.md](changelog-index.md), [backlog.md](backlog.md), [memory-main.md](memory-main.md), and [root-readme.md](root-readme.md) (never overwriting an existing root README).
|
|
34
36
|
|
|
35
37
|
**Ownership.** A feature doc is the canonical reference for the code paths in its **`owns:` frontmatter** — the only ownership key. To find what a doc owns, read its `owns:` globs; to find the doc for a path, match the path against the injected ownership index (the union of every feature's `owns:` globs), narrower glob wins. See [`../references/frontmatter.md`](../references/frontmatter.md) for turning code into `owns:` globs.
|
|
@@ -31,6 +31,7 @@ Each topic has one canonical location. Read from here, not from plans or changel
|
|
|
31
31
|
| Historical plans | `docs/history/plans/` | YYYY-MM-DD-name.md |
|
|
32
32
|
| Change records | `docs/history/changelog/` | `YYYY-MM-DD-{three-words}.md` — one per unit of work, written at commit time |
|
|
33
33
|
| Migration runbooks | `docs/history/migrations/` | YYYY-MM-DD-name.md |
|
|
34
|
+
| Session gate logs | `docs/history/sessions/` | `YYYY-MM-DD-{sid}.md` — machinery-written; denials and their resolutions, appended, never edited down |
|
|
34
35
|
| Deep-research artifacts | `docs/history/research/{topic}/` | README.md + findings.md + sources.md |
|
|
35
36
|
| Brainstorm design records | `docs/research/{topic}-brainstorm/` (active; legacy `-brainstorming/`) → `docs/history/brainstorms/{topic}/` (harvested; user deletes or commits) | thesis.md + forks.md + ledger.md + state.md |
|
|
36
37
|
| Backlog | `docs/history/` | backlog.md |
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@nurix/etna",
|
|
3
|
-
"version": "0.19.
|
|
3
|
+
"version": "0.19.68",
|
|
4
4
|
"description": "Bootstrap a project with a Nurix harness — copies the harness's CLAUDE.md, skills, agents, rules, and hooks directly into the project from a bundled payload (no marketplace fetch, no network).",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"bin": {
|
|
@@ -42,5 +42,5 @@
|
|
|
42
42
|
"agent",
|
|
43
43
|
"plugin"
|
|
44
44
|
],
|
|
45
|
-
"etnaFingerprint": "
|
|
45
|
+
"etnaFingerprint": "d5b676c55c3a"
|
|
46
46
|
}
|