@codyswann/lisa 2.328.2 → 2.328.3

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.
Files changed (68) hide show
  1. package/dist/core/upstream-evidence-manifest.d.ts.map +1 -1
  2. package/dist/core/upstream-evidence-manifest.js +5 -2
  3. package/dist/core/upstream-evidence-manifest.js.map +1 -1
  4. package/dist/utils/usage-accounting.d.ts +42 -0
  5. package/dist/utils/usage-accounting.d.ts.map +1 -1
  6. package/dist/utils/usage-accounting.js +116 -3
  7. package/dist/utils/usage-accounting.js.map +1 -1
  8. package/package.json +1 -1
  9. package/plugins/lisa/.claude-plugin/plugin.json +1 -1
  10. package/plugins/lisa/.codex-plugin/plugin.json +1 -1
  11. package/plugins/lisa/.codex-plugin/skills/lisa-usage-accounting/SKILL.md +16 -2
  12. package/plugins/lisa/rules/reference/usage-accounting.md +37 -4
  13. package/plugins/lisa/skills/lisa-usage-accounting/SKILL.md +16 -2
  14. package/plugins/lisa-agy/plugin.json +1 -1
  15. package/plugins/lisa-agy/skills/lisa-usage-accounting/SKILL.md +16 -2
  16. package/plugins/lisa-cdk/.claude-plugin/plugin.json +1 -1
  17. package/plugins/lisa-cdk/.codex-plugin/plugin.json +1 -1
  18. package/plugins/lisa-cdk-agy/plugin.json +1 -1
  19. package/plugins/lisa-cdk-copilot/.claude-plugin/plugin.json +1 -1
  20. package/plugins/lisa-cdk-cursor/.claude-plugin/plugin.json +1 -1
  21. package/plugins/lisa-copilot/.claude-plugin/plugin.json +1 -1
  22. package/plugins/lisa-copilot/rules/reference/usage-accounting.md +37 -4
  23. package/plugins/lisa-copilot/skills/lisa-usage-accounting/SKILL.md +16 -2
  24. package/plugins/lisa-cursor/.claude-plugin/plugin.json +1 -1
  25. package/plugins/lisa-cursor/rules/usage-accounting-reference.mdc +37 -4
  26. package/plugins/lisa-cursor/skills/lisa-usage-accounting/SKILL.md +16 -2
  27. package/plugins/lisa-expo/.claude-plugin/plugin.json +1 -1
  28. package/plugins/lisa-expo/.codex-plugin/plugin.json +1 -1
  29. package/plugins/lisa-expo-agy/plugin.json +1 -1
  30. package/plugins/lisa-expo-copilot/.claude-plugin/plugin.json +1 -1
  31. package/plugins/lisa-expo-cursor/.claude-plugin/plugin.json +1 -1
  32. package/plugins/lisa-harper-fabric/.claude-plugin/plugin.json +1 -1
  33. package/plugins/lisa-harper-fabric/.codex-plugin/plugin.json +1 -1
  34. package/plugins/lisa-harper-fabric-agy/plugin.json +1 -1
  35. package/plugins/lisa-harper-fabric-copilot/.claude-plugin/plugin.json +1 -1
  36. package/plugins/lisa-harper-fabric-cursor/.claude-plugin/plugin.json +1 -1
  37. package/plugins/lisa-nestjs/.claude-plugin/plugin.json +1 -1
  38. package/plugins/lisa-nestjs/.codex-plugin/plugin.json +1 -1
  39. package/plugins/lisa-nestjs-agy/plugin.json +1 -1
  40. package/plugins/lisa-nestjs-copilot/.claude-plugin/plugin.json +1 -1
  41. package/plugins/lisa-nestjs-cursor/.claude-plugin/plugin.json +1 -1
  42. package/plugins/lisa-openclaw/.claude-plugin/plugin.json +1 -1
  43. package/plugins/lisa-openclaw/.codex-plugin/plugin.json +1 -1
  44. package/plugins/lisa-openclaw-agy/plugin.json +1 -1
  45. package/plugins/lisa-openclaw-copilot/.claude-plugin/plugin.json +1 -1
  46. package/plugins/lisa-openclaw-cursor/.claude-plugin/plugin.json +1 -1
  47. package/plugins/lisa-phaser/.claude-plugin/plugin.json +1 -1
  48. package/plugins/lisa-phaser/.codex-plugin/plugin.json +1 -1
  49. package/plugins/lisa-phaser-agy/plugin.json +1 -1
  50. package/plugins/lisa-phaser-copilot/.claude-plugin/plugin.json +1 -1
  51. package/plugins/lisa-phaser-cursor/.claude-plugin/plugin.json +1 -1
  52. package/plugins/lisa-rails/.claude-plugin/plugin.json +1 -1
  53. package/plugins/lisa-rails/.codex-plugin/plugin.json +1 -1
  54. package/plugins/lisa-rails-agy/plugin.json +1 -1
  55. package/plugins/lisa-rails-copilot/.claude-plugin/plugin.json +1 -1
  56. package/plugins/lisa-rails-cursor/.claude-plugin/plugin.json +1 -1
  57. package/plugins/lisa-typescript/.claude-plugin/plugin.json +1 -1
  58. package/plugins/lisa-typescript/.codex-plugin/plugin.json +1 -1
  59. package/plugins/lisa-typescript-agy/plugin.json +1 -1
  60. package/plugins/lisa-typescript-copilot/.claude-plugin/plugin.json +1 -1
  61. package/plugins/lisa-typescript-cursor/.claude-plugin/plugin.json +1 -1
  62. package/plugins/lisa-wiki/.claude-plugin/plugin.json +1 -1
  63. package/plugins/lisa-wiki/.codex-plugin/plugin.json +1 -1
  64. package/plugins/lisa-wiki-agy/plugin.json +1 -1
  65. package/plugins/lisa-wiki-copilot/.claude-plugin/plugin.json +1 -1
  66. package/plugins/lisa-wiki-cursor/.claude-plugin/plugin.json +1 -1
  67. package/plugins/src/base/rules/reference/usage-accounting.md +37 -4
  68. package/plugins/src/base/skills/lisa-usage-accounting/SKILL.md +16 -2
@@ -154,12 +154,24 @@ The implementation path should use the shared utility layer (`parseLisaUsageSect
154
154
  `mergeLisaUsageEntries`, `createLisaUsageRollup`, `upsertLisaUsageSection`) rather than duplicating
155
155
  token parsing or markdown rendering in each caller.
156
156
 
157
- ### Step 4 — Persist and report
157
+ ### Step 4 — Persist, verify by read-back, and report
158
158
 
159
159
  1. If the rendered ledger body is byte-identical to the current managed surface, return `outcome:
160
160
  no-op`.
161
161
  2. Otherwise write the body or managed comment through the host adapter.
162
- 3. Return the exact writable surface used, direct entry ids, rolled-up child entry ids, totals, and
162
+ 3. **Read the written surface back from the host and parse it.** Run
163
+ `verifyLisaUsageSectionIntegrity(<stored body>, { entryIds: <ids just written> })`. A write is
164
+ successful only when that returns `ok: true`. The host's mutation result is not evidence — a
165
+ Linear `issueUpdate` returned `success: true` while silently discarding every entry token
166
+ (2026-08-04), which is the defect this step exists to catch.
167
+ 4. If verification fails on the body, retry the identical payload as a managed comment and verify
168
+ that surface the same way. Return `outcome: comment-fallback` with a warning naming the failed
169
+ surface and the issue codes.
170
+ 5. If verification fails on every surface, return `outcome: blocked` with the issue codes in
171
+ `error.message`. **Never leave a rollup token behind whose `direct_entry_ids` names entries that
172
+ cannot be parsed from the same surface** — restore the prior managed content rather than
173
+ reporting success over an unreadable ledger.
174
+ 6. Return the exact writable surface used, direct entry ids, rolled-up child entry ids, totals, and
163
175
  any fallback warning.
164
176
 
165
177
  If the host write fails, preserve the exact error text in `error.message`. Do not collapse write
@@ -179,4 +191,6 @@ failures into a generic "usage update failed."
179
191
  - Never skip rollup dedupe. Child totals are keyed by stable `entry_id`, not by child ref count.
180
192
  - Never silently drop to comments. Return `outcome: comment-fallback` so the caller can surface the
181
193
  writable surface that actually holds the ledger.
194
+ - Never report `updated` on the strength of a mutation's return value. Verification is read-back
195
+ and parse, on every surface, every write.
182
196
  - Never overwrite unrelated artifact body content. Rewrite only the managed usage section/comment.
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "lisa",
3
- "version": "2.328.2",
3
+ "version": "2.328.3",
4
4
  "description": "Universal governance — agents, skills, commands, hooks, and rules for all projects",
5
5
  "author": {
6
6
  "name": "Cody Swann"
@@ -80,14 +80,24 @@ cost rollups under the normal pricing and currency rules.
80
80
 
81
81
  ## Machine-readable tokens
82
82
 
83
- Every visible direct entry row contains the backward-compatible 17-field primary token:
83
+ Every visible direct entry row has a corresponding backward-compatible 17-field primary token:
84
84
 
85
85
  ```text
86
86
  <!-- lisa:usage-entry entry_id=<id> flow=<flow> run_id=<run-id> provider=<provider> model=<model> source=<source> input_tokens=<n|null> cached_input_tokens=<n|null> output_tokens=<n|null> reasoning_tokens=<n|null> total_tokens=<n|null> cost=<decimal|null> currency=<code|null> pricing_status=<status> pricing_source=<ref|null> artifact_ref=<ref> parent_artifact_ref=<ref-or-empty> -->
87
87
  ```
88
88
 
89
- The row immediately follows it with a correlated measured-subset extension. Writers serialize an
90
- omitted value as `null` instead of `undefined`:
89
+ **Entry tokens are never rendered inside a table row.** They occupy their own lines below the
90
+ visible table, and they correlate to their rows by `entry_id`, not by position. Hosts that
91
+ normalize markdown re-serialize a table from its parsed cell model and discard anything that is
92
+ not a cell: measured against Linear on 2026-08-04, an HTML comment trailing a table row is
93
+ destroyed on write while the same comment on its own line round-trips byte-identically. The
94
+ row-trailing layout therefore produced a ledger that reported a successful write, rendered
95
+ correctly for humans, and enumerated **zero** entries — with a surviving rollup token still naming
96
+ them. Parsing is position-agnostic and always has been, so sections written in the historical
97
+ row-trailing layout still enumerate, and migrate to the own-line layout on their next rewrite.
98
+
99
+ The primary token is immediately followed on the same line by a correlated measured-subset
100
+ extension. Writers serialize an omitted value as `null` instead of `undefined`:
91
101
 
92
102
  ```text
93
103
  <!-- lisa:usage-entry-measured-subset entry_id=<id> measured_subset_tokens=<n|null> -->
@@ -146,7 +156,9 @@ _Managed by Lisa. Regenerated on each usage update; do not edit by hand._
146
156
 
147
157
  | Flow | Model | Source | Tokens | Cost |
148
158
  |---|---|---|---:|---:|
149
- | ...human-readable rows ending with `lisa-usage-entry` tokens... |
159
+ | ...human-readable rows, cells only, no tokens... |
160
+
161
+ <!-- lisa:usage-entry ... --> <!-- lisa:usage-entry-measured-subset ... -->
150
162
 
151
163
  ### Rollup
152
164
 
@@ -159,8 +171,29 @@ _Managed by Lisa. Regenerated on each usage update; do not edit by hand._
159
171
  <!-- lisa:usage-rollup ... -->
160
172
  ```
161
173
 
174
+ Every machine-readable token sits on its own line, outside every table. One entry contributes one
175
+ token line; multiple entries contribute consecutive token lines in the same order as their visible
176
+ rows.
177
+
162
178
  Writers may add host-specific surrounding prose, but they must preserve the heading, the managed-note line, the direct-entry tokens, and the single rollup token.
163
179
 
180
+ ## Write verification
181
+
182
+ A write surface can accept a section, report success, and silently destroy part of it. **Verify
183
+ every managed write by reading the stored bytes back and parsing them — never by the mutation's
184
+ return value.** A write is successful only when the stored surface satisfies the rollup/entry
185
+ agreement invariant below. A caller that cannot verify a surface must fall back to one it can, or
186
+ fail loudly; it must never report success over an unreadable ledger.
187
+
188
+ - Every `entry_id` in the rollup's `direct_entry_ids` resolves to a parseable direct entry in the
189
+ same section.
190
+ - Every parseable direct entry in the section appears in the rollup's `direct_entry_ids`.
191
+ - Every entry the caller just wrote is parseable from the stored surface.
192
+
193
+ `verifyLisaUsageSectionIntegrity` in the shared utility layer implements exactly these checks and
194
+ returns structured issue codes (`missing-section`, `missing-entry-token`, `missing-rollup-token`,
195
+ `unrecorded-entry`). Callers run it against the read-back body, not against the payload they sent.
196
+
164
197
  ## Rollup and dedupe behavior
165
198
 
166
199
  Rollups aggregate descendant usage from native tracker hierarchy, documented generated-work references, and explicit `parent_artifact_ref` links. Within one artifact rollup:
@@ -154,12 +154,24 @@ The implementation path should use the shared utility layer (`parseLisaUsageSect
154
154
  `mergeLisaUsageEntries`, `createLisaUsageRollup`, `upsertLisaUsageSection`) rather than duplicating
155
155
  token parsing or markdown rendering in each caller.
156
156
 
157
- ### Step 4 — Persist and report
157
+ ### Step 4 — Persist, verify by read-back, and report
158
158
 
159
159
  1. If the rendered ledger body is byte-identical to the current managed surface, return `outcome:
160
160
  no-op`.
161
161
  2. Otherwise write the body or managed comment through the host adapter.
162
- 3. Return the exact writable surface used, direct entry ids, rolled-up child entry ids, totals, and
162
+ 3. **Read the written surface back from the host and parse it.** Run
163
+ `verifyLisaUsageSectionIntegrity(<stored body>, { entryIds: <ids just written> })`. A write is
164
+ successful only when that returns `ok: true`. The host's mutation result is not evidence — a
165
+ Linear `issueUpdate` returned `success: true` while silently discarding every entry token
166
+ (2026-08-04), which is the defect this step exists to catch.
167
+ 4. If verification fails on the body, retry the identical payload as a managed comment and verify
168
+ that surface the same way. Return `outcome: comment-fallback` with a warning naming the failed
169
+ surface and the issue codes.
170
+ 5. If verification fails on every surface, return `outcome: blocked` with the issue codes in
171
+ `error.message`. **Never leave a rollup token behind whose `direct_entry_ids` names entries that
172
+ cannot be parsed from the same surface** — restore the prior managed content rather than
173
+ reporting success over an unreadable ledger.
174
+ 6. Return the exact writable surface used, direct entry ids, rolled-up child entry ids, totals, and
163
175
  any fallback warning.
164
176
 
165
177
  If the host write fails, preserve the exact error text in `error.message`. Do not collapse write
@@ -179,4 +191,6 @@ failures into a generic "usage update failed."
179
191
  - Never skip rollup dedupe. Child totals are keyed by stable `entry_id`, not by child ref count.
180
192
  - Never silently drop to comments. Return `outcome: comment-fallback` so the caller can surface the
181
193
  writable surface that actually holds the ledger.
194
+ - Never report `updated` on the strength of a mutation's return value. Verification is read-back
195
+ and parse, on every surface, every write.
182
196
  - Never overwrite unrelated artifact body content. Rewrite only the managed usage section/comment.
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "lisa-expo",
3
- "version": "2.328.2",
3
+ "version": "2.328.3",
4
4
  "description": "Expo/React Native-specific skills, agents, rules, and MCP servers",
5
5
  "author": {
6
6
  "name": "Cody Swann"
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "lisa-expo",
3
- "version": "2.328.2",
3
+ "version": "2.328.3",
4
4
  "description": "Expo and React Native-specific skills, agents, rules, and MCP servers.",
5
5
  "author": {
6
6
  "name": "Cody Swann"
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "lisa-expo",
3
- "version": "2.328.2",
3
+ "version": "2.328.3",
4
4
  "description": "Expo/React Native-specific skills, agents, rules, and MCP servers",
5
5
  "author": {
6
6
  "name": "Cody Swann"
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "lisa-expo",
3
- "version": "2.328.2",
3
+ "version": "2.328.3",
4
4
  "description": "Expo/React Native-specific skills, agents, rules, and MCP servers",
5
5
  "author": {
6
6
  "name": "Cody Swann"
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "lisa-expo",
3
- "version": "2.328.2",
3
+ "version": "2.328.3",
4
4
  "description": "Expo/React Native-specific skills, agents, rules, and MCP servers",
5
5
  "author": {
6
6
  "name": "Cody Swann"
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "lisa-harper-fabric",
3
- "version": "2.328.2",
3
+ "version": "2.328.3",
4
4
  "description": "Harper/Fabric-specific rules for TypeScript component apps",
5
5
  "author": {
6
6
  "name": "Cody Swann"
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "lisa-harper-fabric",
3
- "version": "2.328.2",
3
+ "version": "2.328.3",
4
4
  "description": "Harper/Fabric-specific Lisa rules for TypeScript component apps.",
5
5
  "author": {
6
6
  "name": "Cody Swann"
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "lisa-harper-fabric",
3
- "version": "2.328.2",
3
+ "version": "2.328.3",
4
4
  "description": "Harper/Fabric-specific rules for TypeScript component apps",
5
5
  "author": {
6
6
  "name": "Cody Swann"
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "lisa-harper-fabric",
3
- "version": "2.328.2",
3
+ "version": "2.328.3",
4
4
  "description": "Harper/Fabric-specific rules for TypeScript component apps",
5
5
  "author": {
6
6
  "name": "Cody Swann"
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "lisa-harper-fabric",
3
- "version": "2.328.2",
3
+ "version": "2.328.3",
4
4
  "description": "Harper/Fabric-specific rules for TypeScript component apps",
5
5
  "author": {
6
6
  "name": "Cody Swann"
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "lisa-nestjs",
3
- "version": "2.328.2",
3
+ "version": "2.328.3",
4
4
  "description": "NestJS-specific skills (GraphQL, TypeORM) and hooks (migration write-protection)",
5
5
  "author": {
6
6
  "name": "Cody Swann"
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "lisa-nestjs",
3
- "version": "2.328.2",
3
+ "version": "2.328.3",
4
4
  "description": "NestJS-specific skills and migration write-protection hooks.",
5
5
  "author": {
6
6
  "name": "Cody Swann"
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "lisa-nestjs",
3
- "version": "2.328.2",
3
+ "version": "2.328.3",
4
4
  "description": "NestJS-specific skills (GraphQL, TypeORM) and hooks (migration write-protection)",
5
5
  "author": {
6
6
  "name": "Cody Swann"
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "lisa-nestjs",
3
- "version": "2.328.2",
3
+ "version": "2.328.3",
4
4
  "description": "NestJS-specific skills (GraphQL, TypeORM) and hooks (migration write-protection)",
5
5
  "author": {
6
6
  "name": "Cody Swann"
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "lisa-nestjs",
3
- "version": "2.328.2",
3
+ "version": "2.328.3",
4
4
  "description": "NestJS-specific skills (GraphQL, TypeORM) and hooks (migration write-protection)",
5
5
  "author": {
6
6
  "name": "Cody Swann"
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "lisa-openclaw",
3
- "version": "2.328.2",
3
+ "version": "2.328.3",
4
4
  "description": "Connect staff roles to Telegram or Slack via OpenClaw — facilitator/specialist hub-and-spoke routing and repo-coding topics, for Claude Code and Codex",
5
5
  "author": {
6
6
  "name": "Cody Swann"
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "lisa-openclaw",
3
- "version": "2.328.2",
3
+ "version": "2.328.3",
4
4
  "description": "Connect staff roles to Telegram or Slack via OpenClaw — facilitator/specialist hub-and-spoke routing and repo-coding topics, across Claude and Codex.",
5
5
  "author": {
6
6
  "name": "Cody Swann"
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "lisa-openclaw",
3
- "version": "2.328.2",
3
+ "version": "2.328.3",
4
4
  "description": "Connect staff roles to Telegram or Slack via OpenClaw — facilitator/specialist hub-and-spoke routing and repo-coding topics, for Claude Code and Codex",
5
5
  "author": {
6
6
  "name": "Cody Swann"
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "lisa-openclaw",
3
- "version": "2.328.2",
3
+ "version": "2.328.3",
4
4
  "description": "Connect staff roles to Telegram or Slack via OpenClaw — facilitator/specialist hub-and-spoke routing and repo-coding topics, for Claude Code and Codex",
5
5
  "author": {
6
6
  "name": "Cody Swann"
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "lisa-openclaw",
3
- "version": "2.328.2",
3
+ "version": "2.328.3",
4
4
  "description": "Connect staff roles to Telegram or Slack via OpenClaw — facilitator/specialist hub-and-spoke routing and repo-coding topics, for Claude Code and Codex",
5
5
  "author": {
6
6
  "name": "Cody Swann"
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "lisa-phaser",
3
- "version": "2.328.2",
3
+ "version": "2.328.3",
4
4
  "description": "Phaser 4 game-development rules for TypeScript projects",
5
5
  "author": {
6
6
  "name": "Cody Swann"
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "lisa-phaser",
3
- "version": "2.328.2",
3
+ "version": "2.328.3",
4
4
  "description": "Phaser 4 game-development rules for TypeScript projects",
5
5
  "author": {
6
6
  "name": "Cody Swann"
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "lisa-phaser",
3
- "version": "2.328.2",
3
+ "version": "2.328.3",
4
4
  "description": "Phaser 4 game-development rules for TypeScript projects",
5
5
  "author": {
6
6
  "name": "Cody Swann"
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "lisa-phaser",
3
- "version": "2.328.2",
3
+ "version": "2.328.3",
4
4
  "description": "Phaser 4 game-development rules for TypeScript projects",
5
5
  "author": {
6
6
  "name": "Cody Swann"
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "lisa-phaser",
3
- "version": "2.328.2",
3
+ "version": "2.328.3",
4
4
  "description": "Phaser 4 game-development rules for TypeScript projects",
5
5
  "author": {
6
6
  "name": "Cody Swann"
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "lisa-rails",
3
- "version": "2.328.2",
3
+ "version": "2.328.3",
4
4
  "description": "Ruby on Rails-specific hooks — RuboCop linting/formatting and ast-grep scanning on edit",
5
5
  "author": {
6
6
  "name": "Cody Swann"
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "lisa-rails",
3
- "version": "2.328.2",
3
+ "version": "2.328.3",
4
4
  "description": "Ruby on Rails-specific skills and hooks for RuboCop and ast-grep scanning on edit.",
5
5
  "author": {
6
6
  "name": "Cody Swann"
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "lisa-rails",
3
- "version": "2.328.2",
3
+ "version": "2.328.3",
4
4
  "description": "Ruby on Rails-specific hooks — RuboCop linting/formatting and ast-grep scanning on edit",
5
5
  "author": {
6
6
  "name": "Cody Swann"
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "lisa-rails",
3
- "version": "2.328.2",
3
+ "version": "2.328.3",
4
4
  "description": "Ruby on Rails-specific hooks — RuboCop linting/formatting and ast-grep scanning on edit",
5
5
  "author": {
6
6
  "name": "Cody Swann"
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "lisa-rails",
3
- "version": "2.328.2",
3
+ "version": "2.328.3",
4
4
  "description": "Ruby on Rails-specific hooks — RuboCop linting/formatting and ast-grep scanning on edit",
5
5
  "author": {
6
6
  "name": "Cody Swann"
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "lisa-typescript",
3
- "version": "2.328.2",
3
+ "version": "2.328.3",
4
4
  "description": "TypeScript-specific hooks — Prettier formatting, ESLint linting, ast-grep scanning, and error-suppression blocking on edit",
5
5
  "author": {
6
6
  "name": "Cody Swann"
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "lisa-typescript",
3
- "version": "2.328.2",
3
+ "version": "2.328.3",
4
4
  "description": "TypeScript-specific hooks for formatting, linting, and ast-grep scanning on edit.",
5
5
  "author": {
6
6
  "name": "Cody Swann"
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "lisa-typescript",
3
- "version": "2.328.2",
3
+ "version": "2.328.3",
4
4
  "description": "TypeScript-specific hooks — Prettier formatting, ESLint linting, ast-grep scanning, and error-suppression blocking on edit",
5
5
  "author": {
6
6
  "name": "Cody Swann"
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "lisa-typescript",
3
- "version": "2.328.2",
3
+ "version": "2.328.3",
4
4
  "description": "TypeScript-specific hooks — Prettier formatting, ESLint linting, ast-grep scanning, and error-suppression blocking on edit",
5
5
  "author": {
6
6
  "name": "Cody Swann"
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "lisa-typescript",
3
- "version": "2.328.2",
3
+ "version": "2.328.3",
4
4
  "description": "TypeScript-specific hooks — Prettier formatting, ESLint linting, ast-grep scanning, and error-suppression blocking on edit",
5
5
  "author": {
6
6
  "name": "Cody Swann"
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "lisa-wiki",
3
- "version": "2.328.2",
3
+ "version": "2.328.3",
4
4
  "description": "LLM Wiki — a distributable, git-native markdown knowledge base for Claude Code and Codex",
5
5
  "author": {
6
6
  "name": "Cody Swann"
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "lisa-wiki",
3
- "version": "2.328.2",
3
+ "version": "2.328.3",
4
4
  "description": "Distributable LLM Wiki kernel — ingest, query, lint, and maintain a git-native markdown knowledge base across Claude and Codex.",
5
5
  "author": {
6
6
  "name": "Cody Swann"
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "lisa-wiki",
3
- "version": "2.328.2",
3
+ "version": "2.328.3",
4
4
  "description": "LLM Wiki — a distributable, git-native markdown knowledge base for Claude Code and Codex",
5
5
  "author": {
6
6
  "name": "Cody Swann"
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "lisa-wiki",
3
- "version": "2.328.2",
3
+ "version": "2.328.3",
4
4
  "description": "LLM Wiki — a distributable, git-native markdown knowledge base for Claude Code and Codex",
5
5
  "author": {
6
6
  "name": "Cody Swann"
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "lisa-wiki",
3
- "version": "2.328.2",
3
+ "version": "2.328.3",
4
4
  "description": "LLM Wiki — a distributable, git-native markdown knowledge base for Claude Code and Codex",
5
5
  "author": {
6
6
  "name": "Cody Swann"
@@ -75,14 +75,24 @@ cost rollups under the normal pricing and currency rules.
75
75
 
76
76
  ## Machine-readable tokens
77
77
 
78
- Every visible direct entry row contains the backward-compatible 17-field primary token:
78
+ Every visible direct entry row has a corresponding backward-compatible 17-field primary token:
79
79
 
80
80
  ```text
81
81
  <!-- lisa:usage-entry entry_id=<id> flow=<flow> run_id=<run-id> provider=<provider> model=<model> source=<source> input_tokens=<n|null> cached_input_tokens=<n|null> output_tokens=<n|null> reasoning_tokens=<n|null> total_tokens=<n|null> cost=<decimal|null> currency=<code|null> pricing_status=<status> pricing_source=<ref|null> artifact_ref=<ref> parent_artifact_ref=<ref-or-empty> -->
82
82
  ```
83
83
 
84
- The row immediately follows it with a correlated measured-subset extension. Writers serialize an
85
- omitted value as `null` instead of `undefined`:
84
+ **Entry tokens are never rendered inside a table row.** They occupy their own lines below the
85
+ visible table, and they correlate to their rows by `entry_id`, not by position. Hosts that
86
+ normalize markdown re-serialize a table from its parsed cell model and discard anything that is
87
+ not a cell: measured against Linear on 2026-08-04, an HTML comment trailing a table row is
88
+ destroyed on write while the same comment on its own line round-trips byte-identically. The
89
+ row-trailing layout therefore produced a ledger that reported a successful write, rendered
90
+ correctly for humans, and enumerated **zero** entries — with a surviving rollup token still naming
91
+ them. Parsing is position-agnostic and always has been, so sections written in the historical
92
+ row-trailing layout still enumerate, and migrate to the own-line layout on their next rewrite.
93
+
94
+ The primary token is immediately followed on the same line by a correlated measured-subset
95
+ extension. Writers serialize an omitted value as `null` instead of `undefined`:
86
96
 
87
97
  ```text
88
98
  <!-- lisa:usage-entry-measured-subset entry_id=<id> measured_subset_tokens=<n|null> -->
@@ -141,7 +151,9 @@ _Managed by Lisa. Regenerated on each usage update; do not edit by hand._
141
151
 
142
152
  | Flow | Model | Source | Tokens | Cost |
143
153
  |---|---|---|---:|---:|
144
- | ...human-readable rows ending with `lisa-usage-entry` tokens... |
154
+ | ...human-readable rows, cells only, no tokens... |
155
+
156
+ <!-- lisa:usage-entry ... --> <!-- lisa:usage-entry-measured-subset ... -->
145
157
 
146
158
  ### Rollup
147
159
 
@@ -154,8 +166,29 @@ _Managed by Lisa. Regenerated on each usage update; do not edit by hand._
154
166
  <!-- lisa:usage-rollup ... -->
155
167
  ```
156
168
 
169
+ Every machine-readable token sits on its own line, outside every table. One entry contributes one
170
+ token line; multiple entries contribute consecutive token lines in the same order as their visible
171
+ rows.
172
+
157
173
  Writers may add host-specific surrounding prose, but they must preserve the heading, the managed-note line, the direct-entry tokens, and the single rollup token.
158
174
 
175
+ ## Write verification
176
+
177
+ A write surface can accept a section, report success, and silently destroy part of it. **Verify
178
+ every managed write by reading the stored bytes back and parsing them — never by the mutation's
179
+ return value.** A write is successful only when the stored surface satisfies the rollup/entry
180
+ agreement invariant below. A caller that cannot verify a surface must fall back to one it can, or
181
+ fail loudly; it must never report success over an unreadable ledger.
182
+
183
+ - Every `entry_id` in the rollup's `direct_entry_ids` resolves to a parseable direct entry in the
184
+ same section.
185
+ - Every parseable direct entry in the section appears in the rollup's `direct_entry_ids`.
186
+ - Every entry the caller just wrote is parseable from the stored surface.
187
+
188
+ `verifyLisaUsageSectionIntegrity` in the shared utility layer implements exactly these checks and
189
+ returns structured issue codes (`missing-section`, `missing-entry-token`, `missing-rollup-token`,
190
+ `unrecorded-entry`). Callers run it against the read-back body, not against the payload they sent.
191
+
159
192
  ## Rollup and dedupe behavior
160
193
 
161
194
  Rollups aggregate descendant usage from native tracker hierarchy, documented generated-work references, and explicit `parent_artifact_ref` links. Within one artifact rollup:
@@ -154,12 +154,24 @@ The implementation path should use the shared utility layer (`parseLisaUsageSect
154
154
  `mergeLisaUsageEntries`, `createLisaUsageRollup`, `upsertLisaUsageSection`) rather than duplicating
155
155
  token parsing or markdown rendering in each caller.
156
156
 
157
- ### Step 4 — Persist and report
157
+ ### Step 4 — Persist, verify by read-back, and report
158
158
 
159
159
  1. If the rendered ledger body is byte-identical to the current managed surface, return `outcome:
160
160
  no-op`.
161
161
  2. Otherwise write the body or managed comment through the host adapter.
162
- 3. Return the exact writable surface used, direct entry ids, rolled-up child entry ids, totals, and
162
+ 3. **Read the written surface back from the host and parse it.** Run
163
+ `verifyLisaUsageSectionIntegrity(<stored body>, { entryIds: <ids just written> })`. A write is
164
+ successful only when that returns `ok: true`. The host's mutation result is not evidence — a
165
+ Linear `issueUpdate` returned `success: true` while silently discarding every entry token
166
+ (2026-08-04), which is the defect this step exists to catch.
167
+ 4. If verification fails on the body, retry the identical payload as a managed comment and verify
168
+ that surface the same way. Return `outcome: comment-fallback` with a warning naming the failed
169
+ surface and the issue codes.
170
+ 5. If verification fails on every surface, return `outcome: blocked` with the issue codes in
171
+ `error.message`. **Never leave a rollup token behind whose `direct_entry_ids` names entries that
172
+ cannot be parsed from the same surface** — restore the prior managed content rather than
173
+ reporting success over an unreadable ledger.
174
+ 6. Return the exact writable surface used, direct entry ids, rolled-up child entry ids, totals, and
163
175
  any fallback warning.
164
176
 
165
177
  If the host write fails, preserve the exact error text in `error.message`. Do not collapse write
@@ -179,4 +191,6 @@ failures into a generic "usage update failed."
179
191
  - Never skip rollup dedupe. Child totals are keyed by stable `entry_id`, not by child ref count.
180
192
  - Never silently drop to comments. Return `outcome: comment-fallback` so the caller can surface the
181
193
  writable surface that actually holds the ledger.
194
+ - Never report `updated` on the strength of a mutation's return value. Verification is read-back
195
+ and parse, on every surface, every write.
182
196
  - Never overwrite unrelated artifact body content. Rewrite only the managed usage section/comment.