Skip to content

test(schedules): pin the row a copy writes against the dsh-schedule task type (#1320) - #1349

Merged
Birfy merged 2 commits into
mainfrom
dev3/1320-copyrow-row-type
Oct 27, 2026
Merged

Birfy merged 2 commits into
mainfrom
dev3/1320-copyrow-row-type

Conversation

@Birfy

@Birfy Birfy commented Oct 27, 2026 •

Copy link
Copy Markdown
Collaborator

Written-by: Dev3
Owner: Dev3
Reviewer: Reviewer2
Tip SHA: 5522794

Fixes #1320

Reproduce

copyRow (core/src/host/schedules.js:368-376) does not copy a row it holds: it builds one at :374 — { sessionId, record: { ...source.record, id }, status, deliveryHistory } — and puts it through a private @deepseek-ai/dsh-schedule API. The test fake accepts whatever literal it is handed, so a required key that moves upstream would not fail a rename or a copy; it would fail silently at runtime. The upgrade note above moveSchedules names the private calls to re-check but not the row keys a copy must supply, which is exactly the gap the PASS on #1307 described and #1320 tracks (option 1 of the issue: assert against the pinned package's row type).

What changed

  • core/test/schedules.test.js: one case, #1320: the row a copy writes matches the pinned dsh-schedule task type. It creates a schedule, swaps the fake's source record for a real createEveryScheduleRecord(...) from @deepseek-ai/dsh-schedule (the fake keeps a timing field no stored record has), copies it to another Bot, then asserts scheduleDomain.tables.tasks.valueSchema.safeParse(row).success for the row the copy wrote, pins the keys it supplies (deliveryHistory, record, sessionId, status), and pins that its record differs from the source's only in id. The pinned version is written in the comment: @deepseek-ai/dsh-schedule@0.2.0-rc.2.
  • patches/ds-bot/0001-core-fixes.patch regenerated with node scripts/ds-bot-patches.mjs generate; it carries only this test hunk (plus the hunk's line count). No product code changed, as the issue's scope allows.

What I ran

  • node --test test/schedules.test.js in core/ → # tests 29 / # pass 29 / # fail 0
  • node scripts/ds-bot-patches.mjs check → three ok lines: pin Fei2411/DeepSeek-Bot@2b10c70 (tree 5834c00, v0.1.5), 10 patches apply cleanly in order, core/ equals ds-bot/ + patches/ds-bot/
  • node scripts/build-client.mjs --check → exit 0
  • npm run lint → 70 warnings, 0 errors (same as base; arch-docs reports "cannot diff against origin/main" locally only, no origin remote in this checkout)

Red without the source change

This is a test-only issue: zero source changes here — the knife is a temporary source edit, measured on this tip and then reverted.

Knife: in core/src/host/schedules.js:374, make the written row carry a key the pinned type does not have — record: { ...source.record, id, timing: {} } — then run the file:

not ok 13 - \#1320: the row a copy writes matches the pinned dsh-schedule task type
  expected: true
# tests 29
# pass 28
# fail 1

One failure and it is the new case: the field-level assertions of #1287/#1319 do not see the extra key, only the strict valueSchema does. Restored (cmp against the saved copy: identical, and git status shows only the test file), the file is back to # tests 29 / # pass 29 / # fail 0.

Not run

  • The whole core/ suite locally: CI tests-ok runs it at this tip, and the diff is one test file plus its generated mirror.
  • The browser/smoke suites: no index.js, client or src/host/ behaviour change.

Risk

Test-only: no runtime behaviour moves, and the generated patch only mirrors the test file. The case pins a current contract (the row shape copyRow supplies today) against a pinned package version — when the package moves, this case fails first, which is the point; a deliberate row-shape change must update it together with the moveSchedules upgrade note.

Checkpoint

{
"pr": 1349, "claim": "Dev3", "issue": 1320,
"summary": "Adds one case that decodes the row copyRow writes against the pinned @deepseek-ai/dsh-schedule@0.2.0-rc.2 task type instead of trusting the fake service. It swaps the fake's source record for a real createEveryScheduleRecord one, copies it to another Bot, and asserts the written row satisfies tasks.valueSchema. It also pins the keys a copy supplies and that the copied record differs from the source only in id. No product code changes; the assertion covers the row as it is written today.",
"files": ["core/test/schedules.test.js", "patches/ds-bot/0001-core-fixes.patch"],
"checks": { "ran": "node scripts/ds-bot-patches check; node --test test/schedules.test.js", "result": "green", "at": "55227943da9ed2eb01a503defc79e870ac22b2ea" },
"next": "none — ready for review"
}

…ask type (#1320)

`copyRow` builds the stored task row itself instead of copying one it holds.
The fake service accepts whatever literal it is handed, so a required key added
upstream would fail silently at runtime. Decode the row it writes against the
pinned `@deepseek-ai/dsh-schedule@0.2.0-rc.2` `tasks.valueSchema`, and pin the
keys it supplies, so that drift fails here instead.

No source change: the assertion covers the row as `copyRow` already writes it.
@Birfy Birfy added the agent-pr Pull request opened by an agent label Oct 27, 2026
@Birfy Birfy self-assigned this Oct 27, 2026
The first push reached enqueue-guard before the body was corrected, and a pull
request body edit does not re-trigger that workflow: only [opened,
synchronize, reopened, labeled, unlabeled, ready_for_review] do. Same tree, new
tip, so the guard judges a body whose checkpoint names this head.
@Birfy
Birfy added this pull request to the merge queue Oct 27, 2026
Merged via the queue into main with commit 67c9c18 Oct 27, 2026
12 checks passed
@Birfy
Birfy deleted the dev3/1320-copyrow-row-type branch October 27, 2026 05:52
HugoXK pushed a commit to HugoXK/FlyBot that referenced this pull request Oct 27, 2026
…hinkFlowLab#1348 prose (ThinkFlowLab#1350) (ThinkFlowLab#1352)

Owner: Dev
Reviewer: Reviewer
Fixes ThinkFlowLab#1350
Fixes ThinkFlowLab#1354
Tip SHA: a09f330

**Executor decision B: remove the frozen-branch seal whole, and keep
what `ThinkFlowLab#1350` asked for that is not about the seal.** `ThinkFlowLab#1354`'s repair —
read the list from `main`, list `ThinkFlowLab#1328`'s number in code — is on this
branch's earlier commits and is now moot: with no seal there is nothing
to read and no number to list.

## Reproduce

**The seal could not hold.** `ThinkFlowLab#1328` (branch
`dev4/1265-step2-one-board`, base `8d0a99c1`) entered the queue at
`06:01:1xZ`, was turned draft, and merged at `06:03:21Z` — the seal
never answered it: the base read found no document, and its branch
matched no listed prefix. `ThinkFlowLab#1350`/`ThinkFlowLab#1354` patched the reading so the
next such pull request would be refused. The owner then decided the
mechanism goes instead of being patched: the cost of the seal (a
queue-entry stop re-read on every `labeled` event, a policy document no
pull request may edit, a number list that had to live in code) was not
worth what it caught, and it never was a permission boundary — a direct
push, an admin merge or a renamed branch walked past it.

**The check that judges this pull request is `main`'s copy, and that
copy still carries the seal.** That is why the document is not deleted
here. The first push of this change (`8f97e4f5`) deleted
`.github/agent/frozen-branches.json` along with the code; the check run
at that head answered `do not enqueue ThinkFlowLab#1352: frozen:
.github/agent/frozen-branches.json is not editable by a pull request`.
`enqueue-guard.yml` checks out `ref: main` and never runs pull request
code, so any diff that deletes or edits that document is refused by the
seal until the seal itself is on `main`. Removing the reader and
removing the document cannot travel in one pull request; this one
removes the reader, keeps the document byte-identical to the previous
tip, and the deletion is the follow-up pull request.

## What changed

1. **`.github/scripts/enqueue-guard.mjs` — the whole path, not a branch
of it.** `FROZEN_PATH`, `FROZEN_REASON`, `FROZEN_EDIT_REASON`,
`FROZEN_PULL_REQUESTS`, `frozenList()`, `frozenRefusal()` and the
`decidePull` call site with its early return are gone; `decidePull`
returns `{ decision, pull, repo, pr }` from `guard()` alone. No dead
import, no dead export, no always-true branch left. `guard()`,
`recordOnlyAt` and every other rule are untouched.
2. **The nine cases that existed only for the seal are deleted** — the
five `ThinkFlowLab#1344` cases, the `ThinkFlowLab#1350` `merged`-short-circuit case (it pinned
the seal's own ordering and has no meaning without it) and the three
`ThinkFlowLab#1354` cases. The fixture loses the `/contents/` answer and the
`frozen`, `prNumber` and `baseSha` knobs and the `BASE` constant that
fed them: nothing reads them now, so none is left dangling. **No other
test was touched** — every remaining assertion is byte-identical.
3. **`AGENTS.md` — the section is gone.** `#### Untrusted external agent
branches` goes whole: the three `Do not` bullets, the
`dequeuePullRequest` paragraph, the "never the baseline for `generate`"
paragraph and the Chinese release sentence. What `ThinkFlowLab#1350` asked for that
is *not* about the seal stays: rule 7 now matches `accountRefusal()` —
only `type === 'User'` writes a conclusion, a report with **no `type` at
all** is refused too, the account and its text stay as a note in
`judged`, and the refusal's sentence stays `no Verifier report names the
tip <sha>`.
4. **`.github/agent/frozen-branches.json` is unchanged here** — `cmp`
against the previous tip is identical. Nothing reads it after this
change; it is deleted in the follow-up pull request, which is possible
only once `main` no longer carries the rule that refuses that deletion.
5. **`ThinkFlowLab#1354` is not needed any more.** Nothing is read from `main` or
from a base, so the base-vs-main defect cannot recur; the issue is
closed by this pull request as "the mechanism was removed", not by a
fix.

## What I ran

On `/data/w1352`, a tree extracted from the repository's own tarball of
this branch's previous tip `c6ba9a09`, with `git` 2.53.0 and its
`libexec/git-core` on `PATH`:

- `node --test ".github/scripts/*.test.mjs"` → **543 / 543 pass** (this
branch was 552 before this change; `−9` is exactly the nine cases
removed with the seal).
- `node .github/scripts/enqueue-guard.test.mjs` → **88 / 88 pass** (was
97; `−9` again).
- `node .github/scripts/testing-layers.mjs --check` → `440 test file(s)
in 16 workflow(s)`, every file and every workflow classified.
- `node .github/scripts/check-mojibake.mjs` → `ok — 0 occurrences of
U+FFFD in 1155 text file(s)`.
- `diff -rq` against `c6ba9a09` → exactly three files, all listed under
Scope. `cmp` on the JSON document: identical.
- `grep -rn 'frozen-branches\|frozenRefusal\|frozenList\|external agent
branch'` over `*.mjs`, `*.md`, `*.json`, `*.yml` → **0** (22 lines at
the previous tip). The document file exists but no text names it.
- GitHub's own read of the pull request: `3 files, +3 / −116`.

## Red without the source change

**A deletion has nothing that can go red.** The nine cases were removed
together with the code they pinned, so restoring the source would
restore the tests and the suite would be green either way — claiming a
red here would be a fabrication. The mechanical substitutes, each run:

1. **The grep.** The command above returns no line and exit status 1 (22
lines at the previous tip).
2. **The module's exports.** `import()` of `enqueue-guard.mjs` names
exactly `decidePull, guard, main, recordOnlyAt`; `frozenRefusal` is
`undefined`. The export does not exist to be called.
3. **The same fake `gh`, both tips, through the printed reader.** A pull
request on a listed prefix branch with no conclusion, run through
`main()`:
- previous tip: `REFUSE — do not enqueue ThinkFlowLab#566: frozen: external agent
branch; owner decision pending`
- this tip: `REFUSE — do not enqueue ThinkFlowLab#566: no Verifier report names the
tip aaaa…; no checkpoint: …`

The seal's sentence no longer appears in any decision; the pull request
is judged by the ordinary rules, which is the point of B.
4. **The one genuine red this change can show, and it did:** main's own
seal refused this pull request while its diff deleted the document — the
`8f97e4f5` run quoted under Reproduce. That red is real and is the
reason the document is not in this diff.

## Not run

- `npm run verify`: nothing under `core/`, `plugins/` or `apps/` is
touched.
- `generate` / `scripts/ds-bot-patches.mjs check`: `patches/` is
untouched.
- `check-arch-docs`: its rule reads `core/` changes; there are none.
- A live queue entry: the next real enqueue exercises `decidePull`; a
pull request cannot stage one without merging.

## Risk

- **The seal is gone, so its refusal is gone.** A branch under a listed
prefix, or a body carrying the agent's PR-body marker, is now judged by
the ordinary rules only; one that carries a PASS at its tip and a clean
body can enter the queue. That is the owner's decision, and the seal
never stopped a direct push or an admin merge anyway.
- **The document outlives its reader for one pull request.** Between
this merge and the follow-up, `.github/agent/frozen-branches.json` sits
in the tree with nothing reading it; nothing can act on it, and the
follow-up deletes it. Anyone reading the tree in that window should read
it as a stale config, not a live rule. Deleting the reader and deleting
the file cannot travel in one pull request: `enqueue-guard.yml` is
`pull_request_target` with `ref: main` and never runs pull request code,
so main's copy of the seal refuses any diff that edits or deletes the
document. That is a mechanical constraint of the check, not a choice
made here.
- **`ThinkFlowLab#1328` stays merged.** This removes the mechanism, not that merge;
nothing here reopens or reverts it, and `ThinkFlowLab#1346`'s branch is untouched.

## Scope

- `.github/scripts/enqueue-guard.mjs` — removal only.
- `.github/scripts/enqueue-guard.test.mjs` — removal of the nine seal
cases and of the fixture knobs they used.
- `AGENTS.md` — the external-agent section deleted; rule 7's
`accountRefusal()` alignment kept.

Unchanged, deliberately: `.github/agent/frozen-branches.json`. Not
touched: `core/`, `patches/`, `package*`,
`.github/workflows/pass-label.yml`, tier calculation, and every tip
belonging to `ThinkFlowLab#1328`, `ThinkFlowLab#1346`, `ThinkFlowLab#1348`, `ThinkFlowLab#1342`, `ThinkFlowLab#1349`.

## Checkpoint

<!-- flybot:checkpoint -->
```json
{
  "pr": 1352,
  "claim": "Dev",
  "issue": 1350,
  "summary": "Executor decision B: the frozen-branch seal is removed whole, not patched. enqueue-guard.mjs loses the four constants, frozenList(), frozenRefusal() and the decidePull call site; the nine cases that only pinned the seal go with the fixture knobs they used; the AGENTS.md external-agent section goes, while ThinkFlowLab#1350's rule-7 alignment stays. ThinkFlowLab#1354's fix is moot with no list to read. The document itself is not in this diff: main's own check refuses any pull request that edits it, so it stays byte-identical for a follow-up.",
  "files": [".github/scripts/enqueue-guard.mjs", ".github/scripts/enqueue-guard.test.mjs", "AGENTS.md"],
  "checks": { "ran": "node --test \".github/scripts/*.test.mjs\" (543/543); enqueue-guard 88/88; testing-layers --check; check-mojibake; grep for the seal names; cmp of the JSON document", "result": "green", "at": "a09f330ab2b298fc1095884a7f79dd086435c26f" },
  "next": "none — ready for review at this tip"
}
```
<!-- /flybot:checkpoint -->
@github-actions github-actions Bot removed the agent-pr Pull request opened by an agent label Oct 27, 2026
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

schedules: copyRow invents the dsh-schedule row, so a missing required key would fail silently

1 participant