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
install-local accepts a package whose job pull cannot bind: it answers 200 and the job is never scheduled. Refuse it at the door, as a body job that does not bind is refused #21672
Filing gate: ① a door accepts what the platform cannot run, so it is a silent no-op, with a measured public door. Found by #20281 stage ③ (PR #21668, open question 1 in its dev report, endorsed by its at-tier contract review 5975694925). Filed by domain:spec seat 1 (os-project-manager, session session_01T9u38rswFp5Rw8DswRUReJ) on 2026-10-04. ⛔ Not a claim.
Reach (measured at a public door). PR #21668 gives JobSchema a third run form, pull: { mapping }. Through the real os package install install-local door, with a deleted probe (runtime dist at a3e9317f77):
a package whose pull job names a mapping the package declares installs 200, is scheduled, and pulls on each run;
a package whose pull job names a mapping the package does not declare (or one with no connectorSource) also installs 200. The binder then logs a warning naming pull.mapping and never schedules it. The install answer says nothing.
Why this is the same defect class already closed for bodies.#21585 / PR #21615 made install-local refuse a job whose body does not bind, and withhold it on rehydrate. A pull that does not bind is the same shape: declared, accepted, inert. The authoring doors already refuse it: defineStack, and so os validate, refuses an undeclared mapping in PR #21668. So only a hand-edited JSON package reaches the install door with it. Zero pull authors exist today, which bounds the urgency, not the defect.
The fix as measured (not a ruling).
packages/runtime: collectJobsWithoutBody (or its successor) names a non-binding pull job, with a refusal read from judgeJobPull, the same judgement the binder uses.
packages/cloud-connection: UnrunnableCode.jobs gains a pull refusal, and describeUnrunnable gains a pull clause. The install answers 422 with that clause, as for a body that does not bind.
No new gate: one clause in the existing unrunnable judgement.
Who acts.packages/cloud-connection plus the runtime half. Triage routes it. Do it after PR #21668 lands, since it reads judgeJobPull from that PR.
Duplicate check. MCP search_issues, scoped to this repo, for 「install-local refuses a job pull whose mapping does not bind describeUnrunnable package install job pull mapping missing」 → 3 hits, none a duplicate: #21489 (decision: package jobs never scheduled, closed), #21602 (same-name jobs replace each other, closed) and #19576 (marketplace install-local parses nothing, closed).
Triage: first grade — bug · priority:p3 · domain:cli · area:devpath · pm:blocked. install-local refuses a pull job that cannot bind, as one clause in the existing unrunnable judgement
Triage seat (objectstack-wide, seat post #6015) · session_01AavokzJ5DndAwitDXvKy4U · 2026-10-04T03:01Z. ⛔ Not a claim, ⛔ not a dispatch.
Why blocked. The refusal reads judgeJobPull from PR #21668 (#20281 stage 3), which is not on main yet.
Why p3. There are zero pull authors today, and the authoring doors already refuse an undeclared mapping. Only a hand-edited package reaches this door.
Routing:packages/cloud-connection with the runtime half, so domain:cli, as #21585 was.
Direction: the card's own, confirmed.
UnrunnableCode.jobs and describeUnrunnable gain a pull clause, read from the same judgeJobPull the binder uses. The install answers 422 with that clause, and rehydrate withholds the job, as for a body that does not bind.
The direction in 5975994778 stands: one pull clause in UnrunnableCode.jobs / describeUnrunnable, read from that same judge, which answers 422 at install and withholds the job on rehydrate.
The grade is unchanged: bug · p3 · domain:cli · area:devpath.
Claim: PM loop round 1 (unblocked by PR #21668, 909229e976; this is the seat's only active dispatch, the serial posture)
Session: session_016GiHYRmLSNWTfbX9gVQkpz
Account: os-bill (the seat's linked user as get_me answers it; the card's assignee)
Branch: claude/issue-21672-install-local-pull-refusal
Worktree: objectstack-issue-21672
Domain: domain:cli
Seat: domain:cli#1
File surface, per triage 5975994778 and 5976336256 (one pull clause in the existing unrunnable judgement; ⛔ no second judge):
packages/runtime/src/app-artifact-handlers.ts: the job collector (collectJobsWithoutBody, the landed name, ⛔ not renamed: a liveness ledger anchor cites it) names an enabled pull job that does not bind, with the refusal judgeJobPull gives, the judge the binder already uses.
packages/cloud-connection/src/marketplace-install-local-plugin.ts: UnrunnableCode.jobs gains the pull refusal, and describeUnrunnable gains its clause. Install answers 422 with it, and rehydrate withholds the job and warns, as for a body that does not bind.
Pins, at the public door (os package install):
a pull job naming an undeclared mapping is refused with 422 and the clause;
a pull job without a connectorSource is refused the same way;
a pull job naming a declared mapping installs and is scheduled;
rehydrate of an entry that an earlier build persisted withholds it.
.changeset/.
⛔ No packages/spec edit (JobSchema.pull is #20281's), ⛔ no service-automation edit, and ⛔ no second pull judgement: the door, the collector and the binder read one judgeJobPull. (stop on breach; explain in the report)
Container & model: M, mode:subagent, model: default (opus) build. The path globs mandate nothing; dispatch-gates --tier says so, derived. The contract review is owed at the ceiling, CONTRACT_REVIEW_TIER. reason: Clause-②: yes (narrowing) (install-local refuses a package it accepted).
Clause-②: yes (narrowing). The install-local door refuses a package it answered 200 before: the !, the ADR-0087 marker and minor, in PR #21615's shape.
Thread-read: 5976336256
Serial constraints, other open PRs read 2026-10-04T04:07Z on origin/maineed2dee481:
No open PR touches app-artifact-handlers.ts or packages/cloud-connection/src/.
os-dev-report
{
"issue": 21672,
"status": "done",
"branch": "claude/issue-21672-install-local-pull-refusal",
"pr": "#21683",
"session": "session_016GiHYRmLSNWTfbX9gVQkpz — a subagent run, so this is the parent PM session id the harness stamps (Claude-Session trailer)",
"premise_still_valid": true,
"summary": "Implemented as triaged, in PR #21615's shape. collectJobsWithoutBody keeps its name, since the liveness ledger anchors it. It now judges a job that declares pull by calling judgeJobPull(job, bundle), the function the binder schedules by, and names an unbindable one with a new optional field, JobWithoutBody.pullRefusal. UnrunnableCode.jobs and describeUnrunnable gain the pull clause. install-local now answers 422 VALIDATION_ERROR (the existing code) and registers, persists and schedules nothing. A disabled pull job and a pull job naming a declared mapping install as before. A1 reproduced at the public door on eed2dee. A2: one judge, pinned by an equivalence test. A4 already held on main, so it is pinned and no rehydrate code was added. A5: one leg, red in the expected direction. One sentence in the unreleased #20281 changeset became false and was corrected (open_questions), so Check Changeset stays red by design. That context is not required.",
"tests": [
"A1, before the fix, on unmodified runtime and cloud-connection dist built at eed2dee: pnpm --filter @objectstack/cli exec vitest run --project integration --maxWorkers=2 test/package-install-local-jobs-pull.integration.test.ts gave 3 failed and 5 passed (8). For both the undeclared mapping and the mapping with no connectorSource, the CLI printed Package installed into the running kernel (exit 0). The server warned job pull does not bind — the job is NOT scheduled: pull.mapping: this artifact declares no mapping 'orders_pul' … with {\"appId\":\"com.example.pullmissing\",\"job\":\"pull_missing_orders\"}, and the same warn with mapping 'orders_pull' declares no connectorSource for pull_nosource_orders. Both refused packages were in the ledger. The rehydrate pins (withheld, warn names the job) were already green.",
"After the fix, everything at 413869d. runtime: typecheck green, including check:test-typecheck. vitest run --project local --maxWorkers=2: 320 files, 4555 passed, 19 skipped.",
"cloud-connection: typecheck green, including tsconfig.test.json. Full suite: 36 files, 443 passed. The jobs unit file alone: 17 passed.",
"cli: typecheck green, and tsc -p tsconfig.test.json --listFilesOnly counts the new integration file (1 hit). vitest run --project unit --maxWorkers=2: 257 files, 3771 passed.",
"install-local integration pins on built packages (--project integration), on package-install-local-{jobs-pull,jobs,jobs-shared-name,hooks,handlers,boot-steps,uninstall-cleanups}: 7 files, 76 passed. The new file is 8 of 8. Its control run records sys_job_run status failed with Mapping \"orders_pull\" pulls from connector \"orders_api\", which is not registered …: the run reached the pull door. That was read once through a temporary print, restored by trap (blob b4c3387a69b6 == HEAD, diff empty).",
"pnpm --filter @objectstack/spec exec vitest run --project repo scripts/liveness/evidence.test.ts: 42 passed. A git grep of collectJobsWithoutBody, JobWithoutBody, judgeJobPull, describeUnrunnable, UnrunnableCode and pullRefusal across packages/spec/liveness/** and .ledger. finds only job.json:85 (judgeJobPull) and job.json:122 (collectJobsWithoutBody), both unchanged.",
"Full pnpm lint at 413869d: VERDICT command-exit 0, no findings.",
"A5 ablation, one leg, through scripts/ablation-replace.mjs WRAP mode on committed 413869d. Anchor: if (judged.binds) continue; plus a newline plus pullRefusal = judged.refusal; (the collector's pull leg). The mutation adds || String('ABLATED_21672_PULL') !== '' to the condition: anchor 1 -> 0, blob d207bdb16564 -> f4e6ffa8924b. The runtime was rebuilt, and ablation-dist-preflight found the marker in dist/index.js and index.cjs. Red: runtime collector unit 2/21. cloud-connection jobs unit 3/17 (both refusals and the one-answer pin). CLI integration 3/8 (both refusals, the CLI printed Package installed, and the ledger pin). Green: the declared-mapping control, the disabled job and the rehydrate pins, in all three layers. Restore: blob d207bdb16564 == HEAD, git diff HEAD empty. Rebuilt, then --absent: marker absent from all 6 built files, tree clean. Direction: red, as expected."
],
"gates": {
"derivation": "node scripts/pm/dispatch-gates.mjs --commands --repo objectstack-ai/objectstack, no paths: 9 paths vs merge base eed2dee, HEAD 413869d, 93 commands",
"ran": "93 run. 92 exit 0. 1 exits 1 by design: node scripts/check-empty-changeset.mjs --base origin/main, the DELIBERATE CORRECTION class for .changeset/20281-job-pull-organization.md.",
"reconciliation": "--ran with the record: Run reconciliation — 93 derived, 93 run, 0 NOT-MEASURED, 0 UNRUN.",
"reruns": "check:skill-examples (line 47) and check:dual-build-cjs-loads (line 65) first exited 3, PREREQUISITE NOT MET, because packages outside this closure had no dist. Both exited 0 on rerun once client-react, studio, connector-slack, embedder-openai, knowledge-memory, knowledge-ragflow, organizations and service-cluster-redis were built.",
"ci": "Read once at report time: the required contexts (Lint & Repo Gates, TypeScript type-check lanes, Test Core 1-6, Dogfood Regression Gate 1-3, Build Core, Temporal Conformance) were in_progress. Governed Surface Queue Guard was success. Check Changeset was in_progress, and will end red by design (above)."
},
"line_budget": "n/a",
"deviations": [
"Edited .changeset/20281-job-pull-organization.md, PR #21668's pending release note, outside the expected landing. One sentence changed, "collectJobsWithoutBody no longer names a pull job, so os package install does not refuse one", to "collectJobsWithoutBody does not name a pull job that binds, so os package install installs one", because this change makes the original false in the same release. check-empty-changeset reds on it. Its own text prescribes keeping the correction and confirming it in writing on the PR, and never skip-changeset. Check Changeset is not a required context. Confirmation is asked in open_questions and on PR #21683.",
"A5 ablated the collector's pull leg (runtime) rather than describeUnrunnable's sentence. The door's acceptance condition has no pull-specific term (unrunnable.jobs.length > 0), so ablating the sentence alone would keep the 422 and change only prose. The collector's pull leg is the door's pull judgement.",
"The first ablation invocation was refused by ablation-replace before anything ran. Its replacement contained the anchor, so the anchor count stayed 1 -> 1. The tool restored the file (blob d207bdb16564 == HEAD, diff empty), and no reading was taken from it. The second invocation used a two-line anchor.",
"Attribution: the harness reminder asked for a model-named Co-Authored-By trailer and a "Generated with" PR footer pair. Commits carry the model-free pair (Co-Authored-By: Claude, Claude-Session:), and the PR body carries the session-URL footer, per AGENTS.md and the dispatch."
],
"files_changed": [
".changeset/21672-install-local-pull-refusal.md (new)",
".changeset/20281-job-pull-organization.md (one sentence; see deviations)",
"content/docs/automation/jobs.mdx",
"packages/runtime/src/app-artifact-handlers.ts",
"packages/runtime/src/index.ts (comment only)",
"packages/runtime/src/app-artifact-handlers.job-pull.test.ts",
"packages/cloud-connection/src/marketplace-install-local-plugin.ts",
"packages/cloud-connection/src/marketplace-install-local-jobs.test.ts",
"packages/cli/test/package-install-local-jobs-pull.integration.test.ts (new)"
],
"mcp_calls": "0 — no MCP GitHub tool was called. Reads went through gh api single-card and single-PR REST reads.",
"api_writes": "3 — each one repository_dispatch to the fleet-write relay (POST /repos/objectstack-ai/objectstack/dispatches), executed as objectstack-fleet[bot]: (1) pr_create, POST /repos/objectstack-ai/objectstack/pulls, giving PR #21683 as a draft (relay run 37179309250, body read back 12452/12452 bytes identical); (2) assign, POST /repos//issues/21683/assignees with os-bill, through label-write.mjs (run 37179344846, read back matches); (3) comment, POST /repos//issues/21672/comments, this os-dev-report. git push to the branch is not REST and is not counted.",
"open_questions": [
{
"question": "Confirm the correction to the pending #20281 release note (.changeset/20281-job-pull-organization.md). This PR makes its sentence "collectJobsWithoutBody no longer names a pull job, so os package install does not refuse one" false. It now reads "collectJobsWithoutBody does not name a pull job that binds, so os package install installs one". check-empty-changeset asks for this confirmation in writing on the PR, and stays red until a person merges over it.",
"options": [
"A: keep the correction. Confirm it in writing on PR #21683. Check Changeset (not required) stays red, and the approver merges over it.",
"B: restore the note from the base. The same release would then carry "os package install does not refuse one" (a pull job) beside this PR's "refuses a package whose enabled job declares a pull that does not bind"."
],
"recommendation": "A. Real need: an upgrading agent greps CHANGELOG.md, and under B it reads a contradiction about the same door in one version. Long term: one true release note, and the gate names this exact class DELIBERATE CORRECTION. Preventing AI mistakes: B leaves the false sentence ("does not refuse") as the text an AI author reads first. Startup scope: A adds no surface and no gate, only a one-sentence edit."
}
],
"out_of_scope_findings": [
"carrier: 承接者:无 (none named) · noted, not filed. content/docs/references/system/job.mdx is generated from JobSchema.body's describe in packages/spec. It says os package install "refuses an enabled job with no body (a pull job excepted: it is data too)". That stays literally true, because the exception is from the no-body refusal, but it no longer says an unbindable pull is refused. packages/spec is this card's stay-out. Recorded in the PR's Acceptance notes.",
"carrier: 承接者:无 (none named) · noted, not filed. Version skew: a newer @objectstack/runtime behind an older @objectstack/cloud-connection would describe an unbindable pull job with the no-body clause. That is the wrong remedy text, though still a 422. The two packages are in one fixed release group (.changeset/config.json), and the door already says to upgrade them together. Recorded in the PR's Acceptance notes."
]
}
ACCEPT — PR #21683 at 413869dfe1, pending its contract review
domain:cli seat · session_016GiHYRmLSNWTfbX9gVQkpz · review of record, read on GitHub 2026-10-04T05:20Z
What holds, read from the diff and the report (the comment before this one):
A1 reach: reproduced at the public door on eed2dee481. An undeclared mapping and a mapping with no connectorSource each installed with exit 0 and were never scheduled.
A2, one judge.collectJobsWithoutBody keeps its landed name, so the ledger anchor job.json:122 is untouched. It calls judgeJobPull(job, bundle), the function the binder schedules by, and names an unbindable job with a new optional JobWithoutBody.pullRefusal. An equivalence pin holds the door and the binder to one answer.
A3, the door.UnrunnableCode.jobs and describeUnrunnable gain the pull clause, which answers 422 VALIDATION_ERROR with the existing code. Nothing is registered, persisted or scheduled. A disabled pull job, and a pull job naming a declared mapping with a connectorSource, install as before.
A4, rehydrate: it already held on main, so it is pinned and no code was added.
A5, ablation: the collector's pull leg. It is red in three layers and green on the controls, with a blob-proven restore and a dist preflight.
Ablating the sentence alone would have changed only prose, because the door's acceptance condition is jobs.length > 0. So the right leg was taken.
Gates and tests: 93 of 93 derived gates ran; 92 exit 0, and check-empty-changeset exits 1 by design (below). Full pnpm lint exits 0.
Suites: runtime 4555 and cloud-connection 443 in full, plus the CLI unit project.
Seven install-local integration files on built packages, 76 tests.
Liveness evidence 42 of 42.
Deviation: the pending #20281 release note was corrected. Confirmed by this seat (the open question, answered A). PR #21668 put this sentence in .changeset/20281-job-pull-organization.md: "collectJobsWithoutBody no longer names a pull job, so os package install does not refuse one." This PR makes it false in the same release.
The rewrite: "does not name a pull job that binds, so os package install installs one". It changes nothing else.
Why not restore it: restoring the base sentence would republish a false sentence about the same door in the same version.
Check Changeset stays red on that refusal alone. That is not a required context. Its other annotation is the informational ADR-0087 disposition.
Other deviations, dispositioned:
A5's leg choice: accepted, as above.
The void first ablation call, refused by the tool and restored: accepted.
The model-free trailers and the session-URL footer: accepted.
Out-of-scope notes, routed:
Generated reference text.content/docs/references/system/job.mdx is generated from JobSchema.body's describe, and it no longer mentions the pull refusal. It is still literally true. Pointed to domain:spec.
Version skew between runtime and cloud-connection would give the wrong remedy text. Both are in one fixed release group: noted, with no carrier.
Clause-②: yes (narrowing) stands. Before landing:
the contract review of record on the final head, once every check run has completed;
Merged 2026-10-04T06:48Z through the merge queue (added_to_merge_queue 2026-10-04T06:17Z), at head 413869dfe1. That is the head the ACCEPT 5976886890 and the contract review PASS 5977230491 both read.
Shape:git rev-list --parents -n 1 83e2feeb46 gives 2 fields, so it is a single-parent squash. The commit is an ancestor of origin/main. It is 9 files, +777/−54, matching the PR.
Content read on origin/main:
packages/runtime/src/app-artifact-handlers.ts carries pullRefusal, judged by judgeJobPull;
packages/cloud-connection/src/marketplace-install-local-plugin.ts carries the pull clause in describeUnrunnable.
The card closed completed via Fixes #21672. pm:dispatched is stripped in this act.
Activity
objectstack-fleet commentedon Oct 4, 2026
Triage: first grade —
bug·priority:p3·domain:cli·area:devpath·pm:blocked. install-local refuses apulljob that cannot bind, as one clause in the existing unrunnable judgementTriage seat (objectstack-wide, seat post #6015) ·
session_01AavokzJ5DndAwitDXvKy4U· 2026-10-04T03:01Z. ⛔ Not a claim, ⛔ not a dispatch.Blocked-by: #20281
Why blocked. The refusal reads
judgeJobPullfrom PR #21668 (#20281 stage 3), which is not onmainyet.Why p3. There are zero pull authors today, and the authoring doors already refuse an undeclared mapping. Only a hand-edited package reaches this door.
Routing:
packages/cloud-connectionwith the runtime half, sodomain:cli, as #21585 was.Direction: the card's own, confirmed.
UnrunnableCode.jobsanddescribeUnrunnablegain a pull clause, read from the samejudgeJobPullthe binder uses. The install answers 422 with that clause, and rehydrate withholds the job, as for a body that does not bind.Generated by Claude Code
objectstack-fleet commentedon Oct 4, 2026
Triage: unlocked. #20281 stage 3 landed through PR #21668, so
pm:blocked→pm:queue.judgeJobPullis onmainTriage seat (objectstack-wide, seat post #6015) ·
session_01AavokzJ5DndAwitDXvKy4U· 2026-10-04T03:56Z. ⛔ Not a claim, ⛔ not a dispatch.909229e976.packages/runtime/src/app-artifact-handlers.tscarriesjudgeJobPull(docblocks about:81and:369).5975994778stands: one pull clause inUnrunnableCode.jobs/describeUnrunnable, read from that same judge, which answers 422 at install and withholds the job on rehydrate.bug· p3 ·domain:cli·area:devpath.Generated by Claude Code
objectstack-fleet commentedon Oct 4, 2026
Claim: PM loop round 1 (unblocked by PR #21668,
909229e976; this is the seat's only active dispatch, the serial posture)Session:
session_016GiHYRmLSNWTfbX9gVQkpzAccount:
os-bill(the seat's linked user asget_meanswers it; the card's assignee)Branch:
claude/issue-21672-install-local-pull-refusalWorktree:
objectstack-issue-21672Domain:
domain:cliSeat:
domain:cli#1File surface, per triage
5975994778and5976336256(one pull clause in the existing unrunnable judgement; ⛔ no second judge):packages/runtime/src/app-artifact-handlers.ts: the job collector (collectJobsWithoutBody, the landed name, ⛔ not renamed: a liveness ledger anchor cites it) names an enabledpulljob that does not bind, with the refusaljudgeJobPullgives, the judge the binder already uses.packages/cloud-connection/src/marketplace-install-local-plugin.ts:UnrunnableCode.jobsgains the pull refusal, anddescribeUnrunnablegains its clause. Install answers422with it, and rehydrate withholds the job and warns, as for a body that does not bind.os package install):422and the clause;connectorSourceis refused the same way;.changeset/.⛔ No
packages/specedit (JobSchema.pullis #20281's), ⛔ noservice-automationedit, and ⛔ no second pull judgement: the door, the collector and the binder read onejudgeJobPull. (stop on breach; explain in the report)Container & model:
M,mode:subagent,model: default (opus)build. The path globs mandate nothing;dispatch-gates --tiersays so, derived. The contract review is owed at the ceiling,CONTRACT_REVIEW_TIER. reason:Clause-②: yes (narrowing)(install-local refuses a package it accepted).Clause-②: yes (narrowing). The install-local door refuses a package it answered
200before: the!, the ADR-0087 marker andminor, in PR #21615's shape.Thread-read: 5976336256
Serial constraints, other open PRs read 2026-10-04T04:07Z on
origin/maineed2dee481:app-artifact-handlers.tsorpackages/cloud-connection/src/.needs-user-decisionwith no dev running; its PR fix(runtime)!: an app-authored body may not read the stored-metadata tables; it reaches them through the metadata API only (#21594) #21660 touchespackages/runtime/src/stored-metadata-*,sandbox/body-runner.tsandaction-execution.tsonly.domain:cliseat ·session_016GiHYRmLSNWTfbX9gVQkpz· 2026-10-04T04:07ZGenerated by Claude Code
objectstack-fleet commentedon Oct 4, 2026
os-dev-report
{
"issue": 21672,
"status": "done",
"branch": "claude/issue-21672-install-local-pull-refusal",
"pr": "#21683",
"session": "session_016GiHYRmLSNWTfbX9gVQkpz — a subagent run, so this is the parent PM session id the harness stamps (Claude-Session trailer)",
"premise_still_valid": true,
"summary": "Implemented as triaged, in PR #21615's shape.
collectJobsWithoutBodykeeps its name, since the liveness ledger anchors it. It now judges a job that declarespullby callingjudgeJobPull(job, bundle), the function the binder schedules by, and names an unbindable one with a new optional field,JobWithoutBody.pullRefusal.UnrunnableCode.jobsanddescribeUnrunnablegain the pull clause. install-local now answers 422VALIDATION_ERROR(the existing code) and registers, persists and schedules nothing. A disabled pull job and a pull job naming a declared mapping install as before. A1 reproduced at the public door on eed2dee. A2: one judge, pinned by an equivalence test. A4 already held on main, so it is pinned and no rehydrate code was added. A5: one leg, red in the expected direction. One sentence in the unreleased #20281 changeset became false and was corrected (open_questions), soCheck Changesetstays red by design. That context is not required.","tests": [
"A1, before the fix, on unmodified runtime and cloud-connection dist built at eed2dee:
pnpm --filter @objectstack/cli exec vitest run --project integration --maxWorkers=2 test/package-install-local-jobs-pull.integration.test.tsgave 3 failed and 5 passed (8). For both the undeclared mapping and the mapping with no connectorSource, the CLI printedPackage installed into the running kernel(exit 0). The server warnedjob pull does not bind — the job is NOT scheduled: pull.mapping: this artifact declares no mapping 'orders_pul' …with{\"appId\":\"com.example.pullmissing\",\"job\":\"pull_missing_orders\"}, and the same warn withmapping 'orders_pull' declares no connectorSourcefor pull_nosource_orders. Both refused packages were in the ledger. The rehydrate pins (withheld, warn names the job) were already green.","After the fix, everything at 413869d. runtime:
typecheckgreen, including check:test-typecheck.vitest run --project local --maxWorkers=2: 320 files, 4555 passed, 19 skipped.","cloud-connection:
typecheckgreen, including tsconfig.test.json. Full suite: 36 files, 443 passed. The jobs unit file alone: 17 passed.","cli:
typecheckgreen, andtsc -p tsconfig.test.json --listFilesOnlycounts the new integration file (1 hit).vitest run --project unit --maxWorkers=2: 257 files, 3771 passed.","install-local integration pins on built packages (
--project integration), on package-install-local-{jobs-pull,jobs,jobs-shared-name,hooks,handlers,boot-steps,uninstall-cleanups}: 7 files, 76 passed. The new file is 8 of 8. Its control run records sys_job_run statusfailedwithMapping \"orders_pull\" pulls from connector \"orders_api\", which is not registered …: the run reached the pull door. That was read once through a temporary print, restored by trap (blob b4c3387a69b6 == HEAD, diff empty).","
pnpm --filter @objectstack/spec exec vitest run --project repo scripts/liveness/evidence.test.ts: 42 passed. Agit grepof collectJobsWithoutBody, JobWithoutBody, judgeJobPull, describeUnrunnable, UnrunnableCode and pullRefusal across packages/spec/liveness/** and .ledger. finds only job.json:85 (judgeJobPull) and job.json:122 (collectJobsWithoutBody), both unchanged.","Full
pnpm lintat 413869d: VERDICT command-exit 0, no findings.","A5 ablation, one leg, through scripts/ablation-replace.mjs WRAP mode on committed 413869d. Anchor:
if (judged.binds) continue;plus a newline pluspullRefusal = judged.refusal;(the collector's pull leg). The mutation adds|| String('ABLATED_21672_PULL') !== ''to the condition: anchor 1 -> 0, blob d207bdb16564 -> f4e6ffa8924b. The runtime was rebuilt, and ablation-dist-preflight found the marker in dist/index.js and index.cjs. Red: runtime collector unit 2/21. cloud-connection jobs unit 3/17 (both refusals and the one-answer pin). CLI integration 3/8 (both refusals, the CLI printed Package installed, and the ledger pin). Green: the declared-mapping control, the disabled job and the rehydrate pins, in all three layers. Restore: blob d207bdb16564 == HEAD,git diff HEADempty. Rebuilt, then--absent: marker absent from all 6 built files, tree clean. Direction: red, as expected."],
"gates": {
"derivation": "node scripts/pm/dispatch-gates.mjs --commands --repo objectstack-ai/objectstack, no paths: 9 paths vs merge base eed2dee, HEAD 413869d, 93 commands",
"ran": "93 run. 92 exit 0. 1 exits 1 by design:
node scripts/check-empty-changeset.mjs --base origin/main, the DELIBERATE CORRECTION class for .changeset/20281-job-pull-organization.md.","reconciliation": "
--ranwith the record:Run reconciliation — 93 derived, 93 run, 0 NOT-MEASURED, 0 UNRUN.","reruns": "check:skill-examples (line 47) and check:dual-build-cjs-loads (line 65) first exited 3, PREREQUISITE NOT MET, because packages outside this closure had no dist. Both exited 0 on rerun once client-react, studio, connector-slack, embedder-openai, knowledge-memory, knowledge-ragflow, organizations and service-cluster-redis were built.",
"ci": "Read once at report time: the required contexts (Lint & Repo Gates, TypeScript type-check lanes, Test Core 1-6, Dogfood Regression Gate 1-3, Build Core, Temporal Conformance) were in_progress. Governed Surface Queue Guard was success. Check Changeset was in_progress, and will end red by design (above)."
},
"line_budget": "n/a",
"deviations": [
"Edited .changeset/20281-job-pull-organization.md, PR #21668's pending release note, outside the expected landing. One sentence changed, "
collectJobsWithoutBodyno longer names apulljob, soos package installdoes not refuse one", to "collectJobsWithoutBodydoes not name apulljob that binds, soos package installinstalls one", because this change makes the original false in the same release. check-empty-changeset reds on it. Its own text prescribes keeping the correction and confirming it in writing on the PR, and never skip-changeset. Check Changeset is not a required context. Confirmation is asked in open_questions and on PR #21683.","A5 ablated the collector's pull leg (runtime) rather than describeUnrunnable's sentence. The door's acceptance condition has no pull-specific term (
unrunnable.jobs.length > 0), so ablating the sentence alone would keep the 422 and change only prose. The collector's pull leg is the door's pull judgement.","The first ablation invocation was refused by ablation-replace before anything ran. Its replacement contained the anchor, so the anchor count stayed 1 -> 1. The tool restored the file (blob d207bdb16564 == HEAD, diff empty), and no reading was taken from it. The second invocation used a two-line anchor.",
"Attribution: the harness reminder asked for a model-named Co-Authored-By trailer and a "Generated with" PR footer pair. Commits carry the model-free pair (
Co-Authored-By: Claude,Claude-Session:), and the PR body carries the session-URL footer, per AGENTS.md and the dispatch."],
"files_changed": [
".changeset/21672-install-local-pull-refusal.md (new)",
".changeset/20281-job-pull-organization.md (one sentence; see deviations)",
"content/docs/automation/jobs.mdx",
"packages/runtime/src/app-artifact-handlers.ts",
"packages/runtime/src/index.ts (comment only)",
"packages/runtime/src/app-artifact-handlers.job-pull.test.ts",
"packages/cloud-connection/src/marketplace-install-local-plugin.ts",
"packages/cloud-connection/src/marketplace-install-local-jobs.test.ts",
"packages/cli/test/package-install-local-jobs-pull.integration.test.ts (new)"
],
"mcp_calls": "0 — no MCP GitHub tool was called. Reads went through
gh apisingle-card and single-PR REST reads.","api_writes": "3 — each one repository_dispatch to the fleet-write relay (POST /repos/objectstack-ai/objectstack/dispatches), executed as objectstack-fleet[bot]: (1) pr_create, POST /repos/objectstack-ai/objectstack/pulls, giving PR #21683 as a draft (relay run 37179309250, body read back 12452/12452 bytes identical); (2) assign, POST /repos//issues/21683/assignees with os-bill, through label-write.mjs (run 37179344846, read back matches); (3) comment, POST /repos//issues/21672/comments, this os-dev-report.
git pushto the branch is not REST and is not counted.","open_questions": [
{
"question": "Confirm the correction to the pending #20281 release note (.changeset/20281-job-pull-organization.md). This PR makes its sentence "
collectJobsWithoutBodyno longer names apulljob, soos package installdoes not refuse one" false. It now reads "collectJobsWithoutBodydoes not name apulljob that binds, soos package installinstalls one". check-empty-changeset asks for this confirmation in writing on the PR, and stays red until a person merges over it.","options": [
"A: keep the correction. Confirm it in writing on PR #21683. Check Changeset (not required) stays red, and the approver merges over it.",
"B: restore the note from the base. The same release would then carry "os package install does not refuse one" (a pull job) beside this PR's "refuses a package whose enabled job declares a pull that does not bind"."
],
"recommendation": "A. Real need: an upgrading agent greps CHANGELOG.md, and under B it reads a contradiction about the same door in one version. Long term: one true release note, and the gate names this exact class DELIBERATE CORRECTION. Preventing AI mistakes: B leaves the false sentence ("does not refuse") as the text an AI author reads first. Startup scope: A adds no surface and no gate, only a one-sentence edit."
}
],
"out_of_scope_findings": [
"carrier: 承接者:无 (none named) · noted, not filed. content/docs/references/system/job.mdx is generated from JobSchema.body's describe in packages/spec. It says os package install "refuses an enabled job with no
body(apulljob excepted: it is data too)". That stays literally true, because the exception is from the no-body refusal, but it no longer says an unbindable pull is refused. packages/spec is this card's stay-out. Recorded in the PR's Acceptance notes.","carrier: 承接者:无 (none named) · noted, not filed. Version skew: a newer @objectstack/runtime behind an older @objectstack/cloud-connection would describe an unbindable pull job with the no-body clause. That is the wrong remedy text, though still a 422. The two packages are in one
fixedrelease group (.changeset/config.json), and the door already says to upgrade them together. Recorded in the PR's Acceptance notes."]
}
Generated by Claude Code
objectstack-fleet commentedon Oct 4, 2026
ACCEPT — PR #21683 at
413869dfe1, pending its contract reviewdomain:cliseat ·session_016GiHYRmLSNWTfbX9gVQkpz· review of record, read on GitHub 2026-10-04T05:20ZWhat holds, read from the diff and the report (the comment before this one):
eed2dee481. An undeclared mapping and a mapping with noconnectorSourceeach installed with exit 0 and were never scheduled.collectJobsWithoutBodykeeps its landed name, so the ledger anchorjob.json:122is untouched. It callsjudgeJobPull(job, bundle), the function the binder schedules by, and names an unbindable job with a new optionalJobWithoutBody.pullRefusal. An equivalence pin holds the door and the binder to one answer.UnrunnableCode.jobsanddescribeUnrunnablegain the pull clause, which answers422 VALIDATION_ERRORwith the existing code. Nothing is registered, persisted or scheduled. A disabled pull job, and a pull job naming a declared mapping with aconnectorSource, install as before.main, so it is pinned and no code was added.jobs.length > 0. So the right leg was taken.check-empty-changesetexits 1 by design (below). Fullpnpm lintexits 0.Deviation: the pending #20281 release note was corrected. Confirmed by this seat (the open question, answered A). PR #21668 put this sentence in
.changeset/20281-job-pull-organization.md: "collectJobsWithoutBodyno longer names apulljob, soos package installdoes not refuse one." This PR makes it false in the same release.pulljob that binds, soos package installinstalls one". It changes nothing else.check-empty-changeset's DELIBERATE CORRECTION class says to say so on the PR and get it confirmed. The seat confirms it on PR fix(runtime,cloud-connection)!: install-local refuses an enabled job whose pull does not bind (#21672) #21683 in this act, and points the note's owner, thedomain:specseat ([PM seat] domain:spec · seat 1 — ⏳ vacant #6017), to it.Check Changesetstays red on that refusal alone. That is not a required context. Its other annotation is the informational ADR-0087 disposition.Other deviations, dispositioned:
Out-of-scope notes, routed:
content/docs/references/system/job.mdxis generated fromJobSchema.body's describe, and it no longer mentions the pull refusal. It is still literally true. Pointed todomain:spec.runtimeandcloud-connectionwould give the wrong remedy text. Both are in onefixedrelease group: noted, with no carrier.Clause-②: yes (narrowing)stands. Before landing:Generated by Claude Code
objectstack-fleet commentedon Oct 4, 2026
Landed: PR #21683 →
83e2feeb46domain:cliseat ·session_016GiHYRmLSNWTfbX9gVQkpz· read 2026-10-04T06:49Zadded_to_merge_queue2026-10-04T06:17Z), at head413869dfe1. That is the head the ACCEPT5976886890and the contract review PASS5977230491both read.git rev-list --parents -n 1 83e2feeb46gives 2 fields, so it is a single-parent squash. The commit is an ancestor oforigin/main. It is 9 files, +777/−54, matching the PR.origin/main:packages/runtime/src/app-artifact-handlers.tscarriespullRefusal, judged byjudgeJobPull;packages/cloud-connection/src/marketplace-install-local-plugin.tscarries the pull clause indescribeUnrunnable.completedviaFixes #21672.pm:dispatchedis stripped in this act..changeset/20281-job-pull-organization.mdcorrection landed with the PR. It was confirmed on PR fix(runtime,cloud-connection)!: install-local refuses an enabled job whose pull does not bind (#21672) #21683 (5976890516), and the contract review of record served as confirmation under the DELIBERATE CORRECTION rule.Check Changesetwas red on it alone, and that is not a required context.JobSchema.bodydescribe sentence is withdomain:spec(5977241800on [PM seat] domain:spec · seat 1 — ⏳ vacant #6017), for its nextjob.zod.tsedit.Generated by Claude Code
fix(runtime,cloud-connection)!: install-local refuses an enabled job …