@christang/keel 5.3.3 → 5.3.4

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.
@@ -1,8 +1,8 @@
1
- <!-- keel:start version=5.3.3 -->
1
+ <!-- keel:start version=5.3.4 -->
2
2
  ## Keel Bootstrap
3
3
 
4
4
  - Start every session with `keel context`; OpenSpec artifacts and Git are the only durable authority — never native memory, goals, or transcripts.
5
- - Obey the selected task capsule: `keel gate task-start` before implementing, record its fingerprint in Evidence `Contract`, and pass `keel gate task-complete` before checking complete. Touch is the write boundary for product files; on Claude a passing `task-start` guards it by default (`--no-guard`/`keel guard clear` opt out).
5
+ - Obey the selected task capsule: `keel gate task-start` before implementing, record its fingerprint in Evidence `Contract`, and pass `keel gate task-complete` before checking complete. Touch bounds product writes; the change's own dir is exempt. On Claude a passing `task-start` guards it by default (`--no-guard` opts out).
6
6
  - One current agent owns writes; helpers return read-only report/evidence only. No commit, sync, or archive without explicit authorization.
7
7
  - Native plugin projections (SessionStart context) are disposable views, never authority; without the plugin or hook, run the commands manually.
8
8
  - Keel skills and hooks come from the `keel` native plugin (`codex plugin add` / `claude plugin install`); `keel --init` owns only the OpenSpec schema, overlays, and this bootstrap.
@@ -93,8 +93,15 @@ artifacts:
93
93
  Verify selects the least-cost strategy that still proves the resolved
94
94
  Acceptance: vertical-tdd, regression-first, characterization,
95
95
  snapshot-characterization, rendered-behavior, or evidence-first.
96
- Red-green strategies record per-label `.red` and `.green` Evidence for
97
- the same check before completion.
96
+ Red-green strategies record per-label `.red` and `.green` Evidence in
97
+ addition to the bare `M<n>` Evidence, which is always required; all three
98
+ must be concrete before completion. An `M<n>` may carry a comma-separated
99
+ tag set after its label, drawn from `fast`, `full`, and `regression`.
100
+ `fast`/`full` marks which checks the fast inner-loop pre-push runs.
101
+ `regression` marks a check asserting that something already green stays
102
+ green: it has no honest red, so it is exempt from `.red`/`.green` while
103
+ still needing its bare `M<n>` Evidence, and a red-green strategy must keep
104
+ at least one check untagged.
98
105
  The Task Authoring Gate requires every relevant critical expectation to
99
106
  be covered by a slice, deferred to a durable owner, or explicitly
100
107
  discarded with rationale before the slice can be selected for execution.
@@ -137,14 +144,19 @@ artifacts:
137
144
  Review with Status, Acceptance check, Scope check, and Findings. Status is
138
145
  one of pass, passed, complete, completed, ok, or done. Findings
139
146
  are `none` or carry a durable owner — a `Discard reason:`/`Discard
140
- rationale:` prefix, a `keel/archive/…` path, or an existing
141
- `openspec/changes/…` artifact; `keel/HANDOFF.md` is never the owner.
147
+ rationale:` prefix, an absolute `https://…` reference, or any
148
+ repo-relative path that exists, named after `Durable owner:` so it reads
149
+ as the owner rather than a file the finding mentions;
150
+ `keel/HANDOFF.md` is never the owner.
142
151
  tasks.md carries two change-level sections beside its tasks.
143
152
  `## Invalidates` is required by task-start, before any task of the
144
153
  change runs: one `- I<n>: "the wording that is now wrong" — where it lives.`
145
154
  line per statement this change makes stale, closed by `Updated by: <task
146
155
  ids>` naming tasks of this change, a `Durable owner:`, or a `Discard
147
156
  reason:`, or `- None.` when the change makes no existing statement wrong.
157
+ A `Durable owner:` is an absolute `https://…` reference or any
158
+ repo-relative path that exists; a path with no file behind it is refused,
159
+ and `keel/HANDOFF.md` is a pointer override rather than an owner.
148
160
  Quote the wording a reader would search for rather than only listing
149
161
  files, because the text that goes stale is the text the author was not
150
162
  already holding in mind; naming it while tasks are authored is what lets
@@ -20,10 +20,16 @@
20
20
  rendered-behavior, or evidence-first. Each M<n> check must prove the
21
21
  resolved Acceptance through the public interface, not build-only or
22
22
  shape-only evidence. Red-green strategies record per-label `.red` and
23
- `.green` Evidence entries for the same check before completion. An M<n>
24
- check may carry an optional (fast) or (full) layer tag after its label
25
- (e.g. `M1 (fast): …`) marking which checks the fast inner-loop pre-push
26
- runs; an untagged check is full and change-close still needs every
23
+ `.green` Evidence entries IN ADDITION TO the bare `M<n>` entry, which
24
+ is always required; all three must be concrete before completion.
25
+ An M<n> check may carry an optional comma-separated tag set after its
26
+ label, drawn from fast, full, and regression (e.g. `M1 (fast): …`,
27
+ `M2 (regression): …`, `M3 (fast, regression): …`). fast/full marks
28
+ which checks the fast inner-loop pre-push runs; an untagged check is
29
+ full. regression marks a check that asserts something already green
30
+ stays green: it has no honest red, so it is exempt from `.red`/`.green`
31
+ but still needs its bare `M<n>` Evidence, and a red-green strategy must
32
+ keep at least one check untagged. change-close still needs every
27
33
  M<n>'s Evidence. -->
28
34
  - Strategy: <strategy>
29
35
  - M1: <public behavior check>
@@ -32,7 +38,7 @@
32
38
  - M1: pending
33
39
  - Review:
34
40
  <!-- Status: one of pass, passed, complete, completed, ok, done -->
35
- <!-- Findings: none, or carry a durable owner — a "Discard reason:"/"Discard rationale:" prefix, a keel/archive/… path, or an existing openspec/changes/… artifact; not keel/HANDOFF.md -->
41
+ <!-- Findings: none, or carry a durable owner — a "Discard reason:"/"Discard rationale:" prefix, an absolute https://… reference, or any repo-relative path that exists (keel/archive/…, an openspec/changes/… artifact, or the repository's own ledger) named after "Durable owner:"; not keel/HANDOFF.md, which is a pointer override -->
36
42
  - Status: pending
37
43
  - Acceptance check: pending
38
44
  - Scope check: pending
@@ -84,8 +90,9 @@
84
90
  Each entry quotes the wording a reader would SEARCH for — not just the
85
91
  files you already remembered, because the text that goes stale is the text
86
92
  you were not thinking about — then says where it lives, then closes:
87
- `Updated by: 1.1` (tasks of this change), `Durable owner: <url or path>`,
88
- or `Discard reason: why it stands`. Use `- None.` when this change makes
93
+ `Updated by: 1.1` (tasks of this change), `Durable owner: <url or path>`
94
+ an absolute https:// reference, or any repo-relative path that exists;
95
+ keel/HANDOFF.md is refused — or `Discard reason: why it stands`. Use `- None.` when this change makes
89
96
  no existing statement wrong.
90
97
 
91
98
  - I1: "the exact wording that is now wrong" — where that wording lives. Updated by: 1.1
@@ -96,6 +103,6 @@
96
103
 
97
104
  <!-- change-close requires this section. One line per critical expectation:
98
105
  `- E1: the expectation Covered by: 1.1` (task ids that own it), or a
99
- `Durable owner: openspec/changes/<change>/tasks.md` / `Discard reason: why`
100
- closure. Use `- None.` only when the change has no critical expectations. -->
106
+ `Durable owner: <url or any repo-relative path that exists>` /
107
+ `Discard reason: why` closure. Use `- None.` only when the change has no critical expectations. -->
101
108
  - None.
package/package.json CHANGED
@@ -2,7 +2,7 @@
2
2
  "name": "@christang/keel",
3
3
  "displayName": "Keel",
4
4
  "description": "Keel OpenSpec execution discipline CLI for Claude Code, Codex, and OpenCode.",
5
- "version": "5.3.3",
5
+ "version": "5.3.4",
6
6
  "license": "MIT",
7
7
  "repository": {
8
8
  "type": "git",
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "keel",
3
- "version": "5.3.3",
3
+ "version": "5.3.4",
4
4
  "description": "Keel OpenSpec execution discipline: stateless continuity, task capsules, deterministic gates, and expectation alignment for Codex and Claude Code.",
5
5
  "author": {
6
6
  "name": "TanglmChris",
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "keel",
3
- "version": "5.3.3",
3
+ "version": "5.3.4",
4
4
  "description": "Keel OpenSpec execution discipline: stateless continuity, task capsules, deterministic gates, and expectation alignment for Codex and Claude Code.",
5
5
  "author": {
6
6
  "name": "TanglmChris",
@@ -74,8 +74,45 @@ function replaceInFile(relPath, replacements) {
74
74
  process.stdout.write(` updated ${relPath}\n`);
75
75
  }
76
76
 
77
+ // Every Keel marker carrying `version=` is a shipped claim about which version
78
+ // this is, and they must all move together. Sweeping for the markers that exist
79
+ // is what keeps a target from falling behind: the `.codex/` overlays sat four
80
+ // versions back because only the surfaces something happened to touch got
81
+ // refreshed, and nothing failed while they drifted.
82
+ const MARKER_SKIP_PREFIXES = [
83
+ "node_modules",
84
+ ".git",
85
+ path.join("openspec", "changes", "archive"),
86
+ path.join("keel", "archive"),
87
+ ];
88
+
89
+ function sweepVersionMarkers(dir, oldVersion, newVersion, touched) {
90
+ for (const entry of fs.readdirSync(dir, { withFileTypes: true })) {
91
+ const full = path.join(dir, entry.name);
92
+ const relative = path.relative(ROOT, full);
93
+ if (MARKER_SKIP_PREFIXES.some((prefix) => relative.startsWith(prefix))) continue;
94
+ if (entry.isDirectory()) {
95
+ sweepVersionMarkers(full, oldVersion, newVersion, touched);
96
+ continue;
97
+ }
98
+ if (!/\.(md|json)$/.test(entry.name)) continue;
99
+ const content = fs.readFileSync(full, "utf8");
100
+ const updated = content.replace(
101
+ new RegExp(`(keel:[a-z-]+(?::end)?\\s+version=)${oldVersion.replace(/\./g, "\\.")}\\b`, "g"),
102
+ `$1${newVersion}`
103
+ );
104
+ if (updated !== content) {
105
+ fs.writeFileSync(full, updated);
106
+ touched.push(relative.split(path.sep).join("/"));
107
+ }
108
+ }
109
+ }
110
+
77
111
  function prependChangelogEntry(newVersion) {
78
- let content = fs.readFileSync(CHANGELOG_PATH, "utf8");
112
+ // Read line endings as the file has them: a CRLF checkout made the header
113
+ // comparison below fail after every version marker had already been written,
114
+ // leaving the repository half-bumped.
115
+ let content = fs.readFileSync(CHANGELOG_PATH, "utf8").replace(/\r\n/g, "\n");
79
116
  if (content.includes(`## ${newVersion} `) || content.includes(`## ${newVersion}\n`)) {
80
117
  process.stdout.write(` keel/CHANGELOG.md already has a ${newVersion} entry\n`);
81
118
  return;
@@ -118,13 +155,14 @@ function main() {
118
155
  [`PACKAGE_VERSION = "${oldVersion}"`, `PACKAGE_VERSION = "${newVersion}"`],
119
156
  [`PROTOCOL_VERSION = "${oldVersion}"`, `PROTOCOL_VERSION = "${newVersion}"`],
120
157
  ]);
121
- replaceInFile("AGENTS.md", [
122
- [`v${oldVersion}`, `v${newVersion}`],
123
- [`version=${oldVersion}`, `version=${newVersion}`],
124
- ]);
125
- replaceInFile("assets/bootstrap/AGENTS.md", [
126
- [`version=${oldVersion}`, `version=${newVersion}`],
127
- ]);
158
+ replaceInFile("AGENTS.md", [[`v${oldVersion}`, `v${newVersion}`]]);
159
+
160
+ const touched = [];
161
+ sweepVersionMarkers(ROOT, oldVersion, newVersion, touched);
162
+ for (const relative of touched) {
163
+ process.stdout.write(` updated marker ${relative}\n`);
164
+ }
165
+
128
166
  prependChangelogEntry(newVersion);
129
167
 
130
168
  process.stdout.write(