You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
{{ message }}
Repository navigation
qa(authz-conformance), docs(api): record that POST /api/v1/keys mints only for a signed-in session, as a matrix row and a one-line docs mention (follow-up to #27536) #27708
Filing gate: ③ a maintainer-directed task. The maintainer, in the PM session session_017xRBcVy4VXmkQjn2MGeaWk on 2026-10-29, said (verbatim): 「其他任务正常提交 issue」. This card carries the two Acceptance-notes follow-ups of PR #27536 (merged), filed as a normal card.
Business reason: since #27536, POST /api/v1/keys mints a key only for a caller admitted by a signed-in session; a request admitted by an API key gets 403 PERMISSION_DENIED. The authz-conformance matrix and the API-key docs do not yet say so. The PR's "Acceptance notes" name both as follow-ups owed by the dispatching seat, and the seat's ACCEPT (comment 6502597025) says: "Two Acceptance-notes follow-ups (an authz-conformance matrix row and a docs one-liner) stay with the dispatching seat, per the notes." Without them, a script author reading the docs learns of the rule only from the 403.
Reader: the dev who takes this card from the queue (packages/qa/dogfood and content/docs).
Dedupe: searched the open and closed issues (GitHub issue search scoped to objectstack-ai/objectstack) for "api keys mint session required authz-conformance matrix docs" (4 hits) and "POST /api/v1/keys API key cannot mint another key session only docs" (8 hits). None covers either item.
What to change
1. Authz-conformance matrix row
The PR's Acceptance note: "packages/qa/dogfood/test/authz-conformance.matrix.ts: the anonymous-deny-keys row's note says "a signed-in caller reaches the mint exactly as before", which is still true for a session. This PR adds no row for the session requirement (outside this dispatch's file surface)."
At origin/maina75ddba1:
packages/qa/dogfood/test/authz-conformance.matrix.ts:336–339: the anonymous-deny-keys row. Its enforcement ends "and a signed-in caller reaches the mint exactly as before".
packages/runtime/src/domains/keys.ts:140–146: the session check, context.admission?.credential !== 'session' refused, after the anonymous decision and before the body is read.
The ask: add one row beside anonymous-deny-keys for the session-required rule (state enforced, enforcement naming keys.ts and the positive credential === 'session' check, covers and note in the matrix's own conventions, note naming the pin file). Change the anonymous-deny-keys row's "a signed-in caller" to "a session-admitted caller", so the two rows agree.
2. Docs one-liner
The PR's Acceptance note: "The docs that teach minting (content/docs/api/index.mdx, content/docs/ai/connect-mcp.mdx, content/docs/api/client-sdk.mdx) already show session-based minting. None of them says a key cannot mint. A one-line mention there is a follow-up."
At origin/maina75ddba1, the page that should carry it is content/docs/api/index.mdx:68, the API key bullet ("mint one with POST /api/v1/keys (the key is shown once), or from the Connect an Agent page …"). Add one sentence there: minting needs a signed-in session, and a request authenticated with an API key is refused 403 PERMISSION_DENIED. If the same sentence also fits under "Or mint one over REST:" at content/docs/ai/connect-mcp.mdx:121, add it there too. client-sdk.mdx:176 is a table row and needs no change.
Out of scope: any runtime change, which shipped in #27536.
Read fresh. Both surfaces are the devx lane: packages/qa/dogfood and content/docs. The matrix gets a row for the session-only mint (an API-key caller gets 403 PERMISSION_DENIED), and the API-key docs get one line naming the rule. No behaviour change.
Claim: PM loop round 8 · 2026-10-29T20:01Z
Session: session_01QSeKYmTYfaPbLQD4BJfomW (mode:subagent: the dev shares this session ID; its identity is the branch)
Account: os-justin (the seat's linked user, as GET /user answers it; the card's assignee)
Branch: claude/issue-27708-keys-session-mint-docs
Worktree: objectstack-issue-27708
Domain: domain:devx
Seat: domain:devx#2
File surface: packages/qa/dogfood/test/authz-conformance.matrix.ts (one new row beside anonymous-deny-keys, plus the "signed-in caller" → "session-admitted caller" wording in that row); content/docs/api/index.mdx (one sentence on the API key bullet, ~L68); optionally content/docs/ai/connect-mcp.mdx (one sentence under "Or mint one over REST:", ~L121), plus whatever the derived gates force (e.g. a matrix count pin). No runtime change (stop on breach; explain in the report)
Container & model: S, mode:subagent, model: default, effort: medium
Clause-②: no
Metadata-protocol: none
Responsibility: n/a — not a defect card (records a shipped rule from #27536)
Thread-read: 6506874880
Premise: holds at origin/main e35db835b4. keys.ts:146 refuses context.admission?.credential !== 'session'. The anonymous-deny-keys row (matrix L336–337) still says "a signed-in caller reaches the mint exactly as before". content/docs/api/index.mdx:68 and connect-mcp.mdx:121 carry no session rule.
Serial constraints cleared: open PR #27649 touches content/docs/ai/connect-mcp.mdx, but only at its L242 and L392 hunks. This card's optional edit is near L121, so there is no line overlap, and whoever lands second merges main. No open PR touches the matrix file or content/docs/api/index.mdx.
Dispatched under claim 6507004606 · 2026-10-29T20:01Z: an os-dev subagent (mode:subagent, default tier, effort medium) on branch claude/issue-27708-keys-session-mint-docs. The order:
write the new matrix row from keys.ts and its pin, not from the card text;
find every reader of the matrix and update what pins it;
{
"issue": 27708,
"status": "done",
"branch": "claude/issue-27708-keys-session-mint-docs",
"pr": "https://github.com/objectstack-ai/objectstack/pull/27718",
"session": "session_01QSeKYmTYfaPbLQD4BJfomW",
"premise_still_valid": true,
"summary": "Added the authz-conformance matrix row keys-mint-session-required (state enforced, no covers, note naming the 14-case pin). The anonymous-deny-keys row now says 'a session-admitted caller' and points to the new row. The docblock covers census (stale at base) was corrected to the measured figures. One sentence names the session-only mint rule and the 403 PERMISSION_DENIED in content/docs/api/index.mdx (API key bullet) and in content/docs/ai/connect-mcp.mdx (under 'Or mint one over REST'). There is no runtime change. H1 HOLDS, read at base 2140821ea6: packages/runtime/src/domains/keys.ts L146 `if (context.admission?.credential !== 'session')` answers deps.error(KEYS_SESSION_REQUIRED_MESSAGE, 403) (code derived as PERMISSION_DENIED). It sits below the anonymous decision at L129 and above readDispatchedBody and the method check. The pin keys-mint-interactive-session.pin.test.ts has 14 cases (1 mint + 3 header spellings + 1 key-beside-cookie + 1 session wrong-verb 405 + 1 anonymous 401 + 4 verbs under a key + 3 handler-level), measured at 14/14 pass. The row's enforcement is written from that code. H2: two files read the matrix. authz-conformance.test.ts imports AUTHZ_CONFORMANCE, and authz-probe-blind-spot.test.ts reads the matrix text at L160. Both were run: 2 files, 70/70 pass. No count or snapshot pins the row set: the #17111 docblock pin reads only the two ledger group counts, and a ruling explicitly forbids stated row counts there. The docblock's unpinned covers census ('49 of 67', '43 of 60') was already one row stale at base (measured 68 rows / 50 no-covers / 61 enforced / 44 enforced-no-covers). It was corrected to 69/51/62/45. The new row deliberately carries no `covers`: a key that no discover() probe mints fails as STALE, and the matrix's convention for a predicate inside an already-classified domain is no covers. H3 HOLDS: index.mdx L68 bullet gets the sentence, and connect-mcp.mdx L121 reads naturally, so it gets one too. Its hunk is L121-122, disjoint from #27649's L242/L392.",
"tests": "At head 2ba6263244: `pnpm --filter @objectstack/dogfood exec vitest run --maxWorkers=2 test/authz-conformance.test.ts test/authz-probe-blind-spot.test.ts` gives Test Files 2 passed (2), Tests 70 passed (70), lock VERDICT command-exit 0. `pnpm --filter @objectstack/runtime exec vitest run --maxWorkers=2 src/domains/keys-mint-interactive-session.pin.test.ts` gives Test Files 1 passed (1), Tests 14 passed (14). `pnpm --filter @objectstack/dogfood run typecheck` exits 0, and `tsc --listFiles` holds 409 dogfood/test files including authz-conformance.matrix.ts. No ablation was run: data rows and prose only, no tested behaviour changed. test:repo is declared to CI (Test Core).",
"gates": "`node scripts/pm/dispatch-gates.mjs --commands --repo objectstack-ai/objectstack` exits 0: 71 commands over 3 paths at 2ba6263244. Each was run with its exit code recorded before any pipe, then reconciled: `--ran` exits 0, '71 derived famil(ies) accounted for — 70 run, 1 NOT-MEASURED (1 DERIVED from a recorded exit 3)'. NOT MEASURED: `pnpm check:dual-build-cjs-loads`, exit 3 PREREQUISITE NOT MET (no dist for studio, embedder-openai, knowledge-memory, knowledge-ragflow, service-cluster-redis, service-knowledge; outside this diff's closure). `pnpm --filter @objectstack/spec run check:skill-examples` exited 3 before client-react was built and 0 after. Builds: `pnpm --workspace-concurrency=2 --filter '@objectstack/dogfood^...' build` VERDICT command-exit 0; `--filter '@objectstack/client-react...' build` VERDICT command-exit 0. `--ran` warned that the tree was 11 commits behind origin/main, with stale input scripts/pm/check-skill-line-ratchet.mjs, which no derived family runs. CI check-runs: in_progress at report time, not awaited.",
"dogfood_battery": "n/a — no `!` in the PR title and no (narrowing) arm",
"mcp_calls": "0",
"api_writes": "3 — relay repository_dispatch for pr_create, executing POST /repos/objectstack-ai/objectstack/pulls (draft) and POST /repos/objectstack-ai/objectstack/issues/27718/labels [skip-changeset]; plus POST /repos/objectstack-ai/objectstack/issues/27708/comments (this report). git push x2 are not REST writes.",
"line_budget": "n/a — no skills/** touched; 16 changed lines (+11/-5, 3 files) vs the 3000 human-merge threshold",
"files_changed": ["packages/qa/dogfood/test/authz-conformance.matrix.ts", "content/docs/api/index.mdx", "content/docs/ai/connect-mcp.mdx"],
"deviations": [
"PR opened with no assignees, as the dispatch and the relay's pr_create note direct. os-dev.md says to set assignees to the card's login. The dispatch was followed, and the conflict is noted here.",
"The commit carries AGENTS.md's model-free trailer pair, and the PR body ends with the AGENTS.md session-URL footer, not the harness reminder's model-named Co-Authored-By trailer and footer.",
"Docblock covers census figures in the matrix were edited (outside the literal row ask, same file): stale at base, moved again by the new row, corrected to measured values.",
"One bare `tsc --listFiles` was run outside the lock without NODE_OPTIONS. It hit OOM (SIGABRT) and was re-run under the lock with a 4096 MB heap.",
"origin/main is 11+ commits ahead. No merge was done: no conflict, and the derivation input that moved does not feed this diff's families."
],
"open_questions": [],
"out_of_scope_findings": ["carrier: none · noted, not filed — the matrix docblock covers census is unpinned hand-typed prose that went one row stale before this PR (corrected here); recorded in the PR's Acceptance notes"]
}
Landed: PR #27718, merged as d93d9be598 · 2026-10-29T21:12Z
The merged diff matches the reviewed head 2ba6263244: the sorted +/− lines are hash-identical. ACCEPT → PR #27718 comment 6508069578. Fixes #27708 closed the card, and pm:dispatched is removed in this act. The dev ran as mode:subagent, so there is no cloud session to archive.
Activity
objectstack-fleet commentedon Oct 29, 2026
triage#1 · os-zhuang · session_01AavokzJ5DndAwitDXvKy4U
Path: 真挡得住的权限 | none | P②
Triage: p2 ·
domain:devx·area:auth· 2026-10-29T19:54Z⛔ Not a claim.
packages/qa/dogfoodandcontent/docs. The matrix gets a row for the session-only mint (an API-key caller gets 403PERMISSION_DENIED), and the API-key docs get one line naming the rule. No behaviour change.tests,pm:queue.Generated by Claude Code
objectstack-fleet commentedon Oct 29, 2026
domain:devx#2 · os-justin · session_01QSeKYmTYfaPbLQD4BJfomW
Claim: PM loop round 8 · 2026-10-29T20:01Z
Session:
session_01QSeKYmTYfaPbLQD4BJfomW(mode:subagent: the dev shares this session ID; its identity is the branch)Account:
os-justin(the seat's linked user, asGET /useranswers it; the card's assignee)Branch:
claude/issue-27708-keys-session-mint-docsWorktree:
objectstack-issue-27708Domain:
domain:devxSeat:
domain:devx#2File surface:
packages/qa/dogfood/test/authz-conformance.matrix.ts(one new row besideanonymous-deny-keys, plus the "signed-in caller" → "session-admitted caller" wording in that row);content/docs/api/index.mdx(one sentence on the API key bullet, ~L68); optionallycontent/docs/ai/connect-mcp.mdx(one sentence under "Or mint one over REST:", ~L121), plus whatever the derived gates force (e.g. a matrix count pin). No runtime change (stop on breach; explain in the report)Container & model:
S,mode:subagent,model: default,effort: mediumClause-②: no
Metadata-protocol: none
Responsibility: n/a — not a defect card (records a shipped rule from #27536)
Thread-read: 6506874880
Premise: holds at origin/main
e35db835b4.keys.ts:146refusescontext.admission?.credential !== 'session'. Theanonymous-deny-keysrow (matrix L336–337) still says "a signed-in caller reaches the mint exactly as before".content/docs/api/index.mdx:68andconnect-mcp.mdx:121carry no session rule.Serial constraints cleared: open PR #27649 touches
content/docs/ai/connect-mcp.mdx, but only at its L242 and L392 hunks. This card's optional edit is near L121, so there is no line overlap, and whoever lands second mergesmain. No open PR touches the matrix file orcontent/docs/api/index.mdx.Generated by Claude Code
objectstack-fleet commentedon Oct 29, 2026
domain:devx#2 · os-justin · session_01QSeKYmTYfaPbLQD4BJfomW
Dispatched under claim 6507004606 · 2026-10-29T20:01Z: an
os-devsubagent (mode:subagent, default tier, effort medium) on branchclaude/issue-27708-keys-session-mint-docs. The order:keys.tsand its pin, not from the card text;content/docs/api/index.mdx(theconnect-mcp.mdxsentence is optional and does not overlap open PR fix(runtime)!: a same-origintype: 'api'action is dispatched through the action doors, so its packaged-action switch holds (#27506) #27649's hunks).The report comes back here as
os-dev-report.Generated by Claude Code
objectstack-fleet commentedon Oct 29, 2026
domain:devx#2 · os-justin · session_01QSeKYmTYfaPbLQD4BJfomW
os-dev-report
{ "issue": 27708, "status": "done", "branch": "claude/issue-27708-keys-session-mint-docs", "pr": "https://github.com/objectstack-ai/objectstack/pull/27718", "session": "session_01QSeKYmTYfaPbLQD4BJfomW", "premise_still_valid": true, "summary": "Added the authz-conformance matrix row keys-mint-session-required (state enforced, no covers, note naming the 14-case pin). The anonymous-deny-keys row now says 'a session-admitted caller' and points to the new row. The docblock covers census (stale at base) was corrected to the measured figures. One sentence names the session-only mint rule and the 403 PERMISSION_DENIED in content/docs/api/index.mdx (API key bullet) and in content/docs/ai/connect-mcp.mdx (under 'Or mint one over REST'). There is no runtime change. H1 HOLDS, read at base 2140821ea6: packages/runtime/src/domains/keys.ts L146 `if (context.admission?.credential !== 'session')` answers deps.error(KEYS_SESSION_REQUIRED_MESSAGE, 403) (code derived as PERMISSION_DENIED). It sits below the anonymous decision at L129 and above readDispatchedBody and the method check. The pin keys-mint-interactive-session.pin.test.ts has 14 cases (1 mint + 3 header spellings + 1 key-beside-cookie + 1 session wrong-verb 405 + 1 anonymous 401 + 4 verbs under a key + 3 handler-level), measured at 14/14 pass. The row's enforcement is written from that code. H2: two files read the matrix. authz-conformance.test.ts imports AUTHZ_CONFORMANCE, and authz-probe-blind-spot.test.ts reads the matrix text at L160. Both were run: 2 files, 70/70 pass. No count or snapshot pins the row set: the #17111 docblock pin reads only the two ledger group counts, and a ruling explicitly forbids stated row counts there. The docblock's unpinned covers census ('49 of 67', '43 of 60') was already one row stale at base (measured 68 rows / 50 no-covers / 61 enforced / 44 enforced-no-covers). It was corrected to 69/51/62/45. The new row deliberately carries no `covers`: a key that no discover() probe mints fails as STALE, and the matrix's convention for a predicate inside an already-classified domain is no covers. H3 HOLDS: index.mdx L68 bullet gets the sentence, and connect-mcp.mdx L121 reads naturally, so it gets one too. Its hunk is L121-122, disjoint from #27649's L242/L392.", "tests": "At head 2ba6263244: `pnpm --filter @objectstack/dogfood exec vitest run --maxWorkers=2 test/authz-conformance.test.ts test/authz-probe-blind-spot.test.ts` gives Test Files 2 passed (2), Tests 70 passed (70), lock VERDICT command-exit 0. `pnpm --filter @objectstack/runtime exec vitest run --maxWorkers=2 src/domains/keys-mint-interactive-session.pin.test.ts` gives Test Files 1 passed (1), Tests 14 passed (14). `pnpm --filter @objectstack/dogfood run typecheck` exits 0, and `tsc --listFiles` holds 409 dogfood/test files including authz-conformance.matrix.ts. No ablation was run: data rows and prose only, no tested behaviour changed. test:repo is declared to CI (Test Core).", "gates": "`node scripts/pm/dispatch-gates.mjs --commands --repo objectstack-ai/objectstack` exits 0: 71 commands over 3 paths at 2ba6263244. Each was run with its exit code recorded before any pipe, then reconciled: `--ran` exits 0, '71 derived famil(ies) accounted for — 70 run, 1 NOT-MEASURED (1 DERIVED from a recorded exit 3)'. NOT MEASURED: `pnpm check:dual-build-cjs-loads`, exit 3 PREREQUISITE NOT MET (no dist for studio, embedder-openai, knowledge-memory, knowledge-ragflow, service-cluster-redis, service-knowledge; outside this diff's closure). `pnpm --filter @objectstack/spec run check:skill-examples` exited 3 before client-react was built and 0 after. Builds: `pnpm --workspace-concurrency=2 --filter '@objectstack/dogfood^...' build` VERDICT command-exit 0; `--filter '@objectstack/client-react...' build` VERDICT command-exit 0. `--ran` warned that the tree was 11 commits behind origin/main, with stale input scripts/pm/check-skill-line-ratchet.mjs, which no derived family runs. CI check-runs: in_progress at report time, not awaited.", "dogfood_battery": "n/a — no `!` in the PR title and no (narrowing) arm", "mcp_calls": "0", "api_writes": "3 — relay repository_dispatch for pr_create, executing POST /repos/objectstack-ai/objectstack/pulls (draft) and POST /repos/objectstack-ai/objectstack/issues/27718/labels [skip-changeset]; plus POST /repos/objectstack-ai/objectstack/issues/27708/comments (this report). git push x2 are not REST writes.", "line_budget": "n/a — no skills/** touched; 16 changed lines (+11/-5, 3 files) vs the 3000 human-merge threshold", "files_changed": ["packages/qa/dogfood/test/authz-conformance.matrix.ts", "content/docs/api/index.mdx", "content/docs/ai/connect-mcp.mdx"], "deviations": [ "PR opened with no assignees, as the dispatch and the relay's pr_create note direct. os-dev.md says to set assignees to the card's login. The dispatch was followed, and the conflict is noted here.", "The commit carries AGENTS.md's model-free trailer pair, and the PR body ends with the AGENTS.md session-URL footer, not the harness reminder's model-named Co-Authored-By trailer and footer.", "Docblock covers census figures in the matrix were edited (outside the literal row ask, same file): stale at base, moved again by the new row, corrected to measured values.", "One bare `tsc --listFiles` was run outside the lock without NODE_OPTIONS. It hit OOM (SIGABRT) and was re-run under the lock with a 4096 MB heap.", "origin/main is 11+ commits ahead. No merge was done: no conflict, and the derivation input that moved does not feed this diff's families." ], "open_questions": [], "out_of_scope_findings": ["carrier: none · noted, not filed — the matrix docblock covers census is unpinned hand-typed prose that went one row stale before this PR (corrected here); recorded in the PR's Acceptance notes"] }Generated by Claude Code
objectstack-fleet commentedon Oct 29, 2026
domain:devx#2 · os-justin · session_01QSeKYmTYfaPbLQD4BJfomW
ACCEPT → PR #27718 comment 6508069578 · 2026-10-29T20:54Z · ready + auto-merge armed.
Generated by Claude Code
objectstack-fleet commentedon Oct 29, 2026
domain:devx#2 · os-justin · session_01QSeKYmTYfaPbLQD4BJfomW
Landed: PR #27718, merged as
d93d9be598· 2026-10-29T21:12ZThe merged diff matches the reviewed head
2ba6263244: the sorted +/− lines are hash-identical. ACCEPT → PR #27718 comment 6508069578.Fixes #27708closed the card, andpm:dispatchedis removed in this act. The dev ran asmode:subagent, so there is no cloud session to archive.Generated by Claude Code