Skip to content

upgrade repairs the installed-file record, legacy request.body migration hint, shared env/secrets (#1131, #1132, #1133) - #1134

Merged
jimhoyd merged 7 commits into
mainfrom
claude/issues-1131-1133
Oct 1, 2026
Merged

jimhoyd merged 7 commits into
mainfrom
claude/issues-1131-1133

Conversation

@jimhoyd

@jimhoyd jimhoyd commented Oct 1, 2026

Copy link
Copy Markdown
Collaborator

Problem and change

#1131: urlcode upgrade leaves addon-files.lock.json unwritten, so extensions list --strict fails

  • Root cause: the old release's upgrade code runs the upgrade. 0.6.5's had no record-writing step; it first shipped in 0.6.6 (Artifact inspection follow-ups: $id bases, registry integrity, $ref in data, YAML anchors, catalog documents #857). Main records on a moving upgrade, but if the site was already up to date it returned early, so a second upgrade could never repair the missing record.
  • Repair on an up-to-date upgrade: it now records every installed catalog add-on that still matches its pin but has no entry. An add-on npm moved off its pin is left for list --strict to report. UpgradeResult.recorded lists what was recorded, and the CLI prints it.
  • Atomic record writes: writeFilesLock writes a temporary file and renames it into place. A failure names the file and fails the upgrade; a moving upgrade rolls back everything.
  • Output of extensions add: it reports "Recorded the installed files of X…" when it only writes the record. "nothing to do" appears only for a true no-op. --json carries recorded.

#1132: targeted migration hint for the route-wide request.body shape (#870)

  • One targeted error: the old shape (required, maxBytes, contentTypes, format or schema directly under request.body, in a route or a shared block) is refused with one error, code legacy-request-body, before the generic schema errors.
  • What it says: it names the file:line:column, the route and the keys. It says which method to move them under, gives a before/after, and links the new docs/HTTP.md#moving-from-the-route-wide-body-shape through docsUrl(). Extra places are listed with their line and column, capped at 8.
  • Same text everywhere: the CLI, MCP validate and explain_error all give it.

#1133: shared: blocks may carry env and secrets (owner reversed #576)

  • Schema: route and shared blocks share $defs/envBindings and $defs/secretBindings, so shapes and limits are identical.
  • Merge rule: resolved when the project loads, name by name, and the route's own entry wins. use stays a single name, so two blocks never conflict.
  • Visibility preserved:
    • permissions lists the inherited grants under each route that uses the block, and only there.
    • Adding a route to a block changes its grants and projectSha256, so an old policy is refused. A policy granting /a still refuses /b.
    • Inline and inherited bindings give the same route version and grants.
    • explain shows binding names and never values.
    • Sandboxed routes behave the same.
  • Docs: SPECIFICATION, yaml/organization, FUNCTION-SECURITY, SECURITY.md (the reversed decision and how per-route visibility is kept) and the RIM-CFG-002 card. There is a new examples/shared-bindings example.

Also included: the #1121 agent-facts check now counts only packages/ directories that hold source. Before, an older checkout's leftover dist/ or node_modules/ from a removed package failed check:docs.

Verification

  • npm run verify exits 0 on this exact tree.

    • Core: 1414 pass.
    • Workspaces: auth 33, mcp 47, store 239.
    • Add-ons and proofs: addons 9, proof 12, authjs 13, native 7, ecosystem 13.
    • 0 failures anywhere.
  • npm run test:package exits 0: "43 packaged example commands ran from consumer copies; Packed installation and starter/cookbook checks passed".

  • New tests:

    • test/upgrade.test.ts: 4 new; three fail on main.
    • test/addon-files.test.ts: record-only add output.
    • test/legacy-request-body.test.ts: 5 tests, including the exact-message snapshot.
    • test/shared-blocks.test.ts: 9 new.
  • Core package budget, from the merged measurement:

    Old budget New budget Measured
    Packed 1090 KiB 1098 KiB 1120281 bytes
    Unpacked 4274 KiB 4300 KiB 4396305 bytes
    Entries 561 570 565

Limitations

Closes #1131
Closes #1132
Closes #1133

🤖 Generated with Claude Code

jimhoyd and others added 7 commits October 1, 2026 14:32
…change (#1131)

The reported failure came from a 0.6.5 `urlcode upgrade` moving a site to
0.6.6: that release's upgrade wrote no addon-files.lock.json at all, so the
0.6.6 `extensions list --strict` found every add-on unrecorded. The current
upgrade already records moved add-ons inside its rollback, but an up-to-date
site returned early, so re-running upgrade could never repair that state.

- upgrade on an up-to-date site records each installed catalog add-on that
  still matches the installed core's pin and has no entry; a package npm moved
  off its pin is left for list --strict to report. UpgradeResult gains
  `recorded`, printed by the CLI.
- writeFilesLock writes a temporary file and renames it into place, and a
  failed write is a ConfigError naming the file, so a record is never torn.
- extensions|artifacts add reports `recorded` and says "Recorded the installed
  files of <name>" instead of "nothing to do" when only the record changed.
- Tests: upgrade then list --strict passes with tarball-installed add-ons; an
  up-to-date unrecorded site is repaired; a mispinned one is not recorded; a
  record that cannot be written fails upgrade and rolls everything back; add
  reports the record write and "nothing to do" only for a true no-op.
- docs/EXTENSIONS.md, CLI help and llms-full.txt describe it.

Refs #1131

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
…hape (#1132)

Policy keys (required, maxBytes, contentTypes, format, schema) written
directly under request.body in a route or a shared block, the shape #870
keyed by HTTP method, now fail with one legacy-request-body error before the
schema runs, instead of a generic unknown-key error for the first one only.

- The error is located at the first such place (file:line:column, pointer,
  key) and gives one instruction per route and shared block, each later one
  with its own line and column: the keys to move, the method keys to move
  them under, and a one-line before/after (key names only, never values).
- A route with methods moves every key under each method that takes a body,
  and maxBytes alone under its GET/HEAD/DELETE. A route without methods
  answers GET and HEAD: maxBytes moves under both, and any other key gets
  the suggestion to declare methods: [POST]. A shared block uses the methods
  every route that uses it answers.
- explainError (MCP explain_error) returns the error's own hint as its
  guidance, so the CLI, MCP validate and explain_error give the same text.
- docs/HTTP.md gains "Moving from the route-wide body shape" with the
  before/after, which the hint links through docsUrl(). No alias and no
  rewriting.

Refs #1132

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Owner decision 2026-10-01 reverses the declined #576. A top-level shared
block may declare env and secrets with the route-level shapes. A route that
names it with use inherits them, merged name by name; the route's own entry
wins. use is a single name, so two blocks can never conflict.

Bindings are resolved into each route at load time, before hashing, so
projectSha256, urlcode permissions (requested grants per route), the
operator policy's per-route grants and revision pin, explain and audit all
see each route's effective bindings. A block grants nothing and nothing
becomes project-wide; adding a route to a block changes its requested
grants and the revision, so the old pin is refused.

Adds examples/shared-bindings, schema $defs envBindings/secretBindings
shared by routes and shared blocks, tests, and docs (specification,
bindings guide, FUNCTION-SECURITY, SECURITY, RIM-CFG-002).

Refs #1133, #576

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Measured on the merged branch (Node 26): 1120281 packed, 4396305 unpacked,
565 entries. Budgets: 1098 KiB packed, 4300 KiB unpacked, 570 entries.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
…ource

The #1121 workspace-package fact listed every directory under packages/, so an
older checkout keeping a removed package's untracked dist/ or node_modules/
(ui, admin, forms, ...) failed check:docs and agent-facts.test.ts. A directory
now counts only when it holds a package.json or core's src/.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
@jimhoyd
jimhoyd enabled auto-merge (squash) October 1, 2026 20:25
@jimhoyd
jimhoyd merged commit 1f75521 into main Oct 1, 2026
24 checks passed
@jimhoyd
jimhoyd deleted the claude/issues-1131-1133 branch October 1, 2026 20:35
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

1 participant