Skip to content

finding(forms): the CRM example and the submit route's docstring say the guest_portal profile authorizes an anonymous form submit; measured on 17.7.0, it does not #24130

Closed

Description

@objectstack-fleet

Found by the repo:www.objectos.ai seat (#12224) while staging www.objectos.ai#272, a post on public form intake, on 2026-10-17. Measured on the published @objectstack/cli 17.7.0 against examples/app-crm taken from tag @objectstack/cli@17.7.0. Class b: the comments an AI author reads contradict both the docs and the runtime.

What disagrees

Source What it says
content/docs/ui/public-data-collection.mdx:13 "Declare a public form view; the submit route derives a narrow authorization from that declaration. No guest profile, no broad grant."
packages/rest/src/rest-server.ts:11102-11107 and packages/plugin-security security-plugin.ts:2334-2336 (at the tag) Both agree with the docs: the publicFormGrant works without guest_portal.
examples/app-crm/src/views/lead.view.ts:96-104 (tag; :95-106 on origin/main 570c7a2) "the guest_portal profile (INSERT-only on crm_lead) authorizes the write".
examples/app-crm/src/security/sales-positions.ts:59-66 (tag; :63-73 on main) "Applied to anonymous … visitors who POST the public form".
packages/rest/src/rest-server.ts:10702-10706 (tag; :9066-9071 on main), the route docstring "Security is delegated to the guest_portal permission set … If the deployment hasn't registered a guest_portal profile, the security middleware falls open".

Measured

The seat removed GuestPortalProfile from the CRM's permissions. The build refused with an access-matrix drift, which was accepted with --update-access-matrix, leaving one permission set in the artifact. It then re-ran the same probes. Every answer was identical to the run with the profile in place:

Probe Answer
Clean POST 201
POST smuggling status, owner_id and organization_id 201, with the same stripping
Anonymous list 401
Anonymous read of the created row 401

Why it matters

An agent that copies the CRM example adds a guest_portal profile it does not need. An agent that reads the docstring can conclude that a deployment without the profile "falls open", which is the opposite of what the runtime does.

A stale pointer sits next to it. rest-server.ts:11028-11029 (at the tag) names lead.hook.ts / case.hook.ts in app-crm as the canonical defaults-stamping pattern. Neither file exists at the tag: src/hooks/ holds only opportunity.hook.ts.

Done looks like

  • The example's comments and the route docstring state the mechanism the docs and the runtime implement. The example either drops GuestPortalProfile or says why it keeps it.
  • The stale hook-file pointer is corrected.
  • If guest_portal still has a real role on this path, for example the permissions: ['guest_portal'] the submit context carries, the docs say what that role is.

Related, not duplicated: #22437 (the 201 read-back, closed) and #6920 (section-less forms, closed).


Generated by Claude Code

Activity

  1. objectstack-fleet commented on Oct 17, 2026

    @objectstack-fleet
    ContributorAuthor

    Triage: first grade, priority:p3 · domain:cli · area:api · documentation · pm:queue · triage seat · session_01AavokzJ5DndAwitDXvKy4U · 2026-10-17T03:58Z

    Triage seat (objectstack-wide, seat post #6015). ⛔ Not a claim, ⛔ not a dispatch.

    • Still on the 18 line: measured on 17.7.0, which ships no further release; re-read on origin/main 462d02f00a. The comments are still there: packages/rest/src/form-routes.ts:407, :433 (the lead.hook.ts / case.hook.ts pointer) and :507, packages/rest/src/rest-server.ts:9090–:9095 ("falls open"), and examples/app-crm/src/views/lead.view.ts:102.
    • Why p3: comments and docs only; the runtime is right. The "falls open" sentence is the misleading part an AI author reads, and it goes in the same change.
    • Why domain:cli: packages/rest, and the CRM example exercises that door.

    Generated by Claude Code

  2. objectstack-fleet commented on Oct 18, 2026

    @objectstack-fleet
    ContributorAuthor

    Claim: PM loop round 2 · 2026-10-18T00:19Z
    Session: session_01QyoWKK9RwUNxBxmevy9Neb
    Account: marchtian (the seat's linked user as GET /user answers it; always the card's assignee)
    Branch: claude/issue-24130-guest-portal-form-comments
    Worktree: objectstack-issue-24130
    Domain: domain:cli
    Seat: domain:cli#2 (seat post #22648)
    File surface (read on origin/main 6e43b7bc3; line numbers move; stop on a breach and explain it in the report):


    Generated by Claude Code

  3. objectstack-fleet commented on Oct 18, 2026

    @objectstack-fleet
    ContributorAuthor

    os-dev-report
    {
    "issue": 24130,
    "status": "done",
    "branch": "claude/issue-24130-guest-portal-form-comments",
    "pr": "#24237",
    "session": "session_01QyoWKK9RwUNxBxmevy9Neb — subagent, so the parent's harness-stamped id (the Claude-Session line on every commit)",
    "premise_still_valid": true,
    "summary": "The submit route's docstring (rest-server.ts, the registerFormEndpoints JSDoc only), three form-routes.ts comments, the CRM lead.view.ts web_to_lead comment and the GuestPortalProfile comment now state the measured mechanism. Admission is the declaration-derived publicFormGrant, decided before any permission set resolves; nothing falls open. The guest_portal name on the submit context admits nothing and is read only as the result masker's field permissions and held capabilities when a set of that name is registered; its objects bits are never read there. Neither permissions nor anonymous reaches an object hook. The stale lead.hook.ts / case.hook.ts pointer now names a field defaultValue, a select's default:true option, and app-showcase's StampInquiryDefaultsHook. H3 was measured the other way: GuestPortalProfile is KEPT, because Accepted ADR-0138's fate table names this exact declaration as the reference for the form doors' guest_portal name (fate: keep), and dropping it would need a Tier H ADR edit outside the surface; its comment says why and that it changes nothing on the form path. public-data-collection.mdx gets one paragraph on the name's role. The JSDoc ships in @objectstack/rest dist (.d.ts/.d.cts/.js/.cjs, measured), so a patch changeset, not skip-changeset. No behaviour changes.",
    "tests": "Head c564b0e (main 2bcd406 merged). Package tests: @objectstack/rest vitest run --project local --maxWorkers=2: Test Files 294 passed (294), Tests 6028 passed | 326 skipped (6354), exit 0. rest typecheck (tsc --noEmit && check:test-typecheck): exit 0, 'check:test-typecheck: OK'. @objectstack/example-crm vitest run: Test Files 6 passed (6), Tests 46 passed (46), exit 0. example-crm typecheck: exit 0. CRM objectstack build (in the turbo build): 'Build complete', 'Security: 3 Positions 2 Permissions', no access-matrix drift. Throwaway probes (deleted, never committed). (1) A dogfood bootStack(crmStack) run with and without GuestPortalProfile: clean and forged POST /forms/contact-us/submit both answer 201 {id}; the stored row (system read) has status new, lead_score 0, source web, owner_id null and no forged org; anonymous GET /data/crm_lead and GET /data/crm_lead/ID answer 401; a beforeInsert hook sees session null and user null; the probe asserted both shapes equal, 'Tests 1 passed'. (2) An objectql engine run with the route's context verbatim: hook ctx.session and ctx.user are unset; a positive control with userId/positions/permissions/anonymous reaches the hook as session {userId, positions} and user {id}, never permissions or anonymous; 'Tests 2 passed'. dist measurement: 'admits on that grant alone' appears 1x each in packages/rest/dist index.d.ts, index.d.cts, index.js and index.cjs, and 'falls open with' 0x. Control: the form-routes.ts body comment 'Symmetric with #6601' is in src 1x and dist 0x. No ablation: no tested behaviour changed (comments and docs only).",
    "gates": "Local subset, every exit captured before any pipe. (1) Build: pnpm turbo run build --filter=@objectstack/dogfood --filter=@objectstack/example-crm --concurrency=2 under os-verify-lock: 'Tasks: 66 successful, 66 total', VERDICT command-exit 0, on the final head. (2) Package tests and typechecks above. (3) node scripts/pm/dispatch-gates.mjs --commands --repo objectstack-ai/objectstack at c564b0e derived 93 commands; all 93 exit 0. On the first pass pnpm --filter @objectstack/spec run check:skill-examples and pnpm check:dual-build-cjs-loads exited 3 (PREREQUISITE NOT MET: client-react plus 7 other packages outside this closure unbuilt). I built those 8 (VERDICT command-exit 0) and re-ran both: exit 0 ('263 prose examples type-check across 3 surface(s)'; dual-build provenance line, floors held). --ran: 'Run reconciliation — 93 derived, 93 run, 0 NOT-MEASURED, 0 UNRUN', exit 0. Verdict lines: check:doc-authoring OK; check-issue-citations 'every citation this change adds resolves'; check:nul-bytes OK; check-adr-0087-registration '1 non-breaking changeset(s) seen'; check-empty-changeset OK; check:published-files OK; check:dts-closure '167/167'. Lane blind spot: pnpm exec eslint --no-inline-config over the 4 changed .ts files: exit 0, no output. Not local: test:repo and repo-wide pnpm lint belong to CI. CI on PR 24237 at report time (one read, not awaited): 24 check-runs, 22 in_progress, 1 success, 1 skipped; Governed Surface Queue Guard in_progress; the other required contexts not yet concluded. in_progress is the honest value.",
    "mcp_calls": "0 — no MCP GitHub tool used (reads via gh api REST, writes via the scripts/pm relay)",
    "api_writes": "2 relay strokes, each POST /repos/objectstack-ai/objectstack/dispatches executed by fleet-write.yml as objectstack-fleet[bot]: (1) pr_create, which sent POST /repos/objectstack-ai/objectstack/pulls (draft) and POST /repos//issues/24237/assignees ['marchtian']; run 39085035590 success, body read back identical 10561/10561 bytes; (2) the os-dev-report comment, POST /repos//issues/24130/comments. Plus 4 git pushes (not REST): empty-branch probe, 5fcf6a9, 3a043fe, c564b0e. No labels written: no skip-changeset (a patch changeset is owed), and the dispatch named no labels.",
    "open_questions": [],
    "out_of_scope_findings": [
    "class: b · reach: public door — on c564b0e a real CRM boot answers POST /forms/contact-us/submit identically with and without a guest_portal set, and a hook sees neither the permissions nor the anonymous key (both probes above), against the text · evidence: content/docs/ui/forms.mdx says (about :50) 'The guest_portal permission set + anonymous flag are still attached for back-compat (object hooks that detect a guest via a falsy ctx.user?.id)'; (about :109) 'object hooks that branch on the guest_portal permission'; (about :111) 'When present the set is attached to the anonymous context, so keep it INSERT-only'; (about :250) 'permissions: [guest_portal] is retained for back-compat'. Contract: Accepted ADR-0138's fate row says 'the result masker resolves it where a deployment registers one'. Seam: spec:ExecutionContext.permissions → runtime:security-plugin.ts publicFormGrant branch (admits before resolvePermissionSetsForContext) and engine.ts buildSession/buildUser | consumer: none (no hook can read it). SAME FAMILY as #24130: fold into this card's family, ⛔ not a single-point card. Not edited here because it is outside the claimed file surface, and the in-place condition ③ (no other claim holds the file) cannot be established without a board scan · dedupe words: forms.mdx guest_portal back-compat; guest_portal INSERT-only hook; publicFormGrant docs guest_portal",
    "class: b · reach: same two probes · evidence: skills/objectstack-api/SKILL.md about :87 says the form routes 'run under a synthetic { permissions: [guest_portal], anonymous: true } execution context' and omits publicFormGrant, so an AI reader infers the set authorizes. Same family as #24130; governed surface (skills/, Tier H), so it rides a Tier H carrier · dedupe words: objectstack-api SKILL guest_portal context; skills public form publicFormGrant",
    "carrier: 承接者:无 — examples/app-crm/src/objects/lead.object.ts, the status field comment 'the option default below is only a UI preselect': engine.ts about :7086 applies a select's default:true option on write when no defaultValue is declared, and the CRM probe stored source web with no defaultValue declared. The spec declares only 'Is default option' (field.zod.ts :384), so this is a misleading comment, not a declared-contract violation. Noted in the PR's Acceptance notes, not filed",
    "carrier: 承接者:无 — anonymous: true on the form-submit context (form-routes.ts) has no reader: 0 non-test property reads in packages/ against 1 for the control key publicFormGrant with the same pattern, at 5a9a80b. Dead key, not changed because the card changes no behaviour. Acceptance notes only",
    "carrier: 承接者:无 — docs/adr/0096 census row for rest-server.ts#enforceAuth reads 'fall open when guest_portal unregistered (partly mitigated by the publicFormGrant)': an accepted record's historical census (Tier H). Acceptance notes only"
    ],
    "files_changed": [
    ".changeset/24130-form-submit-docstring.md",
    "content/docs/ui/public-data-collection.mdx",
    "examples/app-crm/src/security/sales-positions.ts",
    "examples/app-crm/src/views/lead.view.ts",
    "packages/rest/src/form-routes.ts",
    "packages/rest/src/rest-server.ts (registerFormEndpoints JSDoc only; the merge from main brought #24223's lines, which are not this diff)"
    ],
    "line_budget": "n/a — skills/
    not touched",
    "deviations": [
    "H3 decided against the PM's preferred drop, with measurement: GuestPortalProfile is kept because Accepted ADR-0138 names it as the reference declaration (fate: keep), and the masker reads the name. security/index.ts, objectstack.config.ts and access-matrix.json are untouched.",
    "Changeset: patch for @objectstack/rest, not skip-changeset — the private method's JSDoc ships in dist .d.ts/.d.cts/.js/.cjs (measured with a control).",
    "Merged origin/main 2bcd406 (PR #24223, rest-server.ts about :3681, no overlap) before opening the PR, per AGENTS.md §10; merge commit c564b0e carries model-free trailers.",
    "Built 8 packages outside the closure (studio, client-react, embedder-openai, knowledge-memory, knowledge-ragflow, organizations, service-cluster-redis, service-knowledge) so two exit-3 gates could measure; both then exited 0.",
    "test:repo (vitest repo project) not run locally; CI's Test Core owns it.",
    "Two throwaway probe tests were created in the worktree and deleted before the final commits; none is committed (dispatch-gates at the final head: untracked 0).",
    "content/docs/ui/forms.mdx carries the same wrong claims but sits outside the claimed surface; reported, not edited.",
    "Conflict noted: the harness system-reminder asked for a model-named Co-Authored-By trailer and a different PR footer; the dispatch and AGENTS.md (model-free trailer pair, session-URL footer) were followed instead, and no model identifier is in any commit, PR, changeset or comment."
    ]
    }


    Generated by Claude Code

  4. objectstack-fleet commented on Oct 18, 2026

    @objectstack-fleet
    ContributorAuthor

    os-dev-report
    {
    "round": "patch round 1",
    "issue": 24130,
    "status": "done",
    "branch": "claude/issue-24130-guest-portal-form-comments",
    "pr": "#24237",
    "head": "91ca7f3b7",
    "session": "session_01QyoWKK9RwUNxBxmevy9Neb — subagent, so the parent's harness-stamped id (the Claude-Session line on every commit)",
    "premise_still_valid": true,
    "summary": "Patch round 1 folds the two seat-named sites into PR 24237, as the revised claim (comment 6243651386, 'Revised 2026-10-18T01:09Z') lists them. content/docs/ui/forms.mdx, the guest_portal passages only: the ADR-0056 callout drops 'back-compat (object hooks that detect a guest …)' and now says neither permissions nor anonymous authorizes anything or reaches an object hook. Section 2 is KEPT, retitled 'No permission set to create — what the guest_portal name does', and rewritten. It says: admission is the publicFormGrant, decided before any set resolves; a registered set's object bits are not read; only its field permissions and held capabilities feed the result masker over the record the route gets back; the visitor gets the id only, so a deployment registers one only to mask fields on that record and nothing else needs it; no hook can read either key, so a public submission is told apart by the missing ctx.user. The INSERT-only os:check snippet is removed (object bits nothing reads). The auth-model bullet drops 'retained for back-compat'. examples/app-crm/src/objects/lead.object.ts, the status comment only: the declared defaultValue 'new' is what the write uses and takes precedence over the default:true option, which engine.ts (about :7086, resolveOptionDefault) falls back to on write only when no defaultValue is declared; the 'only a UI preselect' claim is gone. The PR body gains a 'Patch round 1' section, and the two items left Acceptance notes. The changeset was re-read: it describes only the rest docstring and stays true, unchanged. No behaviour change; packages/spec, skills/** and docs/adr/** untouched.",
    "tests": "Head 91ca7f3. pnpm turbo run build (round-0 closure plus the 8 dist-reading-gate packages) under os-verify-lock: 'Tasks: 74 successful, 74 total', VERDICT command-exit 0. The CRM objectstack build re-ran on the new lead.object.ts: 'Build complete', 'Security: 3 Positions 2 Permissions'. @objectstack/example-crm vitest run --maxWorkers=2: Test Files 6 passed (6), Tests 46 passed (46), exit 0. example-crm typecheck: exit 0. Evidence for the text: round 0's two probes (the CRM boot with and without GuestPortalProfile answered identically, and the hook saw session and user unset; the engine positive control showed permissions and anonymous never reach a hook; the CRM stored source web with no defaultValue declared) and engine.ts about :7086 ('A field that declares NO defaultValue falls back to the option marked default: true'). No ablation: text only.",
    "gates": "On 91ca7f3, every exit captured before any pipe. node scripts/pm/dispatch-gates.mjs --commands --repo objectstack-ai/objectstack derived 93 commands, byte-identical to round 0's list; all 93 exit 0 on the first pass. check:skill-examples reads '262 prose examples type-check' (263 before: the removed snippet); check:doc-anchors reads '536 internal #fragment link(s) … all resolve'. --ran: 'Run reconciliation — 93 derived, 93 run, 0 NOT-MEASURED, 0 UNRUN', exit 0. The derivation warned STALE TREE: 5 commits behind origin/main, and scripts/check-position-name-fold-loaders.mjs changed there (#24236). I also ran main's copy of that script at its own path against this tree, under a trap restore, with the restore proved by blob hash (bd90f10a6 = the HEAD blob; git diff HEAD empty): scan exit 0, --self-test exit 0 (39 cases). (A first attempt from a renamed copy flagged only itself as a loader; discarded as a measurement artifact.) pnpm exec eslint --no-inline-config examples/app-crm/src/objects/lead.object.ts: exit 0, no output. CI on 91ca7f3 at report time (one read): 47 check-runs, 34 success, 7 skipped, 6 in_progress. Required Lint & Repo Gates, TypeScript Type Check, Build Core and Governed Surface Queue Guard: success. Test Core shards 1, 4, 5 and 6 success; shards 2 and 3 in_progress; Check Changeset in_progress.",
    "mcp_calls": "0 — no MCP GitHub tool used",
    "api_writes": "This round: 2 relay strokes, each POST /repos/objectstack-ai/objectstack/dispatches executed as objectstack-fleet[bot]. (1) issue_patch on 24237, body only: PATCH /repos//issues/24237, run 39086694396 success, read back identical 14469/14469 bytes. (2) This os-dev-report comment: POST /repos//issues/24130/comments. Plus 1 git push (not REST): c564b0e..91ca7f3. No labels written; the labels on the PR (documentation, size/m, tooling) are another actor's and were left alone.",
    "open_questions": [],
    "out_of_scope_findings": [
    "carrier: 承接者:无 — content/docs/ui/forms.mdx's error table (about :229) says a 403 PERMISSION_DENIED on submit means 'the resolved profile does not allow create on the target object'. On this path the grant admits the create; the grant branch's 403 comes only from an operation outside the grant or its fail-closed arms. Same family, outside this round's three named passages; in the PR's Acceptance notes",
    "class: b · skills/objectstack-api/SKILL.md about :87 (context shape without publicFormGrant) — unchanged from round 0; the seat files it to its lane, not touched here",
    "carrier: 承接者:无 — anonymous: true has no reader; ADR-0096's census row. Both unchanged from round 0, in Acceptance notes"
    ],
    "files_changed": [
    "content/docs/ui/forms.mdx (the guest_portal passages: the callout at about :50, section 2 at about :105–:130, the auth-model bullet at about :250)",
    "examples/app-crm/src/objects/lead.object.ts (the status field comment only)"
    ],
    "line_budget": "n/a — skills/** not touched",
    "deviations": [
    "origin/main was not merged: it moved 5 commits, none on a file this PR touches (the order's merge condition was not met, and AGENTS.md section 10 limits post-open merges). The one stale derived gate was covered by running main's copy of it against this tree.",
    "Section 2's os:check snippet (an INSERT-only guest_portal set) was removed, not rewritten, because its whole content was object bits nothing reads. The section itself is kept, retitled and rewritten.",
    "The worktree was recreated from origin/claude/issue-24130-guest-portal-form-comments at c564b0e, because round 0 had removed it."
    ]
    }


    Generated by Claude Code

  5. objectstack-fleet commented on Oct 18, 2026

    @objectstack-fleet
    ContributorAuthor

    os-dev-report
    {
    "round": "patch round 2",
    "issue": 24130,
    "status": "done",
    "branch": "claude/issue-24130-guest-portal-form-comments",
    "pr": "#24237",
    "head": "860ca38a9",
    "session": "session_01QyoWKK9RwUNxBxmevy9Neb — subagent, so the parent's harness-stamped id (the Claude-Session line on every commit)",
    "premise_still_valid": true,
    "summary": "Patch round 2 replaces one cell: the 403 PERMISSION_DENIED row of content/docs/ui/forms.mdx's submit error table, per the claim revision 6243651386 ('Revised 2026-10-18T01:33Z … patch round 2'). It used to say 'the resolved profile does not allow create on the target object'. It now says the 403 is never a permission set refusing the create (section 2). It answers when the security layer fails closed (the submission's permission sets cannot be resolved, 'permission subsystem unavailable'; or the target object's security posture cannot be resolved), when a write under the submission's context leaves the grant (e.g. an afterInsert hook writing a different object through ctx.api), or when a code-registered hook throws its own 403 (PermissionDeniedError). A declarative hook's throw answers 400. Every condition was measured through the real route; none was inferred. The PR body gained a 'Patch round 2' section, and the :229 item left Acceptance notes. No other row or passage changed; no behaviour change; packages/spec, skills/** and docs/adr/** untouched; changeset unchanged.",
    "measured_403_conditions": [
    "permission-set resolution throws: 403 PERMISSION_DENIED '[Security] Access denied: permission subsystem unavailable for operation 'insert' on object 'pfx_a'' (fault injected by overriding resolvePermissionSetsForContext on the boot's own SecurityPlugin instance; the server logged the fail-closed line; after restore 201)",
    "object security posture unresolved: 403 PERMISSION_DENIED '[Security] Access denied: the security posture of object 'pfx_a' could not be resolved for operation 'insert' …' (fault injected on getObjectSecurityMeta; after restore 201)",
    "a code-registered beforeInsert hook throws PermissionDeniedError: 403 PERMISSION_DENIED with the hook's message",
    "an afterInsert hook writes a different object through ctx.api, unelevated: 403 PERMISSION_DENIED '[Security] Access denied: public-form grant permits only create/read-back on 'pfx_cross', not 'insert' on 'pfx_other''. The hook's nested write carries the submission's grant context",
    "controls, not 403: baseline submit 201; a code hook throwing a plain Error answers 500 INTERNAL_ERROR; a declarative (sandboxed) hook's throw answers 400 with the hook's message"
    ],
    "tests": "Throwaway dogfood probe (packages/qa/dogfood/test/zz-scratch-issue-24130-r2.dogfood.test.ts, deleted before the commit, never committed). It ran one bootStack boot of a synthetic stack (6 objects, 5 public forms) with security: new SecurityPlugin(appSecurityPluginOptions(stack)), the harness default, and sent 7 cases through the real POST /forms/:slug/submit: 'Tests 8 passed (8)', exit 0. Results are in measured_403_conditions. Build under os-verify-lock: 'Tasks: 74 successful, 74 total', 74 cached, exit 0. No ablation: text only.",
    "gates": "On 860ca38, every exit captured before any pipe. node scripts/pm/dispatch-gates.mjs --commands --repo objectstack-ai/objectstack gave the same 93 commands as round 1, and all 93 exit 0 (no exit-0 log carries a PREREQUISITE line). --ran: 'Run reconciliation — 93 derived, 93 run, 0 NOT-MEASURED, 0 UNRUN', exit 0. check:doc-anchors '536 internal #fragment link(s) … all resolve'; check:doc-authoring OK; check:nul-bytes OK. Stale-tree note as in round 1 (scripts/check-position-name-fold-loaders.mjs changed on main): main's copy, run again at its own path under a trap restore with the restore proved by blob hash (bd90f10a6 = HEAD blob; tree clean after), exits 0 on scan and on --self-test. CI on 860ca38 at report time (one read): 47 check-runs, 33 success, 7 skipped, 7 in_progress. Lint & Repo Gates, TypeScript Type Check, Build Core and Governed Surface Queue Guard: success. Test Core shards 1, 5 and 6 success; shards 2, 3 and 4 in_progress.",
    "mcp_calls": "0 — no MCP GitHub tool used",
    "api_writes": "This round: 2 relay strokes, each POST /repos/objectstack-ai/objectstack/dispatches executed as objectstack-fleet[bot]. (1) issue_patch on 24237, body only: PATCH /repos//issues/24237, run 39088023374 success, read back identical 16617/16617 bytes. (2) This os-dev-report comment: POST /repos//issues/24130/comments. Plus 1 git push (not REST): 91ca7f3..860ca38. No labels written.",
    "open_questions": [],
    "out_of_scope_findings": [
    "carrier: 承接者:无 — measured this round: an afterInsert hook on a public-form object that writes another object through ctx.api (unelevated) is refused 403, because the hook's nested write carries the submission's publicFormGrant. This is the grant's declared narrowness ('create + read-back on THAT object only'), not a defect, and the corrected 403 row now says it. Section 3 of forms.mdx (the hook pattern) does not mention it; noted, not filed",
    "class: b · skills/objectstack-api/SKILL.md about :87 — unchanged; the seat files it to its lane",
    "carrier: 承接者:无 — anonymous: true has no reader; ADR-0096's census row. Unchanged, in Acceptance notes"
    ],
    "files_changed": [
    "content/docs/ui/forms.mdx (the 403 PERMISSION_DENIED row of the submit error table only)"
    ],
    "line_budget": "n/a — skills/** not touched",
    "deviations": [
    "origin/main was not merged: it did not move on forms.mdx (the order's condition).",
    "The probe injected faults by overriding two methods on the boot's own SecurityPlugin instance inside a throwaway test. packages/plugins/plugin-security source was only read, never edited.",
    "The worktree was recreated from origin at 91ca7f3, because round 1 had removed it; it is removed again after this report (clean, pushed, no --force)."
    ]
    }


    Generated by Claude Code

  6. objectstack-fleet commented on Oct 18, 2026

    @objectstack-fleet
    ContributorAuthor

    ACCEPT → PR #24237 comment 6244466396 · domain:cli seat 2 · session session_01QyoWKK9RwUNxBxmevy9Neb · 2026-10-18T01:55Z · after patch rounds 1 and 2; landing waits on every check of head 860ca38a9.


    Generated by Claude Code

  7. objectstack-fleet commented on Oct 18, 2026

    @objectstack-fleet
    ContributorAuthor

    Landed: PR #24237 → 9975c26ae (#24130, Fixes #24130) · domain:cli seat 2 · marchtian · session session_01QyoWKK9RwUNxBxmevy9Neb · 2026-10-18T02:42Z

    Reading Result
    PR #24237 object merged: true, merge commit 9975c26ae, merged 2026-10-18T02:37Z through the merge queue (enqueued 2026-10-18T02:11Z)
    origin/main 9975c26ae is an ancestor of origin/main, with a single parent (squash). The 8 files and +114 / −60 match what was reviewed at 860ca38a9
    queue branch no gh-readonly-queue/main/*pr-24237* head remains

    Generated by Claude Code

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Metadata

Metadata

Assignees

Labels

area:apiThe API a customer can call, and integrations — REST, connectors, webhooks, jobsbugSomething isn't workingdocumentationImprovements or additions to documentationdomain:clipriority:p3

Type

No type

Projects

No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions