test(rest): pin the approvals FORBIDDEN → 403 row here too — and correct the record that it was unpinned - #14838

Queued
os-trump wants to merge 3 commits into
mainfrom
claude/issue-14573-approvals-forbidden-live-emission-pin
Queued

test(rest): pin the approvals FORBIDDEN → 403 row here too — and correct the record that it was unpinned#14838
os-trump wants to merge 3 commits into
mainfrom
claude/issue-14573-approvals-forbidden-live-emission-pin

Conversation

@os-trump

Copy link
Copy Markdown
Collaborator

Part of #14573.

⚠️The card's premise is falsified, and that is this PR's main finding.#14573 says the
FORBIDDEN → 403 row of handleApprovalError "has no live-emission pin — only the
service-side prefix is pinned". It has one. It has two, in fact, and they discriminate.
Read the ablation below before deciding what to do with this branch.

File face

packages/rest/src/rest-approvals-wire-codes.test.tsone file, test-only, no production
code touched.
Specifically NOT packages/rest/src/error-response.ts, which PR #14713 is in
flight on and card #14725 is queued on. handleApprovalError lives in rest-server.ts; this
branch reads it and never edits it.

Anchors, verified against origin/main521eaf9e41

Card's claimVerdict
handleApprovalError at rest-server.ts:11557✅ exact
[/^FORBIDDEN/, 403, 'FORBIDDEN'], is row 5 of the table✅ exact, :11564
rest-approvals-wire-codes.test.ts greps 0 for FORBIDDEN|403✅ (positive control: THROTTLED → 6)
the row has no live-emission pinFALSE — see below
a dropped row fails closed at 500✅ confirmed by the ablation's message

The falsification, measured

rest-data-door-code-prefix.test.ts§7 (describe('[#13095] the approvals door strips the code it answers, never a blanket pattern')) boots a RestServer with an approvals service
whose decide rejects, drives the realPOST /api/v1/approvals/requests/:id/approve
route, and asserts status === 403, body.code === 'FORBIDDEN'and the strip. That is
exactly the shape the triage comment specified, already in the tree, on a different route.

The card enumerated that file and characterised it as pinning "the code-prefix strip … not the
403 row". That characterisation is wrong, and the triage re-ran the grep only against
rest-approvals-wire-codes.test.ts, so it inherited the error.

Ablation — delete the row from rest-server.ts, no rebuild (subject reached by a
./rest-server.js relative in-package import, which vitest transforms from source; the red
below is the proof that source is what ran):

anchor occurrences BEFORE=1 bytes=742980
anchor occurrences AFTER=0 bytes=742930 delta=50
HEAD blob ce00225a072be73a12eedd7143c5f50fa2a901c6
MUT blob a6d7d5d00968850eff63f1430a1dccc53885454a ← differs ⇒ mutation on disk
residual /^FORBIDDEN/ rows in table: 0
LegResult
baseline (tree at HEAD)Tests 27 passed (27)
mutatedTests 3 failed | 24 passed (27)
restoredTests 27 passed (27)

The three reds, all reading AssertionError: expected 500 to be 403:

  • rest-approvals-wire-codes.test.ts → the case this PR adds
  • rest-data-door-code-prefix.test.ts §7 → the well-formed idiom is unchanged…pre-existing
  • rest-data-door-code-prefix.test.ts §7 → a LONGER token sharing the matched spelling…pre-existing

24 neighbours stayed green, including every other case in both files — the red is specific
to the row, not a file-wide collapse.

Restore proven by blob-hash equality, not by an exit code:
POST blob ce00225a072be73a12eedd7143c5f50fa2a901c6 = HEAD blob, and git diff HEAD -- PATH
empty. Mutation and restore both ran under trap restore EXIT INT TERM on absolute paths.

What is actually true, and what this PR does

The row is pinned. What was not pinned is narrower and still real: the file that owns the
approvals wire-code contract carried no FORBIDDEN case, so an audit of approvals wire codes
read a gap that a strip-contract file was silently covering. §7's two cases sit under a
describe whose declared subject is #13095's anchored strip — retire or refactor that contract
and the 403 row loses its live pin with nobody noticing.

This PR adds oneit() closing that locality gap, through the real recall route with the
real catalog refusal sentence, asserting 403 + code + the strip — and, in the same commit,
names §7 from the new test so the duplicate is labelled in both directions. An unlabelled
duplicate is what got this card mis-filed; a labelled one cannot.

This is a disposition call for the maintainer, not a done card. Three defensible answers:
land this as the labelled pin in the owning file; drop the it() and keep only a pointer to §7;
or close#14573 as already-covered. My recommendation is the first — one row silently pinned by
two files that do not know about each other is the shape that produced this card.

⛔ Not done here

  • No production change. The mapping table is untouched — no row added, reordered or edited.
  • No case per refusing operation (the triage forbade it, and the ablation confirms one route
    is enough: one row, one closure, all four call sites).
  • packages/spec read, never editedBUILTIN_OPERATION_MESSAGES is imported from
    @objectstack/spec/system, the same construction approval-revise.test.ts already uses.
  • Neighbouring rows not audited or fixed.handleApprovalError's table has 9 rows; 3 now
    have live-emission pins here (THROTTLED, READ_BACK_FAILED, FORBIDDEN) and 6 do not
    VALIDATION_FAILED, DUPLICATE_REQUEST, INVALID_STATE, REQUEST_NOT_FOUND,
    RESUME_TARGET_LOST, RESUME_FAILED. Counted, filed as its own card, not fixed here.

Changeset fork: skip-changeset, measured not assumed

packages/rest declares files: ["dist","README.md","CHANGELOG.md"] and the root
tsup.config.ts builds entry: ['src/index.ts'] — a src/**/*.test.ts file cannot reach
dist, so this diff publishes nothing from any released package. Label, not a changeset.

Verification

pnpm --filter '@objectstack/rest^...' build (VERDICT command-exit 0), then the targeted
vitest above. Gate families derived with node scripts/pm/dispatch-gates.mjs --repo objectstack-ai/objectstack (27 owed by path + kind). Per-run exit codes captured before any
pipe. Full list of what ran, what was narrowed and what is left to CI is in the report on the
issue.

🤖 Generated with Claude Code

https://claude.ai/code/session_016yfqQh2dBgPAymYd7xipza


Generated by Claude Code

`handleApprovalError`'s `[/^FORBIDDEN/, 403, 'FORBIDDEN']` row is the one
every authorisation refusal rides, and it had no live-emission pin: the
service suites assert the `FORBIDDEN:` message prefix at the throw site,
which is a different fact from what the route answers on the wire.
Adds one `it()` to `rest-approvals-wire-codes.test.ts` driving the real
recall route with a service that throws the real refusal, asserting
status 403, `code === 'FORBIDDEN'`, and that the [#13095] anchored strip
removed the prefix. Losing the row fails closed (500
`APPROVAL_RECALL_FAILED` with the raw message), so the third assertion
catches the strip half of the regression as well as the status half.
Test-only; no production behaviour changed.
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_016yfqQh2dBgPAymYd7xipza
… is false
Measured, not read: deleting `[/^FORBIDDEN/, 403, 'FORBIDDEN']` from
`handleApprovalError` reds THREE cases, not one — this new pin and both
cases of `rest-data-door-code-prefix.test.ts` §7, which already drive the
real approve route and already assert 403, `code: 'FORBIDDEN'` and the
anchored strip.
#14573 was filed and triaged on the reading that the row had no
live-emission pin anywhere. That is wrong. What is true is narrower: the
file that OWNS the approvals wire-code contract did not pin it, so an
audit of wire codes here saw a gap a strip-contract file was silently
covering. Naming §7 from here is half the fix — the unlabelled duplicate
is what got the card mis-filed.
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_016yfqQh2dBgPAymYd7xipza
@os-trumpos-trump added skip-changeset PR has no user-facing published change; bypasses the changeset gate and removed tests labels Sep 3, 2026 — with Claude
@github-actions

github-actionsBot commented Sep 3, 2026

Copy link
Copy Markdown
Contributor

📓 Docs Drift Check

Nothing in this diff resolved to a documentable surface (no symbol, route or SDK anchor derived from 0 changed package(s)), so this run has no opinion about the docs.

What this run could not see
  • a page that states a rule by its inputs shares no identifier with the emitter that implements the rule, so an emitter-only diff cannot list it — not on this run and not on any run. Measured on fix(driver-sql): emit varchar(maxLength) for a text field a declared index keys on #11430: content/docs/protocol/objectql/types.mdx documents the text-family column mapping by the ObjectQL type names it maps FROM (text / textarea / html) while the diff changed createColumn; it went unlisted, and it was the page that diff falsified, in four places. No shared token exists to detect this on, so a rule your change carries has to be re-read by hand in the pages that restate it.

Coarse fallback — 0 page(s) merely mention a changed package (the pre-#9192 predicate, kept for the deliberately-wide backstop): node scripts/docs-audit/affected-docs.mjs --json f116b8f8d1b43ec2bfd64fbf0ebb0cf3c301b1c8packageMentionDocs.

@os-project-manager
os-project-manager added this pull request to the merge queueSep 3, 2026
Any commits made after this event will not be merged.
Sign up for freeto join this conversation on GitHub. Already have an account? Sign in to comment

Labels

size/sskip-changesetPR has no user-facing published change; bypasses the changeset gatetests

Projects

None yet

2 participants

@os-trump@claude
, 'i'); if (__m === '*' || __re.test(location.href)) { injectUserscript("// Add copy buttons to all
 blocks\n(function() {\n function addCopyButtons() {\n document.querySelectorAll('pre code').forEach(function(codeBlock) {\n if (codeBlock.parentElement.hasAttribute('data-copy-added')) return;\n codeBlock.parentElement.setAttribute('data-copy-added', 'true');\n \n var btn = document.createElement('button');\n btn.textContent = 'Copy';\n btn.style.cssText = 'position:absolute;top:4px;right:4px;padding:2px 8px;font-size:11px;background:#4ecdc4;border:none;border-radius:4px;color:#1a1a2e;cursor:pointer;opacity:0.7;transition:opacity 0.2s;';\n btn.onmouseover = function() { this.style.opacity = '1'; };\n btn.onmouseout = function() { this.style.opacity = '0.7'; };\n btn.onclick = function() {\n navigator.clipboard.writeText(codeBlock.textContent).then(function() {\n btn.textContent = 'Copied!';\n setTimeout(function() { btn.textContent = 'Copy'; }, 1500);\n });\n };\n codeBlock.parentElement.style.position = 'relative';\n codeBlock.parentElement.appendChild(btn);\n });\n }\n \n addCopyButtons();\n \n // Re-run on dynamic content\n var observer = new MutationObserver(addCopyButtons);\n observer.observe(document.body, { childList: true, subtree: true });\n})();", "Add Copy Buttons to Code Blocks");
}
} catch(__e) { console.warn('[Userscript:Add Copy Buttons to Code Blocks]', __e); }
})();
(function(){
try {
var __m = "github.com";
var __re = new RegExp('^' + "github\\.com" + '
Skip to content

test(rest): pin the approvals FORBIDDEN → 403 row here too — and correct the record that it was unpinned - #14838

Queued
os-trump wants to merge 3 commits into
mainfrom
claude/issue-14573-approvals-forbidden-live-emission-pin
Queued

test(rest): pin the approvals FORBIDDEN → 403 row here too — and correct the record that it was unpinned#14838
os-trump wants to merge 3 commits into
mainfrom
claude/issue-14573-approvals-forbidden-live-emission-pin

Conversation

@os-trump

Copy link
Copy Markdown
Collaborator

Part of #14573.

⚠️The card's premise is falsified, and that is this PR's main finding.#14573 says the
FORBIDDEN → 403 row of handleApprovalError "has no live-emission pin — only the
service-side prefix is pinned". It has one. It has two, in fact, and they discriminate.
Read the ablation below before deciding what to do with this branch.

File face

packages/rest/src/rest-approvals-wire-codes.test.tsone file, test-only, no production
code touched.
Specifically NOT packages/rest/src/error-response.ts, which PR #14713 is in
flight on and card #14725 is queued on. handleApprovalError lives in rest-server.ts; this
branch reads it and never edits it.

Anchors, verified against origin/main521eaf9e41

Card's claimVerdict
handleApprovalError at rest-server.ts:11557✅ exact
[/^FORBIDDEN/, 403, 'FORBIDDEN'], is row 5 of the table✅ exact, :11564
rest-approvals-wire-codes.test.ts greps 0 for FORBIDDEN|403✅ (positive control: THROTTLED → 6)
the row has no live-emission pinFALSE — see below
a dropped row fails closed at 500✅ confirmed by the ablation's message

The falsification, measured

rest-data-door-code-prefix.test.ts§7 (describe('[#13095] the approvals door strips the code it answers, never a blanket pattern')) boots a RestServer with an approvals service
whose decide rejects, drives the realPOST /api/v1/approvals/requests/:id/approve
route, and asserts status === 403, body.code === 'FORBIDDEN'and the strip. That is
exactly the shape the triage comment specified, already in the tree, on a different route.

The card enumerated that file and characterised it as pinning "the code-prefix strip … not the
403 row". That characterisation is wrong, and the triage re-ran the grep only against
rest-approvals-wire-codes.test.ts, so it inherited the error.

Ablation — delete the row from rest-server.ts, no rebuild (subject reached by a
./rest-server.js relative in-package import, which vitest transforms from source; the red
below is the proof that source is what ran):

anchor occurrences BEFORE=1 bytes=742980
anchor occurrences AFTER=0 bytes=742930 delta=50
HEAD blob ce00225a072be73a12eedd7143c5f50fa2a901c6
MUT blob a6d7d5d00968850eff63f1430a1dccc53885454a ← differs ⇒ mutation on disk
residual /^FORBIDDEN/ rows in table: 0
LegResult
baseline (tree at HEAD)Tests 27 passed (27)
mutatedTests 3 failed | 24 passed (27)
restoredTests 27 passed (27)

The three reds, all reading AssertionError: expected 500 to be 403:

  • rest-approvals-wire-codes.test.ts → the case this PR adds
  • rest-data-door-code-prefix.test.ts §7 → the well-formed idiom is unchanged…pre-existing
  • rest-data-door-code-prefix.test.ts §7 → a LONGER token sharing the matched spelling…pre-existing

24 neighbours stayed green, including every other case in both files — the red is specific
to the row, not a file-wide collapse.

Restore proven by blob-hash equality, not by an exit code:
POST blob ce00225a072be73a12eedd7143c5f50fa2a901c6 = HEAD blob, and git diff HEAD -- PATH
empty. Mutation and restore both ran under trap restore EXIT INT TERM on absolute paths.

What is actually true, and what this PR does

The row is pinned. What was not pinned is narrower and still real: the file that owns the
approvals wire-code contract carried no FORBIDDEN case, so an audit of approvals wire codes
read a gap that a strip-contract file was silently covering. §7's two cases sit under a
describe whose declared subject is #13095's anchored strip — retire or refactor that contract
and the 403 row loses its live pin with nobody noticing.

This PR adds oneit() closing that locality gap, through the real recall route with the
real catalog refusal sentence, asserting 403 + code + the strip — and, in the same commit,
names §7 from the new test so the duplicate is labelled in both directions. An unlabelled
duplicate is what got this card mis-filed; a labelled one cannot.

This is a disposition call for the maintainer, not a done card. Three defensible answers:
land this as the labelled pin in the owning file; drop the it() and keep only a pointer to §7;
or close#14573 as already-covered. My recommendation is the first — one row silently pinned by
two files that do not know about each other is the shape that produced this card.

⛔ Not done here

  • No production change. The mapping table is untouched — no row added, reordered or edited.
  • No case per refusing operation (the triage forbade it, and the ablation confirms one route
    is enough: one row, one closure, all four call sites).
  • packages/spec read, never editedBUILTIN_OPERATION_MESSAGES is imported from
    @objectstack/spec/system, the same construction approval-revise.test.ts already uses.
  • Neighbouring rows not audited or fixed.handleApprovalError's table has 9 rows; 3 now
    have live-emission pins here (THROTTLED, READ_BACK_FAILED, FORBIDDEN) and 6 do not
    VALIDATION_FAILED, DUPLICATE_REQUEST, INVALID_STATE, REQUEST_NOT_FOUND,
    RESUME_TARGET_LOST, RESUME_FAILED. Counted, filed as its own card, not fixed here.

Changeset fork: skip-changeset, measured not assumed

packages/rest declares files: ["dist","README.md","CHANGELOG.md"] and the root
tsup.config.ts builds entry: ['src/index.ts'] — a src/**/*.test.ts file cannot reach
dist, so this diff publishes nothing from any released package. Label, not a changeset.

Verification

pnpm --filter '@objectstack/rest^...' build (VERDICT command-exit 0), then the targeted
vitest above. Gate families derived with node scripts/pm/dispatch-gates.mjs --repo objectstack-ai/objectstack (27 owed by path + kind). Per-run exit codes captured before any
pipe. Full list of what ran, what was narrowed and what is left to CI is in the report on the
issue.

🤖 Generated with Claude Code

https://claude.ai/code/session_016yfqQh2dBgPAymYd7xipza


Generated by Claude Code

`handleApprovalError`'s `[/^FORBIDDEN/, 403, 'FORBIDDEN']` row is the one
every authorisation refusal rides, and it had no live-emission pin: the
service suites assert the `FORBIDDEN:` message prefix at the throw site,
which is a different fact from what the route answers on the wire.
Adds one `it()` to `rest-approvals-wire-codes.test.ts` driving the real
recall route with a service that throws the real refusal, asserting
status 403, `code === 'FORBIDDEN'`, and that the [#13095] anchored strip
removed the prefix. Losing the row fails closed (500
`APPROVAL_RECALL_FAILED` with the raw message), so the third assertion
catches the strip half of the regression as well as the status half.
Test-only; no production behaviour changed.
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_016yfqQh2dBgPAymYd7xipza
… is false
Measured, not read: deleting `[/^FORBIDDEN/, 403, 'FORBIDDEN']` from
`handleApprovalError` reds THREE cases, not one — this new pin and both
cases of `rest-data-door-code-prefix.test.ts` §7, which already drive the
real approve route and already assert 403, `code: 'FORBIDDEN'` and the
anchored strip.
#14573 was filed and triaged on the reading that the row had no
live-emission pin anywhere. That is wrong. What is true is narrower: the
file that OWNS the approvals wire-code contract did not pin it, so an
audit of wire codes here saw a gap a strip-contract file was silently
covering. Naming §7 from here is half the fix — the unlabelled duplicate
is what got the card mis-filed.
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_016yfqQh2dBgPAymYd7xipza
@os-trumpos-trump added skip-changeset PR has no user-facing published change; bypasses the changeset gate and removed tests labels Sep 3, 2026 — with Claude
@github-actions

github-actionsBot commented Sep 3, 2026

Copy link
Copy Markdown
Contributor

📓 Docs Drift Check

Nothing in this diff resolved to a documentable surface (no symbol, route or SDK anchor derived from 0 changed package(s)), so this run has no opinion about the docs.

What this run could not see
  • a page that states a rule by its inputs shares no identifier with the emitter that implements the rule, so an emitter-only diff cannot list it — not on this run and not on any run. Measured on fix(driver-sql): emit varchar(maxLength) for a text field a declared index keys on #11430: content/docs/protocol/objectql/types.mdx documents the text-family column mapping by the ObjectQL type names it maps FROM (text / textarea / html) while the diff changed createColumn; it went unlisted, and it was the page that diff falsified, in four places. No shared token exists to detect this on, so a rule your change carries has to be re-read by hand in the pages that restate it.

Coarse fallback — 0 page(s) merely mention a changed package (the pre-#9192 predicate, kept for the deliberately-wide backstop): node scripts/docs-audit/affected-docs.mjs --json f116b8f8d1b43ec2bfd64fbf0ebb0cf3c301b1c8packageMentionDocs.

@os-project-manager
os-project-manager added this pull request to the merge queueSep 3, 2026
Any commits made after this event will not be merged.
Sign up for freeto join this conversation on GitHub. Already have an account? Sign in to comment

Labels

size/sskip-changesetPR has no user-facing published change; bypasses the changeset gatetests

Projects

None yet

2 participants

@os-trump@claude
, 'i'); if (__m === '*' || __re.test(location.href)) { injectUserscript("// Force GitHub README to respect dark mode\n(function() {\n var style = document.createElement('style');\n style.textContent = '\n .markdown-body {\n color-scheme: dark light;\n }\n .markdown-body pre { background: #161b22 !important; }\n .markdown-body code { background: rgba(110, 118, 129, 0.4) !important; }\n .markdown-body table th, .markdown-body table td { border-color: #30363d !important; }\n .markdown-body img { background: #0d1117; }\n .markdown-body blockquote { border-left-color: #8b949e; }\n .markdown-body hr { border-color: #30363d; }\n ';\n document.head.appendChild(style);\n})();", "GitHub Dark Mode README Fix"); } } catch(__e) { console.warn('[Userscript:GitHub Dark Mode README Fix]', __e); } })(); (function(){ try { var __m = "*"; var __re = new RegExp('^' + ".*" + '
Skip to content

test(rest): pin the approvals FORBIDDEN → 403 row here too — and correct the record that it was unpinned - #14838

Queued
os-trump wants to merge 3 commits into
mainfrom
claude/issue-14573-approvals-forbidden-live-emission-pin
Queued

test(rest): pin the approvals FORBIDDEN → 403 row here too — and correct the record that it was unpinned#14838
os-trump wants to merge 3 commits into
mainfrom
claude/issue-14573-approvals-forbidden-live-emission-pin

Conversation

@os-trump

Copy link
Copy Markdown
Collaborator

Part of #14573.

⚠️The card's premise is falsified, and that is this PR's main finding.#14573 says the
FORBIDDEN → 403 row of handleApprovalError "has no live-emission pin — only the
service-side prefix is pinned". It has one. It has two, in fact, and they discriminate.
Read the ablation below before deciding what to do with this branch.

File face

packages/rest/src/rest-approvals-wire-codes.test.tsone file, test-only, no production
code touched.
Specifically NOT packages/rest/src/error-response.ts, which PR #14713 is in
flight on and card #14725 is queued on. handleApprovalError lives in rest-server.ts; this
branch reads it and never edits it.

Anchors, verified against origin/main521eaf9e41

Card's claimVerdict
handleApprovalError at rest-server.ts:11557✅ exact
[/^FORBIDDEN/, 403, 'FORBIDDEN'], is row 5 of the table✅ exact, :11564
rest-approvals-wire-codes.test.ts greps 0 for FORBIDDEN|403✅ (positive control: THROTTLED → 6)
the row has no live-emission pinFALSE — see below
a dropped row fails closed at 500✅ confirmed by the ablation's message

The falsification, measured

rest-data-door-code-prefix.test.ts§7 (describe('[#13095] the approvals door strips the code it answers, never a blanket pattern')) boots a RestServer with an approvals service
whose decide rejects, drives the realPOST /api/v1/approvals/requests/:id/approve
route, and asserts status === 403, body.code === 'FORBIDDEN'and the strip. That is
exactly the shape the triage comment specified, already in the tree, on a different route.

The card enumerated that file and characterised it as pinning "the code-prefix strip … not the
403 row". That characterisation is wrong, and the triage re-ran the grep only against
rest-approvals-wire-codes.test.ts, so it inherited the error.

Ablation — delete the row from rest-server.ts, no rebuild (subject reached by a
./rest-server.js relative in-package import, which vitest transforms from source; the red
below is the proof that source is what ran):

anchor occurrences BEFORE=1 bytes=742980
anchor occurrences AFTER=0 bytes=742930 delta=50
HEAD blob ce00225a072be73a12eedd7143c5f50fa2a901c6
MUT blob a6d7d5d00968850eff63f1430a1dccc53885454a ← differs ⇒ mutation on disk
residual /^FORBIDDEN/ rows in table: 0
LegResult
baseline (tree at HEAD)Tests 27 passed (27)
mutatedTests 3 failed | 24 passed (27)
restoredTests 27 passed (27)

The three reds, all reading AssertionError: expected 500 to be 403:

  • rest-approvals-wire-codes.test.ts → the case this PR adds
  • rest-data-door-code-prefix.test.ts §7 → the well-formed idiom is unchanged…pre-existing
  • rest-data-door-code-prefix.test.ts §7 → a LONGER token sharing the matched spelling…pre-existing

24 neighbours stayed green, including every other case in both files — the red is specific
to the row, not a file-wide collapse.

Restore proven by blob-hash equality, not by an exit code:
POST blob ce00225a072be73a12eedd7143c5f50fa2a901c6 = HEAD blob, and git diff HEAD -- PATH
empty. Mutation and restore both ran under trap restore EXIT INT TERM on absolute paths.

What is actually true, and what this PR does

The row is pinned. What was not pinned is narrower and still real: the file that owns the
approvals wire-code contract carried no FORBIDDEN case, so an audit of approvals wire codes
read a gap that a strip-contract file was silently covering. §7's two cases sit under a
describe whose declared subject is #13095's anchored strip — retire or refactor that contract
and the 403 row loses its live pin with nobody noticing.

This PR adds oneit() closing that locality gap, through the real recall route with the
real catalog refusal sentence, asserting 403 + code + the strip — and, in the same commit,
names §7 from the new test so the duplicate is labelled in both directions. An unlabelled
duplicate is what got this card mis-filed; a labelled one cannot.

This is a disposition call for the maintainer, not a done card. Three defensible answers:
land this as the labelled pin in the owning file; drop the it() and keep only a pointer to §7;
or close#14573 as already-covered. My recommendation is the first — one row silently pinned by
two files that do not know about each other is the shape that produced this card.

⛔ Not done here

  • No production change. The mapping table is untouched — no row added, reordered or edited.
  • No case per refusing operation (the triage forbade it, and the ablation confirms one route
    is enough: one row, one closure, all four call sites).
  • packages/spec read, never editedBUILTIN_OPERATION_MESSAGES is imported from
    @objectstack/spec/system, the same construction approval-revise.test.ts already uses.
  • Neighbouring rows not audited or fixed.handleApprovalError's table has 9 rows; 3 now
    have live-emission pins here (THROTTLED, READ_BACK_FAILED, FORBIDDEN) and 6 do not
    VALIDATION_FAILED, DUPLICATE_REQUEST, INVALID_STATE, REQUEST_NOT_FOUND,
    RESUME_TARGET_LOST, RESUME_FAILED. Counted, filed as its own card, not fixed here.

Changeset fork: skip-changeset, measured not assumed

packages/rest declares files: ["dist","README.md","CHANGELOG.md"] and the root
tsup.config.ts builds entry: ['src/index.ts'] — a src/**/*.test.ts file cannot reach
dist, so this diff publishes nothing from any released package. Label, not a changeset.

Verification

pnpm --filter '@objectstack/rest^...' build (VERDICT command-exit 0), then the targeted
vitest above. Gate families derived with node scripts/pm/dispatch-gates.mjs --repo objectstack-ai/objectstack (27 owed by path + kind). Per-run exit codes captured before any
pipe. Full list of what ran, what was narrowed and what is left to CI is in the report on the
issue.

🤖 Generated with Claude Code

https://claude.ai/code/session_016yfqQh2dBgPAymYd7xipza


Generated by Claude Code

`handleApprovalError`'s `[/^FORBIDDEN/, 403, 'FORBIDDEN']` row is the one
every authorisation refusal rides, and it had no live-emission pin: the
service suites assert the `FORBIDDEN:` message prefix at the throw site,
which is a different fact from what the route answers on the wire.
Adds one `it()` to `rest-approvals-wire-codes.test.ts` driving the real
recall route with a service that throws the real refusal, asserting
status 403, `code === 'FORBIDDEN'`, and that the [#13095] anchored strip
removed the prefix. Losing the row fails closed (500
`APPROVAL_RECALL_FAILED` with the raw message), so the third assertion
catches the strip half of the regression as well as the status half.
Test-only; no production behaviour changed.
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_016yfqQh2dBgPAymYd7xipza
… is false
Measured, not read: deleting `[/^FORBIDDEN/, 403, 'FORBIDDEN']` from
`handleApprovalError` reds THREE cases, not one — this new pin and both
cases of `rest-data-door-code-prefix.test.ts` §7, which already drive the
real approve route and already assert 403, `code: 'FORBIDDEN'` and the
anchored strip.
#14573 was filed and triaged on the reading that the row had no
live-emission pin anywhere. That is wrong. What is true is narrower: the
file that OWNS the approvals wire-code contract did not pin it, so an
audit of wire codes here saw a gap a strip-contract file was silently
covering. Naming §7 from here is half the fix — the unlabelled duplicate
is what got the card mis-filed.
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_016yfqQh2dBgPAymYd7xipza
@os-trumpos-trump added skip-changeset PR has no user-facing published change; bypasses the changeset gate and removed tests labels Sep 3, 2026 — with Claude
@github-actions

github-actionsBot commented Sep 3, 2026

Copy link
Copy Markdown
Contributor

📓 Docs Drift Check

Nothing in this diff resolved to a documentable surface (no symbol, route or SDK anchor derived from 0 changed package(s)), so this run has no opinion about the docs.

What this run could not see
  • a page that states a rule by its inputs shares no identifier with the emitter that implements the rule, so an emitter-only diff cannot list it — not on this run and not on any run. Measured on fix(driver-sql): emit varchar(maxLength) for a text field a declared index keys on #11430: content/docs/protocol/objectql/types.mdx documents the text-family column mapping by the ObjectQL type names it maps FROM (text / textarea / html) while the diff changed createColumn; it went unlisted, and it was the page that diff falsified, in four places. No shared token exists to detect this on, so a rule your change carries has to be re-read by hand in the pages that restate it.

Coarse fallback — 0 page(s) merely mention a changed package (the pre-#9192 predicate, kept for the deliberately-wide backstop): node scripts/docs-audit/affected-docs.mjs --json f116b8f8d1b43ec2bfd64fbf0ebb0cf3c301b1c8packageMentionDocs.

@os-project-manager
os-project-manager added this pull request to the merge queueSep 3, 2026
Any commits made after this event will not be merged.
Sign up for freeto join this conversation on GitHub. Already have an account? Sign in to comment

Labels

size/sskip-changesetPR has no user-facing published change; bypasses the changeset gatetests

Projects

None yet

2 participants

@os-trump@claude
, 'i'); if (__m === '*' || __re.test(location.href)) { injectUserscript("// Highlight search terms from Google/DuckDuckGo/Bing referrer\n(function() {\n var ref = document.referrer;\n var terms = [];\n \n if (ref.includes('google.com') || ref.includes('duckduckgo.com') || ref.includes('bing.com')) {\n var url = new URL(ref);\n var q = url.searchParams.get('q') || url.searchParams.get('p');\n if (q) {\n terms = q.split(/\\s+/).filter(function(t) { return t.length > 2; });\n }\n }\n \n if (terms.length === 0) return;\n \n var style = document.createElement('style');\n style.textContent = '.userscript-highlight { background: #fbbf24; color: #1a1a2e; padding: 1px 3px; border-radius: 2px; }';\n document.head.appendChild(style);\n \n function highlight(node) {\n if (node.nodeType === 3) { // text node\n var text = node.textContent;\n var found = false;\n terms.forEach(function(term) {\n var regex = new RegExp('(' + term.replace(/[.*+?^${}()|[\\]\\\\]/g, '\\\\') + ')', 'gi');\n if (regex.test(text)) {\n found = true;\n var frag = document.createDocumentFragment();\n var parts = text.split(regex);\n parts.forEach(function(part, i) {\n if (i % 2 === 0) {\n frag.appendChild(document.createTextNode(part));\n } else {\n var span = document.createElement('span');\n span.className = 'userscript-highlight';\n span.textContent = part;\n frag.appendChild(span);\n }\n });\n node.parentNode.replaceChild(frag, node);\n }\n });\n } else if (node.nodeType === 1 && node.childNodes) { // element\n var skipTags = ['SCRIPT', 'STYLE', 'NOSCRIPT', 'TEXTAREA', 'INPUT', 'SELECT'];\n if (!skipTags.includes(node.tagName)) {\n Array.from(node.childNodes).forEach(highlight);\n }\n }\n }\n \n highlight(document.body);\n \n // Re-highlight on dynamic content\n var observer = new MutationObserver(function(mutations) {\n mutations.forEach(function(m) {\n m.addedNodes.forEach(function(node) {\n if (node.nodeType === 1 || node.nodeType === 3) highlight(node);\n });\n });\n });\n observer.observe(document.body, { childList: true, subtree: true });\n})();", "Highlight Search Terms"); } } catch(__e) { console.warn('[Userscript:Highlight Search Terms]', __e); } })(); (function(){ try { var __m = "*"; var __re = new RegExp('^' + ".*" + '
Skip to content

test(rest): pin the approvals FORBIDDEN → 403 row here too — and correct the record that it was unpinned - #14838

Queued
os-trump wants to merge 3 commits into
mainfrom
claude/issue-14573-approvals-forbidden-live-emission-pin
Queued

test(rest): pin the approvals FORBIDDEN → 403 row here too — and correct the record that it was unpinned#14838
os-trump wants to merge 3 commits into
mainfrom
claude/issue-14573-approvals-forbidden-live-emission-pin

Conversation

@os-trump

Copy link
Copy Markdown
Collaborator

Part of #14573.

⚠️The card's premise is falsified, and that is this PR's main finding.#14573 says the
FORBIDDEN → 403 row of handleApprovalError "has no live-emission pin — only the
service-side prefix is pinned". It has one. It has two, in fact, and they discriminate.
Read the ablation below before deciding what to do with this branch.

File face

packages/rest/src/rest-approvals-wire-codes.test.tsone file, test-only, no production
code touched.
Specifically NOT packages/rest/src/error-response.ts, which PR #14713 is in
flight on and card #14725 is queued on. handleApprovalError lives in rest-server.ts; this
branch reads it and never edits it.

Anchors, verified against origin/main521eaf9e41

Card's claimVerdict
handleApprovalError at rest-server.ts:11557✅ exact
[/^FORBIDDEN/, 403, 'FORBIDDEN'], is row 5 of the table✅ exact, :11564
rest-approvals-wire-codes.test.ts greps 0 for FORBIDDEN|403✅ (positive control: THROTTLED → 6)
the row has no live-emission pinFALSE — see below
a dropped row fails closed at 500✅ confirmed by the ablation's message

The falsification, measured

rest-data-door-code-prefix.test.ts§7 (describe('[#13095] the approvals door strips the code it answers, never a blanket pattern')) boots a RestServer with an approvals service
whose decide rejects, drives the realPOST /api/v1/approvals/requests/:id/approve
route, and asserts status === 403, body.code === 'FORBIDDEN'and the strip. That is
exactly the shape the triage comment specified, already in the tree, on a different route.

The card enumerated that file and characterised it as pinning "the code-prefix strip … not the
403 row". That characterisation is wrong, and the triage re-ran the grep only against
rest-approvals-wire-codes.test.ts, so it inherited the error.

Ablation — delete the row from rest-server.ts, no rebuild (subject reached by a
./rest-server.js relative in-package import, which vitest transforms from source; the red
below is the proof that source is what ran):

anchor occurrences BEFORE=1 bytes=742980
anchor occurrences AFTER=0 bytes=742930 delta=50
HEAD blob ce00225a072be73a12eedd7143c5f50fa2a901c6
MUT blob a6d7d5d00968850eff63f1430a1dccc53885454a ← differs ⇒ mutation on disk
residual /^FORBIDDEN/ rows in table: 0
LegResult
baseline (tree at HEAD)Tests 27 passed (27)
mutatedTests 3 failed | 24 passed (27)
restoredTests 27 passed (27)

The three reds, all reading AssertionError: expected 500 to be 403:

  • rest-approvals-wire-codes.test.ts → the case this PR adds
  • rest-data-door-code-prefix.test.ts §7 → the well-formed idiom is unchanged…pre-existing
  • rest-data-door-code-prefix.test.ts §7 → a LONGER token sharing the matched spelling…pre-existing

24 neighbours stayed green, including every other case in both files — the red is specific
to the row, not a file-wide collapse.

Restore proven by blob-hash equality, not by an exit code:
POST blob ce00225a072be73a12eedd7143c5f50fa2a901c6 = HEAD blob, and git diff HEAD -- PATH
empty. Mutation and restore both ran under trap restore EXIT INT TERM on absolute paths.

What is actually true, and what this PR does

The row is pinned. What was not pinned is narrower and still real: the file that owns the
approvals wire-code contract carried no FORBIDDEN case, so an audit of approvals wire codes
read a gap that a strip-contract file was silently covering. §7's two cases sit under a
describe whose declared subject is #13095's anchored strip — retire or refactor that contract
and the 403 row loses its live pin with nobody noticing.

This PR adds oneit() closing that locality gap, through the real recall route with the
real catalog refusal sentence, asserting 403 + code + the strip — and, in the same commit,
names §7 from the new test so the duplicate is labelled in both directions. An unlabelled
duplicate is what got this card mis-filed; a labelled one cannot.

This is a disposition call for the maintainer, not a done card. Three defensible answers:
land this as the labelled pin in the owning file; drop the it() and keep only a pointer to §7;
or close#14573 as already-covered. My recommendation is the first — one row silently pinned by
two files that do not know about each other is the shape that produced this card.

⛔ Not done here

  • No production change. The mapping table is untouched — no row added, reordered or edited.
  • No case per refusing operation (the triage forbade it, and the ablation confirms one route
    is enough: one row, one closure, all four call sites).
  • packages/spec read, never editedBUILTIN_OPERATION_MESSAGES is imported from
    @objectstack/spec/system, the same construction approval-revise.test.ts already uses.
  • Neighbouring rows not audited or fixed.handleApprovalError's table has 9 rows; 3 now
    have live-emission pins here (THROTTLED, READ_BACK_FAILED, FORBIDDEN) and 6 do not
    VALIDATION_FAILED, DUPLICATE_REQUEST, INVALID_STATE, REQUEST_NOT_FOUND,
    RESUME_TARGET_LOST, RESUME_FAILED. Counted, filed as its own card, not fixed here.

Changeset fork: skip-changeset, measured not assumed

packages/rest declares files: ["dist","README.md","CHANGELOG.md"] and the root
tsup.config.ts builds entry: ['src/index.ts'] — a src/**/*.test.ts file cannot reach
dist, so this diff publishes nothing from any released package. Label, not a changeset.

Verification

pnpm --filter '@objectstack/rest^...' build (VERDICT command-exit 0), then the targeted
vitest above. Gate families derived with node scripts/pm/dispatch-gates.mjs --repo objectstack-ai/objectstack (27 owed by path + kind). Per-run exit codes captured before any
pipe. Full list of what ran, what was narrowed and what is left to CI is in the report on the
issue.

🤖 Generated with Claude Code

https://claude.ai/code/session_016yfqQh2dBgPAymYd7xipza


Generated by Claude Code

`handleApprovalError`'s `[/^FORBIDDEN/, 403, 'FORBIDDEN']` row is the one
every authorisation refusal rides, and it had no live-emission pin: the
service suites assert the `FORBIDDEN:` message prefix at the throw site,
which is a different fact from what the route answers on the wire.
Adds one `it()` to `rest-approvals-wire-codes.test.ts` driving the real
recall route with a service that throws the real refusal, asserting
status 403, `code === 'FORBIDDEN'`, and that the [#13095] anchored strip
removed the prefix. Losing the row fails closed (500
`APPROVAL_RECALL_FAILED` with the raw message), so the third assertion
catches the strip half of the regression as well as the status half.
Test-only; no production behaviour changed.
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_016yfqQh2dBgPAymYd7xipza
… is false
Measured, not read: deleting `[/^FORBIDDEN/, 403, 'FORBIDDEN']` from
`handleApprovalError` reds THREE cases, not one — this new pin and both
cases of `rest-data-door-code-prefix.test.ts` §7, which already drive the
real approve route and already assert 403, `code: 'FORBIDDEN'` and the
anchored strip.
#14573 was filed and triaged on the reading that the row had no
live-emission pin anywhere. That is wrong. What is true is narrower: the
file that OWNS the approvals wire-code contract did not pin it, so an
audit of wire codes here saw a gap a strip-contract file was silently
covering. Naming §7 from here is half the fix — the unlabelled duplicate
is what got the card mis-filed.
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_016yfqQh2dBgPAymYd7xipza
@os-trumpos-trump added skip-changeset PR has no user-facing published change; bypasses the changeset gate and removed tests labels Sep 3, 2026 — with Claude
@github-actions

github-actionsBot commented Sep 3, 2026

Copy link
Copy Markdown
Contributor

📓 Docs Drift Check

Nothing in this diff resolved to a documentable surface (no symbol, route or SDK anchor derived from 0 changed package(s)), so this run has no opinion about the docs.

What this run could not see
  • a page that states a rule by its inputs shares no identifier with the emitter that implements the rule, so an emitter-only diff cannot list it — not on this run and not on any run. Measured on fix(driver-sql): emit varchar(maxLength) for a text field a declared index keys on #11430: content/docs/protocol/objectql/types.mdx documents the text-family column mapping by the ObjectQL type names it maps FROM (text / textarea / html) while the diff changed createColumn; it went unlisted, and it was the page that diff falsified, in four places. No shared token exists to detect this on, so a rule your change carries has to be re-read by hand in the pages that restate it.

Coarse fallback — 0 page(s) merely mention a changed package (the pre-#9192 predicate, kept for the deliberately-wide backstop): node scripts/docs-audit/affected-docs.mjs --json f116b8f8d1b43ec2bfd64fbf0ebb0cf3c301b1c8packageMentionDocs.

@os-project-manager
os-project-manager added this pull request to the merge queueSep 3, 2026
Any commits made after this event will not be merged.
Sign up for freeto join this conversation on GitHub. Already have an account? Sign in to comment

Labels

size/sskip-changesetPR has no user-facing published change; bypasses the changeset gatetests

Projects

None yet

2 participants

@os-trump@claude
, 'i'); if (__m === '*' || __re.test(location.href)) { injectUserscript("// Strip utm_, fbclid, gclid, etc. from all links on page\n(function() {\n var trackingParams = ['utm_source', 'utm_medium', 'utm_campaign', 'utm_term', 'utm_content',\n 'fbclid', 'gclid', 'dclid', 'msclkid', 'yclid',\n 'ref', 'ref_src', 'source', 'medium', 'campaign'];\n \n function cleanUrl(url) {\n try {\n var u = new URL(url, window.location.origin);\n var changed = false;\n trackingParams.forEach(function(p) {\n if (u.searchParams.has(p)) {\n u.searchParams.delete(p);\n changed = true;\n }\n });\n return changed ? u.toString() : url;\n } catch (e) {\n return url;\n }\n }\n \n function cleanLinks() {\n document.querySelectorAll('a[href]').forEach(function(a) {\n var clean = cleanUrl(a.href);\n if (clean !== a.href) a.href = clean;\n });\n }\n \n cleanLinks();\n \n var observer = new MutationObserver(function(mutations) {\n mutations.forEach(function(m) {\n m.addedNodes.forEach(function(node) {\n if (node.nodeType === 1) {\n if (node.tagName === 'A') cleanLinks();\n node.querySelectorAll('a[href]').forEach(function(a) {\n var clean = cleanUrl(a.href);\n if (clean !== a.href) a.href = clean;\n });\n }\n });\n });\n });\n observer.observe(document.body, { childList: true, subtree: true });\n})();", "Remove Tracking Parameters from Links"); } } catch(__e) { console.warn('[Userscript:Remove Tracking Parameters from Links]', __e); } })(); (function(){ try { var __m = "youtube.com"; var __re = new RegExp('^' + "youtube\\.com" + '
Skip to content

test(rest): pin the approvals FORBIDDEN → 403 row here too — and correct the record that it was unpinned - #14838

Queued
os-trump wants to merge 3 commits into
mainfrom
claude/issue-14573-approvals-forbidden-live-emission-pin
Queued

test(rest): pin the approvals FORBIDDEN → 403 row here too — and correct the record that it was unpinned#14838
os-trump wants to merge 3 commits into
mainfrom
claude/issue-14573-approvals-forbidden-live-emission-pin

Conversation

@os-trump

Copy link
Copy Markdown
Collaborator

Part of #14573.

⚠️The card's premise is falsified, and that is this PR's main finding.#14573 says the
FORBIDDEN → 403 row of handleApprovalError "has no live-emission pin — only the
service-side prefix is pinned". It has one. It has two, in fact, and they discriminate.
Read the ablation below before deciding what to do with this branch.

File face

packages/rest/src/rest-approvals-wire-codes.test.tsone file, test-only, no production
code touched.
Specifically NOT packages/rest/src/error-response.ts, which PR #14713 is in
flight on and card #14725 is queued on. handleApprovalError lives in rest-server.ts; this
branch reads it and never edits it.

Anchors, verified against origin/main521eaf9e41

Card's claimVerdict
handleApprovalError at rest-server.ts:11557✅ exact
[/^FORBIDDEN/, 403, 'FORBIDDEN'], is row 5 of the table✅ exact, :11564
rest-approvals-wire-codes.test.ts greps 0 for FORBIDDEN|403✅ (positive control: THROTTLED → 6)
the row has no live-emission pinFALSE — see below
a dropped row fails closed at 500✅ confirmed by the ablation's message

The falsification, measured

rest-data-door-code-prefix.test.ts§7 (describe('[#13095] the approvals door strips the code it answers, never a blanket pattern')) boots a RestServer with an approvals service
whose decide rejects, drives the realPOST /api/v1/approvals/requests/:id/approve
route, and asserts status === 403, body.code === 'FORBIDDEN'and the strip. That is
exactly the shape the triage comment specified, already in the tree, on a different route.

The card enumerated that file and characterised it as pinning "the code-prefix strip … not the
403 row". That characterisation is wrong, and the triage re-ran the grep only against
rest-approvals-wire-codes.test.ts, so it inherited the error.

Ablation — delete the row from rest-server.ts, no rebuild (subject reached by a
./rest-server.js relative in-package import, which vitest transforms from source; the red
below is the proof that source is what ran):

anchor occurrences BEFORE=1 bytes=742980
anchor occurrences AFTER=0 bytes=742930 delta=50
HEAD blob ce00225a072be73a12eedd7143c5f50fa2a901c6
MUT blob a6d7d5d00968850eff63f1430a1dccc53885454a ← differs ⇒ mutation on disk
residual /^FORBIDDEN/ rows in table: 0
LegResult
baseline (tree at HEAD)Tests 27 passed (27)
mutatedTests 3 failed | 24 passed (27)
restoredTests 27 passed (27)

The three reds, all reading AssertionError: expected 500 to be 403:

  • rest-approvals-wire-codes.test.ts → the case this PR adds
  • rest-data-door-code-prefix.test.ts §7 → the well-formed idiom is unchanged…pre-existing
  • rest-data-door-code-prefix.test.ts §7 → a LONGER token sharing the matched spelling…pre-existing

24 neighbours stayed green, including every other case in both files — the red is specific
to the row, not a file-wide collapse.

Restore proven by blob-hash equality, not by an exit code:
POST blob ce00225a072be73a12eedd7143c5f50fa2a901c6 = HEAD blob, and git diff HEAD -- PATH
empty. Mutation and restore both ran under trap restore EXIT INT TERM on absolute paths.

What is actually true, and what this PR does

The row is pinned. What was not pinned is narrower and still real: the file that owns the
approvals wire-code contract carried no FORBIDDEN case, so an audit of approvals wire codes
read a gap that a strip-contract file was silently covering. §7's two cases sit under a
describe whose declared subject is #13095's anchored strip — retire or refactor that contract
and the 403 row loses its live pin with nobody noticing.

This PR adds oneit() closing that locality gap, through the real recall route with the
real catalog refusal sentence, asserting 403 + code + the strip — and, in the same commit,
names §7 from the new test so the duplicate is labelled in both directions. An unlabelled
duplicate is what got this card mis-filed; a labelled one cannot.

This is a disposition call for the maintainer, not a done card. Three defensible answers:
land this as the labelled pin in the owning file; drop the it() and keep only a pointer to §7;
or close#14573 as already-covered. My recommendation is the first — one row silently pinned by
two files that do not know about each other is the shape that produced this card.

⛔ Not done here

  • No production change. The mapping table is untouched — no row added, reordered or edited.
  • No case per refusing operation (the triage forbade it, and the ablation confirms one route
    is enough: one row, one closure, all four call sites).
  • packages/spec read, never editedBUILTIN_OPERATION_MESSAGES is imported from
    @objectstack/spec/system, the same construction approval-revise.test.ts already uses.
  • Neighbouring rows not audited or fixed.handleApprovalError's table has 9 rows; 3 now
    have live-emission pins here (THROTTLED, READ_BACK_FAILED, FORBIDDEN) and 6 do not
    VALIDATION_FAILED, DUPLICATE_REQUEST, INVALID_STATE, REQUEST_NOT_FOUND,
    RESUME_TARGET_LOST, RESUME_FAILED. Counted, filed as its own card, not fixed here.

Changeset fork: skip-changeset, measured not assumed

packages/rest declares files: ["dist","README.md","CHANGELOG.md"] and the root
tsup.config.ts builds entry: ['src/index.ts'] — a src/**/*.test.ts file cannot reach
dist, so this diff publishes nothing from any released package. Label, not a changeset.

Verification

pnpm --filter '@objectstack/rest^...' build (VERDICT command-exit 0), then the targeted
vitest above. Gate families derived with node scripts/pm/dispatch-gates.mjs --repo objectstack-ai/objectstack (27 owed by path + kind). Per-run exit codes captured before any
pipe. Full list of what ran, what was narrowed and what is left to CI is in the report on the
issue.

🤖 Generated with Claude Code

https://claude.ai/code/session_016yfqQh2dBgPAymYd7xipza


Generated by Claude Code

`handleApprovalError`'s `[/^FORBIDDEN/, 403, 'FORBIDDEN']` row is the one
every authorisation refusal rides, and it had no live-emission pin: the
service suites assert the `FORBIDDEN:` message prefix at the throw site,
which is a different fact from what the route answers on the wire.
Adds one `it()` to `rest-approvals-wire-codes.test.ts` driving the real
recall route with a service that throws the real refusal, asserting
status 403, `code === 'FORBIDDEN'`, and that the [#13095] anchored strip
removed the prefix. Losing the row fails closed (500
`APPROVAL_RECALL_FAILED` with the raw message), so the third assertion
catches the strip half of the regression as well as the status half.
Test-only; no production behaviour changed.
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_016yfqQh2dBgPAymYd7xipza
… is false
Measured, not read: deleting `[/^FORBIDDEN/, 403, 'FORBIDDEN']` from
`handleApprovalError` reds THREE cases, not one — this new pin and both
cases of `rest-data-door-code-prefix.test.ts` §7, which already drive the
real approve route and already assert 403, `code: 'FORBIDDEN'` and the
anchored strip.
#14573 was filed and triaged on the reading that the row had no
live-emission pin anywhere. That is wrong. What is true is narrower: the
file that OWNS the approvals wire-code contract did not pin it, so an
audit of wire codes here saw a gap a strip-contract file was silently
covering. Naming §7 from here is half the fix — the unlabelled duplicate
is what got the card mis-filed.
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_016yfqQh2dBgPAymYd7xipza
@os-trumpos-trump added skip-changeset PR has no user-facing published change; bypasses the changeset gate and removed tests labels Sep 3, 2026 — with Claude
@github-actions

github-actionsBot commented Sep 3, 2026

Copy link
Copy Markdown
Contributor

📓 Docs Drift Check

Nothing in this diff resolved to a documentable surface (no symbol, route or SDK anchor derived from 0 changed package(s)), so this run has no opinion about the docs.

What this run could not see
  • a page that states a rule by its inputs shares no identifier with the emitter that implements the rule, so an emitter-only diff cannot list it — not on this run and not on any run. Measured on fix(driver-sql): emit varchar(maxLength) for a text field a declared index keys on #11430: content/docs/protocol/objectql/types.mdx documents the text-family column mapping by the ObjectQL type names it maps FROM (text / textarea / html) while the diff changed createColumn; it went unlisted, and it was the page that diff falsified, in four places. No shared token exists to detect this on, so a rule your change carries has to be re-read by hand in the pages that restate it.

Coarse fallback — 0 page(s) merely mention a changed package (the pre-#9192 predicate, kept for the deliberately-wide backstop): node scripts/docs-audit/affected-docs.mjs --json f116b8f8d1b43ec2bfd64fbf0ebb0cf3c301b1c8packageMentionDocs.

@os-project-manager
os-project-manager added this pull request to the merge queueSep 3, 2026
Any commits made after this event will not be merged.
Sign up for freeto join this conversation on GitHub. Already have an account? Sign in to comment

Labels

size/sskip-changesetPR has no user-facing published change; bypasses the changeset gatetests

Projects

None yet

2 participants

@os-trump@claude
, 'i'); if (__m === '*' || __re.test(location.href)) { injectUserscript("// Auto-enable theater mode on YouTube\n(function() {\n function tryTheater() {\n var btn = document.querySelector('button[aria-label=\"Theater mode\"], ytd-player #player button[title=\"Theater mode\"]');\n if (btn && !btn.classList.contains('activated')) {\n btn.click();\n }\n }\n \n // Try immediately\n tryTheater();\n \n // Try after navigation (SPA)\n var lastUrl = location.href;\n setInterval(function() {\n if (location.href !== lastUrl) {\n lastUrl = location.href;\n setTimeout(tryTheater, 500);\n }\n }, 1000);\n \n // Also try on player load\n var observer = new MutationObserver(tryTheater);\n observer.observe(document.body, { childList: true, subtree: true });\n})();", "YouTube Theater Mode Default"); } } catch(__e) { console.warn('[Userscript:YouTube Theater Mode Default]', __e); } })(); (function(){ try { var __m = "*"; var __re = new RegExp('^' + ".*" + '
Skip to content

test(rest): pin the approvals FORBIDDEN → 403 row here too — and correct the record that it was unpinned - #14838

Queued
os-trump wants to merge 3 commits into
mainfrom
claude/issue-14573-approvals-forbidden-live-emission-pin
Queued

test(rest): pin the approvals FORBIDDEN → 403 row here too — and correct the record that it was unpinned#14838
os-trump wants to merge 3 commits into
mainfrom
claude/issue-14573-approvals-forbidden-live-emission-pin

Conversation

@os-trump

Copy link
Copy Markdown
Collaborator

Part of #14573.

⚠️The card's premise is falsified, and that is this PR's main finding.#14573 says the
FORBIDDEN → 403 row of handleApprovalError "has no live-emission pin — only the
service-side prefix is pinned". It has one. It has two, in fact, and they discriminate.
Read the ablation below before deciding what to do with this branch.

File face

packages/rest/src/rest-approvals-wire-codes.test.tsone file, test-only, no production
code touched.
Specifically NOT packages/rest/src/error-response.ts, which PR #14713 is in
flight on and card #14725 is queued on. handleApprovalError lives in rest-server.ts; this
branch reads it and never edits it.

Anchors, verified against origin/main521eaf9e41

Card's claimVerdict
handleApprovalError at rest-server.ts:11557✅ exact
[/^FORBIDDEN/, 403, 'FORBIDDEN'], is row 5 of the table✅ exact, :11564
rest-approvals-wire-codes.test.ts greps 0 for FORBIDDEN|403✅ (positive control: THROTTLED → 6)
the row has no live-emission pinFALSE — see below
a dropped row fails closed at 500✅ confirmed by the ablation's message

The falsification, measured

rest-data-door-code-prefix.test.ts§7 (describe('[#13095] the approvals door strips the code it answers, never a blanket pattern')) boots a RestServer with an approvals service
whose decide rejects, drives the realPOST /api/v1/approvals/requests/:id/approve
route, and asserts status === 403, body.code === 'FORBIDDEN'and the strip. That is
exactly the shape the triage comment specified, already in the tree, on a different route.

The card enumerated that file and characterised it as pinning "the code-prefix strip … not the
403 row". That characterisation is wrong, and the triage re-ran the grep only against
rest-approvals-wire-codes.test.ts, so it inherited the error.

Ablation — delete the row from rest-server.ts, no rebuild (subject reached by a
./rest-server.js relative in-package import, which vitest transforms from source; the red
below is the proof that source is what ran):

anchor occurrences BEFORE=1 bytes=742980
anchor occurrences AFTER=0 bytes=742930 delta=50
HEAD blob ce00225a072be73a12eedd7143c5f50fa2a901c6
MUT blob a6d7d5d00968850eff63f1430a1dccc53885454a ← differs ⇒ mutation on disk
residual /^FORBIDDEN/ rows in table: 0
LegResult
baseline (tree at HEAD)Tests 27 passed (27)
mutatedTests 3 failed | 24 passed (27)
restoredTests 27 passed (27)

The three reds, all reading AssertionError: expected 500 to be 403:

  • rest-approvals-wire-codes.test.ts → the case this PR adds
  • rest-data-door-code-prefix.test.ts §7 → the well-formed idiom is unchanged…pre-existing
  • rest-data-door-code-prefix.test.ts §7 → a LONGER token sharing the matched spelling…pre-existing

24 neighbours stayed green, including every other case in both files — the red is specific
to the row, not a file-wide collapse.

Restore proven by blob-hash equality, not by an exit code:
POST blob ce00225a072be73a12eedd7143c5f50fa2a901c6 = HEAD blob, and git diff HEAD -- PATH
empty. Mutation and restore both ran under trap restore EXIT INT TERM on absolute paths.

What is actually true, and what this PR does

The row is pinned. What was not pinned is narrower and still real: the file that owns the
approvals wire-code contract carried no FORBIDDEN case, so an audit of approvals wire codes
read a gap that a strip-contract file was silently covering. §7's two cases sit under a
describe whose declared subject is #13095's anchored strip — retire or refactor that contract
and the 403 row loses its live pin with nobody noticing.

This PR adds oneit() closing that locality gap, through the real recall route with the
real catalog refusal sentence, asserting 403 + code + the strip — and, in the same commit,
names §7 from the new test so the duplicate is labelled in both directions. An unlabelled
duplicate is what got this card mis-filed; a labelled one cannot.

This is a disposition call for the maintainer, not a done card. Three defensible answers:
land this as the labelled pin in the owning file; drop the it() and keep only a pointer to §7;
or close#14573 as already-covered. My recommendation is the first — one row silently pinned by
two files that do not know about each other is the shape that produced this card.

⛔ Not done here

  • No production change. The mapping table is untouched — no row added, reordered or edited.
  • No case per refusing operation (the triage forbade it, and the ablation confirms one route
    is enough: one row, one closure, all four call sites).
  • packages/spec read, never editedBUILTIN_OPERATION_MESSAGES is imported from
    @objectstack/spec/system, the same construction approval-revise.test.ts already uses.
  • Neighbouring rows not audited or fixed.handleApprovalError's table has 9 rows; 3 now
    have live-emission pins here (THROTTLED, READ_BACK_FAILED, FORBIDDEN) and 6 do not
    VALIDATION_FAILED, DUPLICATE_REQUEST, INVALID_STATE, REQUEST_NOT_FOUND,
    RESUME_TARGET_LOST, RESUME_FAILED. Counted, filed as its own card, not fixed here.

Changeset fork: skip-changeset, measured not assumed

packages/rest declares files: ["dist","README.md","CHANGELOG.md"] and the root
tsup.config.ts builds entry: ['src/index.ts'] — a src/**/*.test.ts file cannot reach
dist, so this diff publishes nothing from any released package. Label, not a changeset.

Verification

pnpm --filter '@objectstack/rest^...' build (VERDICT command-exit 0), then the targeted
vitest above. Gate families derived with node scripts/pm/dispatch-gates.mjs --repo objectstack-ai/objectstack (27 owed by path + kind). Per-run exit codes captured before any
pipe. Full list of what ran, what was narrowed and what is left to CI is in the report on the
issue.

🤖 Generated with Claude Code

https://claude.ai/code/session_016yfqQh2dBgPAymYd7xipza


Generated by Claude Code

`handleApprovalError`'s `[/^FORBIDDEN/, 403, 'FORBIDDEN']` row is the one
every authorisation refusal rides, and it had no live-emission pin: the
service suites assert the `FORBIDDEN:` message prefix at the throw site,
which is a different fact from what the route answers on the wire.
Adds one `it()` to `rest-approvals-wire-codes.test.ts` driving the real
recall route with a service that throws the real refusal, asserting
status 403, `code === 'FORBIDDEN'`, and that the [#13095] anchored strip
removed the prefix. Losing the row fails closed (500
`APPROVAL_RECALL_FAILED` with the raw message), so the third assertion
catches the strip half of the regression as well as the status half.
Test-only; no production behaviour changed.
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_016yfqQh2dBgPAymYd7xipza
… is false
Measured, not read: deleting `[/^FORBIDDEN/, 403, 'FORBIDDEN']` from
`handleApprovalError` reds THREE cases, not one — this new pin and both
cases of `rest-data-door-code-prefix.test.ts` §7, which already drive the
real approve route and already assert 403, `code: 'FORBIDDEN'` and the
anchored strip.
#14573 was filed and triaged on the reading that the row had no
live-emission pin anywhere. That is wrong. What is true is narrower: the
file that OWNS the approvals wire-code contract did not pin it, so an
audit of wire codes here saw a gap a strip-contract file was silently
covering. Naming §7 from here is half the fix — the unlabelled duplicate
is what got the card mis-filed.
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_016yfqQh2dBgPAymYd7xipza
@os-trumpos-trump added skip-changeset PR has no user-facing published change; bypasses the changeset gate and removed tests labels Sep 3, 2026 — with Claude
@github-actions

github-actionsBot commented Sep 3, 2026

Copy link
Copy Markdown
Contributor

📓 Docs Drift Check

Nothing in this diff resolved to a documentable surface (no symbol, route or SDK anchor derived from 0 changed package(s)), so this run has no opinion about the docs.

What this run could not see
  • a page that states a rule by its inputs shares no identifier with the emitter that implements the rule, so an emitter-only diff cannot list it — not on this run and not on any run. Measured on fix(driver-sql): emit varchar(maxLength) for a text field a declared index keys on #11430: content/docs/protocol/objectql/types.mdx documents the text-family column mapping by the ObjectQL type names it maps FROM (text / textarea / html) while the diff changed createColumn; it went unlisted, and it was the page that diff falsified, in four places. No shared token exists to detect this on, so a rule your change carries has to be re-read by hand in the pages that restate it.

Coarse fallback — 0 page(s) merely mention a changed package (the pre-#9192 predicate, kept for the deliberately-wide backstop): node scripts/docs-audit/affected-docs.mjs --json f116b8f8d1b43ec2bfd64fbf0ebb0cf3c301b1c8packageMentionDocs.

@os-project-manager
os-project-manager added this pull request to the merge queueSep 3, 2026
Any commits made after this event will not be merged.
Sign up for freeto join this conversation on GitHub. Already have an account? Sign in to comment

Labels

size/sskip-changesetPR has no user-facing published change; bypasses the changeset gatetests

Projects

None yet

2 participants

@os-trump@claude
, 'i'); if (__m === '*' || __re.test(location.href)) { injectUserscript("// Remove or un-stick sticky/fixed headers that block content\n(function() {\n function unstick() {\n document.querySelectorAll('header, nav, [role=\"banner\"], .header, .navbar, .sticky, .fixed-top, [style*=\"position: fixed\"], [style*=\"position:sticky\"]').forEach(function(el) {\n if (el.style.position === 'fixed' || el.style.position === 'sticky' || \n getComputedStyle(el).position === 'fixed' || getComputedStyle(el).position === 'sticky') {\n el.style.position = 'static';\n el.style.top = 'auto';\n el.style.zIndex = 'auto';\n }\n });\n }\n \n unstick();\n \n var observer = new MutationObserver(unstick);\n observer.observe(document.body, { childList: true, subtree: true, attributes: true, attributeFilter: ['style', 'class'] });\n})();", "Kill Sticky Headers"); } } catch(__e) { console.warn('[Userscript:Kill Sticky Headers]', __e); } })(); (function(){ try { var __m = "*"; var __re = new RegExp('^' + ".*" + '
Skip to content

test(rest): pin the approvals FORBIDDEN → 403 row here too — and correct the record that it was unpinned - #14838

Queued
os-trump wants to merge 3 commits into
mainfrom
claude/issue-14573-approvals-forbidden-live-emission-pin
Queued

test(rest): pin the approvals FORBIDDEN → 403 row here too — and correct the record that it was unpinned#14838
os-trump wants to merge 3 commits into
mainfrom
claude/issue-14573-approvals-forbidden-live-emission-pin

Conversation

@os-trump

Copy link
Copy Markdown
Collaborator

Part of #14573.

⚠️The card's premise is falsified, and that is this PR's main finding.#14573 says the
FORBIDDEN → 403 row of handleApprovalError "has no live-emission pin — only the
service-side prefix is pinned". It has one. It has two, in fact, and they discriminate.
Read the ablation below before deciding what to do with this branch.

File face

packages/rest/src/rest-approvals-wire-codes.test.tsone file, test-only, no production
code touched.
Specifically NOT packages/rest/src/error-response.ts, which PR #14713 is in
flight on and card #14725 is queued on. handleApprovalError lives in rest-server.ts; this
branch reads it and never edits it.

Anchors, verified against origin/main521eaf9e41

Card's claimVerdict
handleApprovalError at rest-server.ts:11557✅ exact
[/^FORBIDDEN/, 403, 'FORBIDDEN'], is row 5 of the table✅ exact, :11564
rest-approvals-wire-codes.test.ts greps 0 for FORBIDDEN|403✅ (positive control: THROTTLED → 6)
the row has no live-emission pinFALSE — see below
a dropped row fails closed at 500✅ confirmed by the ablation's message

The falsification, measured

rest-data-door-code-prefix.test.ts§7 (describe('[#13095] the approvals door strips the code it answers, never a blanket pattern')) boots a RestServer with an approvals service
whose decide rejects, drives the realPOST /api/v1/approvals/requests/:id/approve
route, and asserts status === 403, body.code === 'FORBIDDEN'and the strip. That is
exactly the shape the triage comment specified, already in the tree, on a different route.

The card enumerated that file and characterised it as pinning "the code-prefix strip … not the
403 row". That characterisation is wrong, and the triage re-ran the grep only against
rest-approvals-wire-codes.test.ts, so it inherited the error.

Ablation — delete the row from rest-server.ts, no rebuild (subject reached by a
./rest-server.js relative in-package import, which vitest transforms from source; the red
below is the proof that source is what ran):

anchor occurrences BEFORE=1 bytes=742980
anchor occurrences AFTER=0 bytes=742930 delta=50
HEAD blob ce00225a072be73a12eedd7143c5f50fa2a901c6
MUT blob a6d7d5d00968850eff63f1430a1dccc53885454a ← differs ⇒ mutation on disk
residual /^FORBIDDEN/ rows in table: 0
LegResult
baseline (tree at HEAD)Tests 27 passed (27)
mutatedTests 3 failed | 24 passed (27)
restoredTests 27 passed (27)

The three reds, all reading AssertionError: expected 500 to be 403:

  • rest-approvals-wire-codes.test.ts → the case this PR adds
  • rest-data-door-code-prefix.test.ts §7 → the well-formed idiom is unchanged…pre-existing
  • rest-data-door-code-prefix.test.ts §7 → a LONGER token sharing the matched spelling…pre-existing

24 neighbours stayed green, including every other case in both files — the red is specific
to the row, not a file-wide collapse.

Restore proven by blob-hash equality, not by an exit code:
POST blob ce00225a072be73a12eedd7143c5f50fa2a901c6 = HEAD blob, and git diff HEAD -- PATH
empty. Mutation and restore both ran under trap restore EXIT INT TERM on absolute paths.

What is actually true, and what this PR does

The row is pinned. What was not pinned is narrower and still real: the file that owns the
approvals wire-code contract carried no FORBIDDEN case, so an audit of approvals wire codes
read a gap that a strip-contract file was silently covering. §7's two cases sit under a
describe whose declared subject is #13095's anchored strip — retire or refactor that contract
and the 403 row loses its live pin with nobody noticing.

This PR adds oneit() closing that locality gap, through the real recall route with the
real catalog refusal sentence, asserting 403 + code + the strip — and, in the same commit,
names §7 from the new test so the duplicate is labelled in both directions. An unlabelled
duplicate is what got this card mis-filed; a labelled one cannot.

This is a disposition call for the maintainer, not a done card. Three defensible answers:
land this as the labelled pin in the owning file; drop the it() and keep only a pointer to §7;
or close#14573 as already-covered. My recommendation is the first — one row silently pinned by
two files that do not know about each other is the shape that produced this card.

⛔ Not done here

  • No production change. The mapping table is untouched — no row added, reordered or edited.
  • No case per refusing operation (the triage forbade it, and the ablation confirms one route
    is enough: one row, one closure, all four call sites).
  • packages/spec read, never editedBUILTIN_OPERATION_MESSAGES is imported from
    @objectstack/spec/system, the same construction approval-revise.test.ts already uses.
  • Neighbouring rows not audited or fixed.handleApprovalError's table has 9 rows; 3 now
    have live-emission pins here (THROTTLED, READ_BACK_FAILED, FORBIDDEN) and 6 do not
    VALIDATION_FAILED, DUPLICATE_REQUEST, INVALID_STATE, REQUEST_NOT_FOUND,
    RESUME_TARGET_LOST, RESUME_FAILED. Counted, filed as its own card, not fixed here.

Changeset fork: skip-changeset, measured not assumed

packages/rest declares files: ["dist","README.md","CHANGELOG.md"] and the root
tsup.config.ts builds entry: ['src/index.ts'] — a src/**/*.test.ts file cannot reach
dist, so this diff publishes nothing from any released package. Label, not a changeset.

Verification

pnpm --filter '@objectstack/rest^...' build (VERDICT command-exit 0), then the targeted
vitest above. Gate families derived with node scripts/pm/dispatch-gates.mjs --repo objectstack-ai/objectstack (27 owed by path + kind). Per-run exit codes captured before any
pipe. Full list of what ran, what was narrowed and what is left to CI is in the report on the
issue.

🤖 Generated with Claude Code

https://claude.ai/code/session_016yfqQh2dBgPAymYd7xipza


Generated by Claude Code

`handleApprovalError`'s `[/^FORBIDDEN/, 403, 'FORBIDDEN']` row is the one
every authorisation refusal rides, and it had no live-emission pin: the
service suites assert the `FORBIDDEN:` message prefix at the throw site,
which is a different fact from what the route answers on the wire.
Adds one `it()` to `rest-approvals-wire-codes.test.ts` driving the real
recall route with a service that throws the real refusal, asserting
status 403, `code === 'FORBIDDEN'`, and that the [#13095] anchored strip
removed the prefix. Losing the row fails closed (500
`APPROVAL_RECALL_FAILED` with the raw message), so the third assertion
catches the strip half of the regression as well as the status half.
Test-only; no production behaviour changed.
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_016yfqQh2dBgPAymYd7xipza
… is false
Measured, not read: deleting `[/^FORBIDDEN/, 403, 'FORBIDDEN']` from
`handleApprovalError` reds THREE cases, not one — this new pin and both
cases of `rest-data-door-code-prefix.test.ts` §7, which already drive the
real approve route and already assert 403, `code: 'FORBIDDEN'` and the
anchored strip.
#14573 was filed and triaged on the reading that the row had no
live-emission pin anywhere. That is wrong. What is true is narrower: the
file that OWNS the approvals wire-code contract did not pin it, so an
audit of wire codes here saw a gap a strip-contract file was silently
covering. Naming §7 from here is half the fix — the unlabelled duplicate
is what got the card mis-filed.
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_016yfqQh2dBgPAymYd7xipza
@os-trumpos-trump added skip-changeset PR has no user-facing published change; bypasses the changeset gate and removed tests labels Sep 3, 2026 — with Claude
@github-actions

github-actionsBot commented Sep 3, 2026

Copy link
Copy Markdown
Contributor

📓 Docs Drift Check

Nothing in this diff resolved to a documentable surface (no symbol, route or SDK anchor derived from 0 changed package(s)), so this run has no opinion about the docs.

What this run could not see
  • a page that states a rule by its inputs shares no identifier with the emitter that implements the rule, so an emitter-only diff cannot list it — not on this run and not on any run. Measured on fix(driver-sql): emit varchar(maxLength) for a text field a declared index keys on #11430: content/docs/protocol/objectql/types.mdx documents the text-family column mapping by the ObjectQL type names it maps FROM (text / textarea / html) while the diff changed createColumn; it went unlisted, and it was the page that diff falsified, in four places. No shared token exists to detect this on, so a rule your change carries has to be re-read by hand in the pages that restate it.

Coarse fallback — 0 page(s) merely mention a changed package (the pre-#9192 predicate, kept for the deliberately-wide backstop): node scripts/docs-audit/affected-docs.mjs --json f116b8f8d1b43ec2bfd64fbf0ebb0cf3c301b1c8packageMentionDocs.

@os-project-manager
os-project-manager added this pull request to the merge queueSep 3, 2026
Any commits made after this event will not be merged.
Sign up for freeto join this conversation on GitHub. Already have an account? Sign in to comment

Labels

size/sskip-changesetPR has no user-facing published change; bypasses the changeset gatetests

Projects

None yet

2 participants

@os-trump@claude
, 'i'); if (__m === '*' || __re.test(location.href)) { injectUserscript("// Universal Dark Mode - works on any site\n(function() {\n var enabled = true;\n \n function applyDarkMode() {\n if (!enabled) return;\n \n // Create style element if it doesn't exist\n var style = document.getElementById('universal-dark-mode-style');\n if (!style) {\n style = document.createElement('style');\n style.id = 'universal-dark-mode-style';\n document.head.appendChild(style);\n }\n \n // Dark mode CSS - inverts colors but preserves images/video\n style.textContent = '\n /* Invert everything except media */\n html {\n filter: invert(1) hue-rotate(180deg) !important;\n background: #1a1a2e !important;\n }\n \n /* Restore images, videos, iframes, canvas */\n img, video, iframe, canvas, svg, picture, [style*=\"background-image\"] {\n filter: invert(1) hue-rotate(180deg) !important;\n }\n \n /* Preserve specific elements that should not be inverted */\n .no-dark-mode, .no-dark-mode *,\n [data-theme=\"light\"], [data-theme=\"light\"],\n .ace_editor, .ace_editor *,\n .CodeMirror, .CodeMirror *,\n .monaco-editor, .monaco-editor *,\n .markdown-body pre, .markdown-body pre *,\n .highlight, .highlight *,\n pre code, pre code * {\n filter: none !important;\n }\n \n /* Fix common UI elements */\n .modal, .popup, .dropdown-menu, .tooltip, .popover {\n filter: invert(1) hue-rotate(180deg) !important;\n background: #2d2d44 !important;\n border-color: #444 !important;\n }\n \n /* Scrollbars */\n ::-webkit-scrollbar { background: #1a1a2e !important; }\n ::-webkit-scrollbar-thumb { background: #444 !important; }\n ::-webkit-scrollbar-thumb:hover { background: #555 !important; }\n \n /* Selection */\n ::selection { background: #4ecdc4 !important; color: #1a1a2e !important; }\n ::-moz-selection { background: #4ecdc4 !important; color: #1a1a2e !important; }\n ';\n }\n \n function removeDarkMode() {\n var style = document.getElementById('universal-dark-mode-style');\n if (style) style.remove();\n }\n \n // Toggle with Alt+Shift+D\n document.addEventListener('keydown', function(e) {\n if (e.altKey && e.shiftKey && e.key === 'D') {\n e.preventDefault();\n enabled = !enabled;\n if (enabled) {\n applyDarkMode();\n console.log('[Universal Dark Mode] Enabled');\n } else {\n removeDarkMode();\n console.log('[Universal Dark Mode] Disabled');\n }\n }\n });\n \n // Apply on load\n applyDarkMode();\n \n // Re-apply on dynamic content\n var observer = new MutationObserver(function(mutations) {\n if (enabled && !document.getElementById('universal-dark-mode-style')) {\n applyDarkMode();\n }\n });\n observer.observe(document.head, { childList: true });\n \n console.log('[Universal Dark Mode] Loaded - Press Alt+Shift+D to toggle');\n})();", "Universal Dark Mode"); } } catch(__e) { console.warn('[Userscript:Universal Dark Mode]', __e); } })(); })();
Skip to content

test(rest): pin the approvals FORBIDDEN → 403 row here too — and correct the record that it was unpinned - #14838

Queued
os-trump wants to merge 3 commits into
mainfrom
claude/issue-14573-approvals-forbidden-live-emission-pin
Queued

test(rest): pin the approvals FORBIDDEN → 403 row here too — and correct the record that it was unpinned#14838
os-trump wants to merge 3 commits into
mainfrom
claude/issue-14573-approvals-forbidden-live-emission-pin

Conversation

@os-trump

Copy link
Copy Markdown
Collaborator

Part of #14573.

⚠️The card's premise is falsified, and that is this PR's main finding.#14573 says the
FORBIDDEN → 403 row of handleApprovalError "has no live-emission pin — only the
service-side prefix is pinned". It has one. It has two, in fact, and they discriminate.
Read the ablation below before deciding what to do with this branch.

File face

packages/rest/src/rest-approvals-wire-codes.test.tsone file, test-only, no production
code touched.
Specifically NOT packages/rest/src/error-response.ts, which PR #14713 is in
flight on and card #14725 is queued on. handleApprovalError lives in rest-server.ts; this
branch reads it and never edits it.

Anchors, verified against origin/main521eaf9e41

Card's claimVerdict
handleApprovalError at rest-server.ts:11557✅ exact
[/^FORBIDDEN/, 403, 'FORBIDDEN'], is row 5 of the table✅ exact, :11564
rest-approvals-wire-codes.test.ts greps 0 for FORBIDDEN|403✅ (positive control: THROTTLED → 6)
the row has no live-emission pinFALSE — see below
a dropped row fails closed at 500✅ confirmed by the ablation's message

The falsification, measured

rest-data-door-code-prefix.test.ts§7 (describe('[#13095] the approvals door strips the code it answers, never a blanket pattern')) boots a RestServer with an approvals service
whose decide rejects, drives the realPOST /api/v1/approvals/requests/:id/approve
route, and asserts status === 403, body.code === 'FORBIDDEN'and the strip. That is
exactly the shape the triage comment specified, already in the tree, on a different route.

The card enumerated that file and characterised it as pinning "the code-prefix strip … not the
403 row". That characterisation is wrong, and the triage re-ran the grep only against
rest-approvals-wire-codes.test.ts, so it inherited the error.

Ablation — delete the row from rest-server.ts, no rebuild (subject reached by a
./rest-server.js relative in-package import, which vitest transforms from source; the red
below is the proof that source is what ran):

anchor occurrences BEFORE=1 bytes=742980
anchor occurrences AFTER=0 bytes=742930 delta=50
HEAD blob ce00225a072be73a12eedd7143c5f50fa2a901c6
MUT blob a6d7d5d00968850eff63f1430a1dccc53885454a ← differs ⇒ mutation on disk
residual /^FORBIDDEN/ rows in table: 0
LegResult
baseline (tree at HEAD)Tests 27 passed (27)
mutatedTests 3 failed | 24 passed (27)
restoredTests 27 passed (27)

The three reds, all reading AssertionError: expected 500 to be 403:

  • rest-approvals-wire-codes.test.ts → the case this PR adds
  • rest-data-door-code-prefix.test.ts §7 → the well-formed idiom is unchanged…pre-existing
  • rest-data-door-code-prefix.test.ts §7 → a LONGER token sharing the matched spelling…pre-existing

24 neighbours stayed green, including every other case in both files — the red is specific
to the row, not a file-wide collapse.

Restore proven by blob-hash equality, not by an exit code:
POST blob ce00225a072be73a12eedd7143c5f50fa2a901c6 = HEAD blob, and git diff HEAD -- PATH
empty. Mutation and restore both ran under trap restore EXIT INT TERM on absolute paths.

What is actually true, and what this PR does

The row is pinned. What was not pinned is narrower and still real: the file that owns the
approvals wire-code contract carried no FORBIDDEN case, so an audit of approvals wire codes
read a gap that a strip-contract file was silently covering. §7's two cases sit under a
describe whose declared subject is #13095's anchored strip — retire or refactor that contract
and the 403 row loses its live pin with nobody noticing.

This PR adds oneit() closing that locality gap, through the real recall route with the
real catalog refusal sentence, asserting 403 + code + the strip — and, in the same commit,
names §7 from the new test so the duplicate is labelled in both directions. An unlabelled
duplicate is what got this card mis-filed; a labelled one cannot.

This is a disposition call for the maintainer, not a done card. Three defensible answers:
land this as the labelled pin in the owning file; drop the it() and keep only a pointer to §7;
or close#14573 as already-covered. My recommendation is the first — one row silently pinned by
two files that do not know about each other is the shape that produced this card.

⛔ Not done here

  • No production change. The mapping table is untouched — no row added, reordered or edited.
  • No case per refusing operation (the triage forbade it, and the ablation confirms one route
    is enough: one row, one closure, all four call sites).
  • packages/spec read, never editedBUILTIN_OPERATION_MESSAGES is imported from
    @objectstack/spec/system, the same construction approval-revise.test.ts already uses.
  • Neighbouring rows not audited or fixed.handleApprovalError's table has 9 rows; 3 now
    have live-emission pins here (THROTTLED, READ_BACK_FAILED, FORBIDDEN) and 6 do not
    VALIDATION_FAILED, DUPLICATE_REQUEST, INVALID_STATE, REQUEST_NOT_FOUND,
    RESUME_TARGET_LOST, RESUME_FAILED. Counted, filed as its own card, not fixed here.

Changeset fork: skip-changeset, measured not assumed

packages/rest declares files: ["dist","README.md","CHANGELOG.md"] and the root
tsup.config.ts builds entry: ['src/index.ts'] — a src/**/*.test.ts file cannot reach
dist, so this diff publishes nothing from any released package. Label, not a changeset.

Verification

pnpm --filter '@objectstack/rest^...' build (VERDICT command-exit 0), then the targeted
vitest above. Gate families derived with node scripts/pm/dispatch-gates.mjs --repo objectstack-ai/objectstack (27 owed by path + kind). Per-run exit codes captured before any
pipe. Full list of what ran, what was narrowed and what is left to CI is in the report on the
issue.

🤖 Generated with Claude Code

https://claude.ai/code/session_016yfqQh2dBgPAymYd7xipza


Generated by Claude Code

`handleApprovalError`'s `[/^FORBIDDEN/, 403, 'FORBIDDEN']` row is the one
every authorisation refusal rides, and it had no live-emission pin: the
service suites assert the `FORBIDDEN:` message prefix at the throw site,
which is a different fact from what the route answers on the wire.
Adds one `it()` to `rest-approvals-wire-codes.test.ts` driving the real
recall route with a service that throws the real refusal, asserting
status 403, `code === 'FORBIDDEN'`, and that the [#13095] anchored strip
removed the prefix. Losing the row fails closed (500
`APPROVAL_RECALL_FAILED` with the raw message), so the third assertion
catches the strip half of the regression as well as the status half.
Test-only; no production behaviour changed.
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_016yfqQh2dBgPAymYd7xipza
… is false
Measured, not read: deleting `[/^FORBIDDEN/, 403, 'FORBIDDEN']` from
`handleApprovalError` reds THREE cases, not one — this new pin and both
cases of `rest-data-door-code-prefix.test.ts` §7, which already drive the
real approve route and already assert 403, `code: 'FORBIDDEN'` and the
anchored strip.
#14573 was filed and triaged on the reading that the row had no
live-emission pin anywhere. That is wrong. What is true is narrower: the
file that OWNS the approvals wire-code contract did not pin it, so an
audit of wire codes here saw a gap a strip-contract file was silently
covering. Naming §7 from here is half the fix — the unlabelled duplicate
is what got the card mis-filed.
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_016yfqQh2dBgPAymYd7xipza
@os-trumpos-trump added skip-changeset PR has no user-facing published change; bypasses the changeset gate and removed tests labels Sep 3, 2026 — with Claude
@github-actions

github-actionsBot commented Sep 3, 2026

Copy link
Copy Markdown
Contributor

📓 Docs Drift Check

Nothing in this diff resolved to a documentable surface (no symbol, route or SDK anchor derived from 0 changed package(s)), so this run has no opinion about the docs.

What this run could not see
  • a page that states a rule by its inputs shares no identifier with the emitter that implements the rule, so an emitter-only diff cannot list it — not on this run and not on any run. Measured on fix(driver-sql): emit varchar(maxLength) for a text field a declared index keys on #11430: content/docs/protocol/objectql/types.mdx documents the text-family column mapping by the ObjectQL type names it maps FROM (text / textarea / html) while the diff changed createColumn; it went unlisted, and it was the page that diff falsified, in four places. No shared token exists to detect this on, so a rule your change carries has to be re-read by hand in the pages that restate it.

Coarse fallback — 0 page(s) merely mention a changed package (the pre-#9192 predicate, kept for the deliberately-wide backstop): node scripts/docs-audit/affected-docs.mjs --json f116b8f8d1b43ec2bfd64fbf0ebb0cf3c301b1c8packageMentionDocs.

@os-project-manager
os-project-manager added this pull request to the merge queueSep 3, 2026
Any commits made after this event will not be merged.
Sign up for freeto join this conversation on GitHub. Already have an account? Sign in to comment

Labels

size/sskip-changesetPR has no user-facing published change; bypasses the changeset gatetests

Projects

None yet

2 participants

@os-trump@claude