@nurix/etna 0.19.60 → 0.19.62
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/apollo/CLAUDE.md +2 -1
- package/data/harnesses/apollo/agents/bookkeeper.md +1 -0
- package/data/harnesses/apollo/agents/maintenance.md +2 -0
- package/data/harnesses/apollo/harness.json +1 -1
- package/data/harnesses/apollo/hooks/lib/ownership.mjs +10 -1
- package/data/harnesses/code/CLAUDE.md +2 -1
- package/data/harnesses/code/agents/bookkeeper.md +1 -0
- package/data/harnesses/code/agents/maintenance.md +2 -0
- package/data/harnesses/code/harness.json +1 -1
- package/data/harnesses/code/hooks/lib/ownership.mjs +10 -1
- package/data/harnesses/delivery/agents/maintenance.md +2 -0
- package/data/harnesses/delivery/harness.json +1 -1
- package/data/harnesses/etna/agents/maintenance.md +2 -0
- package/data/harnesses/etna/harness.json +1 -1
- package/package.json +2 -2
package/data/harness-index.json
CHANGED
|
@@ -139,7 +139,8 @@ Defaults — ❌ prohibitions hold unless the user explicitly asks otherwise;
|
|
|
139
139
|
- ❌ **Branches & Worktrees [override]** – Never self-create git branches or worktrees; commit straight to the checked-out branch. This replaces any built-in "branch first on the default branch" default. Exception: when the user asks for a pull request, create the branch the PR requires before committing its changes.
|
|
140
140
|
- ❌ **Protected Files** – Once per session, if `docs/operations/protected-files.md` exists, read it and never modify any path it lists; never modify `AGENTS.md` (harness-regenerated) or `protected-files.md` itself.
|
|
141
141
|
- ✅ **Browser Automation** – If the runtime provides browser automation, use it freely; no need to ask first. If it doesn't — or the executing agent can't hold the browser connection (see Runtime Notes) — return a browser-verification checklist (URLs, actions, expected outcomes) for the orchestrating session or the user to run.
|
|
142
|
-
- ✅ **Bookkeeping** — hooks silently append doc-debt rows to `docs/operations/bookkeeping.md`; the commit hook blocks while unresolved rows remain — dispatch the `bookkeeper` agent to drain the queue.
|
|
142
|
+
- ✅ **Bookkeeping** — hooks silently append doc-debt rows to `docs/operations/bookkeeping.md`; the commit hook blocks while unresolved rows remain — dispatch the `bookkeeper` agent to drain the queue. The queue is a queue, never an archive: a drained row is **deleted**, so a fully drained file holds no rows at all.
|
|
143
|
+
- ✅ **Cleanup removes the cause, not the record of it.** When the user asks for something to be deleted or cleaned up, the ask is for the underlying condition to be gone. Deleting the record while the condition survives is worse than doing nothing — it destroys the only evidence the debt exists. The order is fixed: **read what the record is masking** (a `waived:` row, an `UNBUILT:` marker, a `status:` flag, a lint suppression — each asserts something is fine; check whether that is still true), **fix the condition**, **then delete the record**. Reversing it backfires concretely: a deleted waiver's finding is re-appended by the detector as an `auto:` row, which *fails* the commit wall the `waived:` row passed.
|
|
143
144
|
- ✅ **Delegation** — when to fan out, tiers, and trust are § Delegation.
|
|
144
145
|
- ⚠️ **Plans** – Plans are created directly in `docs/history/plans/` (see Workflows). Once `Status: Complete` or `Status: Abandoned`, the file is frozen — never edited. Abandoning a plan whose code was committed first converts its undischarged Test Obligations into backlog items (the `testing` rule). If scope changes after completion, write a new dated plan that links back to the old one.
|
|
145
146
|
- ⚠️ **Tool Issues** – If any CLI tool, shell alias, or MCP tool behaves unexpectedly (syntax errors, silent failures, wrong defaults), report the exact tool name, command, and error to the user so they can fix or remove the underlying library.
|
|
@@ -24,4 +24,5 @@ Ground every edit in this ladder, in order. Never invent content; a fact you can
|
|
|
24
24
|
- **Every touched doc goes through the `documentation` skill's rules** — present tense, two-natures, no history narration in truth documents.
|
|
25
25
|
- **Resolution = deletion.** A finished row is removed from the queue, not annotated. Only `waived:` conversions (a reason plus `expires=YYYY-MM-DD`) and `needs-session:` rows survive your pass.
|
|
26
26
|
- **Never waive on your own judgment** — waiving is the main session's (or the user's) call; your outcomes are fixed, landed, or `needs-session:`.
|
|
27
|
+
- **A waiver's reason expires before its date.** Most waivers defer to something — "plan X reconciles this at completion", "the concurrent session resolves its own doc impact". When you pass a `waived:` row, check whether that reason still holds: a waiver naming a `Status: Complete` plan is discharged debt wearing a live badge, and its `expires=` date will not fire for weeks. Report those rows as `needs-session:` rather than waiving them onward — the finding underneath is live, and the unexpired date is precisely why nothing else will catch it.
|
|
27
28
|
- **Report by row**: one line each — the row, the outcome (fixed / landed in {doc} / needs-session), and the files touched. The main session relays this; keep it terse.
|
|
@@ -113,6 +113,8 @@ For unowned code paths:
|
|
|
113
113
|
|
|
114
114
|
**Declined realignment.** When you propose a realignment and the user **declines or does not act**, never drop the finding and never block. Append it to `docs/history/backlog.md` as `- **[P0–P3]** <finding> — discovered by maintenance`, priority = the finding's own severity **on the same P0–P3 scale as code items** — never a segregated "compliance" section, never auto-relegated to the lowest tier. Record once: dedupe against existing entries; if already present, leave it.
|
|
115
115
|
|
|
116
|
+
> **Never regenerate `.claude/state/drift-report.md` by running the awareness hook when the bookkeeping queue is what you are measuring.** `driftBanner()` calls `resolveRows()`, which *mutates* the queue as a side effect of reporting on it — so the act of refreshing the report changes the thing the report describes. Read the existing report, or recompute the facts directly from `deadGlobs()` / `scanFeatureDocs()`.
|
|
117
|
+
|
|
116
118
|
### Step 6: Report & update tracking
|
|
117
119
|
|
|
118
120
|
1. Update `docs/structure.md` Health Log with today's date and summary — **append to the end**, never date-sorted into the middle. Rows are positional: one may say "the row above is…", and an inserted row silently breaks that reference. A Health Log entry is a **generated row, not a narrative essay**: one line — date · counts (stale docs fixed, dead globs, unowned paths, backlog items created) · links to anything that needs a human.
|
|
@@ -78,9 +78,18 @@ export function field(block, key) {
|
|
|
78
78
|
const raw = m[1].trim();
|
|
79
79
|
if (raw === "") {
|
|
80
80
|
// A bare key may continue as an indented inline array on the next line, or a `- item` block.
|
|
81
|
+
// The array may span several lines, so join through the closing bracket before parsing —
|
|
82
|
+
// reading only the first line yields a bare "[", which parses to [] and makes the whole doc
|
|
83
|
+
// look like it owns nothing. `scanFeatureDocs` skips such docs, so the failure is invisible:
|
|
84
|
+
// the doc drops out of the ownership index and out of every dead-glob count.
|
|
81
85
|
const next = (lines[i + 1] || "").trim();
|
|
82
86
|
if (next.startsWith("[")) {
|
|
83
|
-
|
|
87
|
+
let joined = "";
|
|
88
|
+
for (let j = i + 1; j < lines.length; j++) {
|
|
89
|
+
joined += (joined ? " " : "") + lines[j].trim();
|
|
90
|
+
if (lines[j].includes("]")) break;
|
|
91
|
+
}
|
|
92
|
+
return parseInlineArray(joined);
|
|
84
93
|
}
|
|
85
94
|
const items = [];
|
|
86
95
|
for (let j = i + 1; j < lines.length; j++) {
|
|
@@ -137,7 +137,8 @@ Defaults — ❌ prohibitions hold unless the user explicitly asks otherwise;
|
|
|
137
137
|
- ❌ **Branches & Worktrees [override]** – Never self-create git branches or worktrees; commit straight to the checked-out branch. This replaces any built-in "branch first on the default branch" default. Exception: when the user asks for a pull request, create the branch the PR requires before committing its changes.
|
|
138
138
|
- ❌ **Protected Files** – Once per session, if `docs/operations/protected-files.md` exists, read it and never modify any path it lists; never modify `AGENTS.md` (harness-regenerated) or `protected-files.md` itself.
|
|
139
139
|
- ✅ **Browser Automation** – If the runtime provides browser automation, use it freely; no need to ask first. If it doesn't — or the executing agent can't hold the browser connection (see Runtime Notes) — return a browser-verification checklist (URLs, actions, expected outcomes) for the orchestrating session or the user to run.
|
|
140
|
-
- ✅ **Bookkeeping** — hooks silently append doc-debt rows to `docs/operations/bookkeeping.md`; the commit hook blocks while unresolved rows remain — dispatch the `bookkeeper` agent to drain the queue.
|
|
140
|
+
- ✅ **Bookkeeping** — hooks silently append doc-debt rows to `docs/operations/bookkeeping.md`; the commit hook blocks while unresolved rows remain — dispatch the `bookkeeper` agent to drain the queue. The queue is a queue, never an archive: a drained row is **deleted**, so a fully drained file holds no rows at all.
|
|
141
|
+
- ✅ **Cleanup removes the cause, not the record of it.** When the user asks for something to be deleted or cleaned up, the ask is for the underlying condition to be gone. Deleting the record while the condition survives is worse than doing nothing — it destroys the only evidence the debt exists. The order is fixed: **read what the record is masking** (a `waived:` row, an `UNBUILT:` marker, a `status:` flag, a lint suppression — each asserts something is fine; check whether that is still true), **fix the condition**, **then delete the record**. Reversing it backfires concretely: a deleted waiver's finding is re-appended by the detector as an `auto:` row, which *fails* the commit wall the `waived:` row passed.
|
|
141
142
|
- ✅ **Delegation** — when to fan out, tiers, and trust are § Delegation.
|
|
142
143
|
- ⚠️ **Plans** – Plans are created directly in `docs/history/plans/` (see Workflows). Once `Status: Complete` or `Status: Abandoned`, the file is frozen — never edited. Abandoning a plan whose code was committed first converts its undischarged Test Obligations into backlog items (the `testing` rule). If scope changes after completion, write a new dated plan that links back to the old one.
|
|
143
144
|
- ⚠️ **Tool Issues** – If any CLI tool, shell alias, or MCP tool behaves unexpectedly (syntax errors, silent failures, wrong defaults), report the exact tool name, command, and error to the user so they can fix or remove the underlying library.
|
|
@@ -24,4 +24,5 @@ Ground every edit in this ladder, in order. Never invent content; a fact you can
|
|
|
24
24
|
- **Every touched doc goes through the `documentation` skill's rules** — present tense, two-natures, no history narration in truth documents.
|
|
25
25
|
- **Resolution = deletion.** A finished row is removed from the queue, not annotated. Only `waived:` conversions (a reason plus `expires=YYYY-MM-DD`) and `needs-session:` rows survive your pass.
|
|
26
26
|
- **Never waive on your own judgment** — waiving is the main session's (or the user's) call; your outcomes are fixed, landed, or `needs-session:`.
|
|
27
|
+
- **A waiver's reason expires before its date.** Most waivers defer to something — "plan X reconciles this at completion", "the concurrent session resolves its own doc impact". When you pass a `waived:` row, check whether that reason still holds: a waiver naming a `Status: Complete` plan is discharged debt wearing a live badge, and its `expires=` date will not fire for weeks. Report those rows as `needs-session:` rather than waiving them onward — the finding underneath is live, and the unexpired date is precisely why nothing else will catch it.
|
|
27
28
|
- **Report by row**: one line each — the row, the outcome (fixed / landed in {doc} / needs-session), and the files touched. The main session relays this; keep it terse.
|
|
@@ -113,6 +113,8 @@ For unowned code paths:
|
|
|
113
113
|
|
|
114
114
|
**Declined realignment.** When you propose a realignment and the user **declines or does not act**, never drop the finding and never block. Append it to `docs/history/backlog.md` as `- **[P0–P3]** <finding> — discovered by maintenance`, priority = the finding's own severity **on the same P0–P3 scale as code items** — never a segregated "compliance" section, never auto-relegated to the lowest tier. Record once: dedupe against existing entries; if already present, leave it.
|
|
115
115
|
|
|
116
|
+
> **Never regenerate `.claude/state/drift-report.md` by running the awareness hook when the bookkeeping queue is what you are measuring.** `driftBanner()` calls `resolveRows()`, which *mutates* the queue as a side effect of reporting on it — so the act of refreshing the report changes the thing the report describes. Read the existing report, or recompute the facts directly from `deadGlobs()` / `scanFeatureDocs()`.
|
|
117
|
+
|
|
116
118
|
### Step 6: Report & update tracking
|
|
117
119
|
|
|
118
120
|
1. Update `docs/structure.md` Health Log with today's date and summary — **append to the end**, never date-sorted into the middle. Rows are positional: one may say "the row above is…", and an inserted row silently breaks that reference. A Health Log entry is a **generated row, not a narrative essay**: one line — date · counts (stale docs fixed, dead globs, unowned paths, backlog items created) · links to anything that needs a human.
|
|
@@ -78,9 +78,18 @@ export function field(block, key) {
|
|
|
78
78
|
const raw = m[1].trim();
|
|
79
79
|
if (raw === "") {
|
|
80
80
|
// A bare key may continue as an indented inline array on the next line, or a `- item` block.
|
|
81
|
+
// The array may span several lines, so join through the closing bracket before parsing —
|
|
82
|
+
// reading only the first line yields a bare "[", which parses to [] and makes the whole doc
|
|
83
|
+
// look like it owns nothing. `scanFeatureDocs` skips such docs, so the failure is invisible:
|
|
84
|
+
// the doc drops out of the ownership index and out of every dead-glob count.
|
|
81
85
|
const next = (lines[i + 1] || "").trim();
|
|
82
86
|
if (next.startsWith("[")) {
|
|
83
|
-
|
|
87
|
+
let joined = "";
|
|
88
|
+
for (let j = i + 1; j < lines.length; j++) {
|
|
89
|
+
joined += (joined ? " " : "") + lines[j].trim();
|
|
90
|
+
if (lines[j].includes("]")) break;
|
|
91
|
+
}
|
|
92
|
+
return parseInlineArray(joined);
|
|
84
93
|
}
|
|
85
94
|
const items = [];
|
|
86
95
|
for (let j = i + 1; j < lines.length; j++) {
|
|
@@ -113,6 +113,8 @@ For unowned code paths:
|
|
|
113
113
|
|
|
114
114
|
**Declined realignment.** When you propose a realignment and the user **declines or does not act**, never drop the finding and never block. Append it to `docs/history/backlog.md` as `- **[P0–P3]** <finding> — discovered by maintenance`, priority = the finding's own severity **on the same P0–P3 scale as code items** — never a segregated "compliance" section, never auto-relegated to the lowest tier. Record once: dedupe against existing entries; if already present, leave it.
|
|
115
115
|
|
|
116
|
+
> **Never regenerate `.claude/state/drift-report.md` by running the awareness hook when the bookkeeping queue is what you are measuring.** `driftBanner()` calls `resolveRows()`, which *mutates* the queue as a side effect of reporting on it — so the act of refreshing the report changes the thing the report describes. Read the existing report, or recompute the facts directly from `deadGlobs()` / `scanFeatureDocs()`.
|
|
117
|
+
|
|
116
118
|
### Step 6: Report & update tracking
|
|
117
119
|
|
|
118
120
|
1. Update `docs/structure.md` Health Log with today's date and summary — **append to the end**, never date-sorted into the middle. Rows are positional: one may say "the row above is…", and an inserted row silently breaks that reference. A Health Log entry is a **generated row, not a narrative essay**: one line — date · counts (stale docs fixed, dead globs, unowned paths, backlog items created) · links to anything that needs a human.
|
|
@@ -113,6 +113,8 @@ For unowned code paths:
|
|
|
113
113
|
|
|
114
114
|
**Declined realignment.** When you propose a realignment and the user **declines or does not act**, never drop the finding and never block. Append it to `docs/history/backlog.md` as `- **[P0–P3]** <finding> — discovered by maintenance`, priority = the finding's own severity **on the same P0–P3 scale as code items** — never a segregated "compliance" section, never auto-relegated to the lowest tier. Record once: dedupe against existing entries; if already present, leave it.
|
|
115
115
|
|
|
116
|
+
> **Never regenerate `.claude/state/drift-report.md` by running the awareness hook when the bookkeeping queue is what you are measuring.** `driftBanner()` calls `resolveRows()`, which *mutates* the queue as a side effect of reporting on it — so the act of refreshing the report changes the thing the report describes. Read the existing report, or recompute the facts directly from `deadGlobs()` / `scanFeatureDocs()`.
|
|
117
|
+
|
|
116
118
|
### Step 6: Report & update tracking
|
|
117
119
|
|
|
118
120
|
1. Update `docs/structure.md` Health Log with today's date and summary — **append to the end**, never date-sorted into the middle. Rows are positional: one may say "the row above is…", and an inserted row silently breaks that reference. A Health Log entry is a **generated row, not a narrative essay**: one line — date · counts (stale docs fixed, dead globs, unowned paths, backlog items created) · links to anything that needs a human.
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@nurix/etna",
|
|
3
|
-
"version": "0.19.
|
|
3
|
+
"version": "0.19.62",
|
|
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": "51ceda35d5cc"
|
|
46
46
|
}
|