Skip to content

Decouple plugins: tree and social as peer plugins under plugins/ (#34 PR 2, stacked on #37) - #40

Merged
Birfy merged 2 commits into
ThinkFlowLab:mainfrom
Birfy:plugins-decouple
Oct 14, 2026
Merged

Birfy merged 2 commits into
ThinkFlowLab:mainfrom
Birfy:plugins-decouple

Conversation

@Birfy

@Birfy Birfy commented Oct 14, 2026

Copy link
Copy Markdown
Collaborator

Stacked on #37 (ds-bot-pin): this branch contains #37's commits. Review and merge them together, #37 first. Refs #34 (PR 2).

What changes

  • Tree: brought in @recursive-bot's commit 76bc623 (from Birfy/recursive-bot:flybot-tree-decouple) unchanged, with recursive-bot as author. It moves tree to plugins/tree, rewrites patches 0003/0006/0007, makes send use priority.ROUTING, and sets the peer dependency to >=0.1.5-flybot.1. Thanks @recursive-bot.
  • Social: moved from core/plugins/social to plugins/social. It is now a peer plugin like tree (ds-bot >=0.1.5-flybot.1) with its own test runner (test/resolve.mjs, fake-ctx.js). Its web-entry test moved out of core.
  • Core: core/plugins and the social tests in core are removed, and the patches are regenerated. 0006-flybot-plugins is retired because nothing is left in it. ds-bot/ is untouched, and node scripts/ds-bot-patches.mjs check passes.
  • Tests: the send ordering tests use send.priority.ROUTING/APPROVAL instead of before: ['social'].
  • CI:
    • The required job ubuntu-latest · Node 24 · DSH 0.2.0-rc.2 keeps its name and now runs core only, with coverage.
    • New plugins (tree) and plugins (social) jobs lint the plugin (scripts/lint-plugins.mjs) and run its suite with DSH_HARNESS, so the frontend tests really run. The job fails if any test is skipped.
    • tests-ok now needs both plugin jobs.
    • Branch protection is not changed.
  • Docs: install paths are now path:/core and path:/plugins/{social,tree}. Existing social installs from path:/core/plugins/social need to be reinstalled.

Local results

  • check ok
  • core: 564 pass, 0 skip
  • lint and build-client --check ok
  • tree: 49 pass, 0 skip
  • social: 28 pass, 0 skip
  • check-pack and actionlint ok

recursive-bot and others added 2 commits October 14, 2026 21:56
… ROUTING send priority (#34)

- core/plugins/tree -> plugins/tree; core/test/tree-host.test.js -> plugins/tree/test/host.test.js
  (boots core by its public entry 'ds-bot' via test/resolve.mjs -> FLYBOT_CORE | core/, in a
  plugin-local fake Cordis ctx; loads tree with ctx.plugin, disposes via ctx.effect scope)
- plugins/tree/test/web-entry.test.js: real-Cordis browser entry test (flybot.tree.forest), moved from core
- core changes via the patch workflow: delete test/tree-plugin.test.js, core client tests stop
  loading tree's bundle, local-ci runs ../plugins/tree, plugins/README; topics.json updated,
  patches regenerated (ds-bot-patches.mjs generate/check)
- adapter: flybot.version check; bot.send.use priority ROUTING (flybot.bot.send.priority) instead
  of before:['social']; mock orders by priority bands
- package.json: peer ds-bot >=0.1.5-flybot.1, own npm test, description fixed
- CI (flybot-tests action, nightly), check-pack, READMEs point at plugins/tree
- plugins/social: peer plugin like plugins/tree (ds-bot >=0.1.5-flybot.1)
- core/: drop core/plugins and social tests; regenerate patches (0006 retired); ds-bot/ untouched
- tests: send ordering uses priority constants instead of before: ['social']
- CI: plugins (tree)/plugins (social) jobs with DSH_HARNESS and a no-skip gate, required by tests-ok
- docs: install paths path:/plugins/*

Tree decoupling (76bc623) by recursive-bot.
@Birfy
Birfy marked this pull request as ready for review October 14, 2026 14:36
@chatgpt-codex-connector

chatgpt-codex-connector Bot commented Oct 14, 2026 •

Copy link
Copy Markdown

Codex Review Summary

This comment shows the latest Codex review activity on this pull request.

Review Status Commit Review trigger
📝 Code Review ✅ Completed 2026-10-14T14:49:11.499301Z d9c8a97 Draft marked ready
ℹ️ About Codex in GitHub

Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you

  • Open a pull request for review
  • Mark a draft as ready
  • Comment "@codex review" or "@codex security review".

Codex reacts with 👀 while any review is running, comments if it has suggestions, and reacts with 👍 once all reviews finish with no findings.

@Birfy
Birfy merged commit 67554b5 into ThinkFlowLab:main Oct 14, 2026
5 checks passed

@chatgpt-codex-connector chatgpt-codex-connector Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

💡 Codex Review

Here are some automated review suggestions for this pull request.

Reviewed commit: d9c8a97762

ℹ️ About Codex in GitHub

Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you

  • Open a pull request for review
  • Mark a draft as ready
  • Comment "@codex review".

If Codex has suggestions, it will comment; otherwise it will react with 👍.

Codex can also answer questions or update the PR. Try commenting "@codex address that feedback".

Comment thread CHANGELOG.md
- The core is now pristine upstream ds-bot (`ds-bot/`, pinned at Fei2411/DeepSeek-Bot@2b10c70) plus FlyBot's ordered patch series (`patches/ds-bot/`), applied into the committed `core/` (#34). Install paths move from `path:/ds-bot` to `path:/core` and `path:/plugins/{social,tree}`. The core's version is `0.1.5-flybot.1`.
- Send middleware can set a `priority` (`ROUTING` 100, `DEFAULT` 500, `APPROVAL` 900; `flybot.bot.send.priority`); names in `before`/`after` still work and win over priority. `@flybot/social` runs at `APPROVAL`.
- `types/flybot.d.ts` documents the browser `flybot` service and its slots.
- The plugins are peer packages at the repo root: `@flybot/tree` (`plugins/tree`, by recursive-bot) and `@flybot/social` (`plugins/social`, moved out of `core/plugins/social`). Each needs `ds-bot >=0.1.5-flybot.1`, tests itself against `core/`, and has its own CI job (`plugins (tree)`, `plugins (social)`, both required by `tests-ok`). Reinstall the social plugin from `path:/plugins/social`.

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

P1 Badge Re-add tree when migrating the plugin source paths

Existing profiles installed from the previous README have @flybot/tree saved as a Git dependency using path:/ds-bot/plugins/tree (or the stacked path:/core/plugins/tree). This commit deletes those directories, while README.md's Update command still runs pnpm update ... @flybot/tree and this sentence tells users to reinstall only social. pnpm update --help says it updates packages “based on the specified range,” so it re-resolves the saved, now-invalid Git path and aborts the whole update; document re-adding tree from path:/plugins/tree in both README variants too.

AGENTS.md reference: AGENTS.md:L79-L79

Useful? React with 👍 / 👎.

Comment thread plugins/tree/package.json
},
"peerDependencies": {
"ds-bot": "*"
"ds-bot": ">=0.1.5-flybot.1"

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

P2 Badge Keep future FlyBot prereleases in the peer range

With a later API-v1 FlyBot core such as 0.1.6-flybot.1, this range reports an unmet peer even though that release is newer and createAdapter accepts API v1. npm's bundled node-semver documentation says a prerelease is allowed only when a comparator with the same [major, minor, patch] tuple has a prerelease, so this comparator admits only prereleases on the 0.1.5 tuple (and even admits the unpatched stable 0.1.5) rather than future FlyBot builds; use a peer/versioning scheme that identifies the compatible FlyBot line.

Useful? React with 👍 / 👎.

Comment thread core/scripts/local-ci.sh
step="plugin tests (social)"
echo "=== $step ==="
(cd plugins/social && node --import ../../test/harness-resolve.mjs --test "test/*.test.js")
(cd ../plugins/social && npm test)

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

P2 Badge Run peer-plugin lint from local CI

On the advertised npm run ci:local macOS path, core's npm run lint no longer scans plugins after this diff, and these new package invocations run tests only; no call to scripts/lint-plugins.mjs remains before the script prints PASS. A peer-plugin no-undef or unused-variable failure therefore passes local CI even though the PR's plugins (...) job fails, so run the root plugin linter here as well.

Useful? React with 👍 / 👎.

hsliuustc0106 added a commit that referenced this pull request Oct 14, 2026
Point doctor packages and install commands at plugins/social and
plugins/tree (repo-root peers). Document npm run install:doctor in
README EN/zh and plugins/README.md. Regenerate patches/ds-bot 0007.

Verifier:
- ran: node --test test/install-doctor.test.js (11 pass); ds-bot-patches check ok
- not run: full npm test / smoke

Co-authored-by: hs liu <hsliuustc0106@users.noreply.github.com>
hsliuustc0106 added a commit that referenced this pull request Oct 14, 2026
* feat(core): install doctor for clean DSH plugin setup (part of #7)

Add core/scripts/install-doctor.mjs and npm run install:doctor to verify
Node >= 22.19 and the three plugin packages, then print the /core install
commands. Hardened checkPluginPackage so null/non-string manifests return
structured errors. Unit tests + plugins README note. Regenerate
patches/ds-bot (0006/0007 + topics) so core/ still equals ds-bot + patches.

Verifier:
- ran: node --test test/install-doctor.test.js (11 pass); node scripts/ds-bot-patches.mjs check (ok); Codex r2 FAIL (missing patches) → fixed; Codex r3 INC (no code findings, sandbox limits)
- not run: full npm test / smoke / GHA

Co-authored-by: hs liu <hsliuustc0106@users.noreply.github.com>

* fix(core): adapt install-doctor paths after plugins-decouple (#40)

Point doctor packages and install commands at plugins/social and
plugins/tree (repo-root peers). Document npm run install:doctor in
README EN/zh and plugins/README.md. Regenerate patches/ds-bot 0007.

Verifier:
- ran: node --test test/install-doctor.test.js (11 pass); ds-bot-patches check ok
- not run: full npm test / smoke

Co-authored-by: hs liu <hsliuustc0106@users.noreply.github.com>

---------

Co-authored-by: hs liu <hsliuustc0106@users.noreply.github.com>
hsliuustc0106 pushed a commit that referenced this pull request Oct 14, 2026
* Logo: new Wingbot mark and FlyBot wordmark lockup (#32)

* README: wordmark hero, CI badges, How FlyBot is built (#34)

* README: name the pin, patches and core folders

* README: drop CodeQL badge; plugins/ in architecture after #40

* README: use #main for the GitHub install example (no v0.1.5 tag)

---------

Co-authored-by: Danyang Chen <cdy@recursive.bot>
Birfy added a commit that referenced this pull request Oct 23, 2026
#774)

Written-by: Dev2

Fixes #773

Tip SHA: 14a13fc

## Reproduce

A face-to-face room is joined by reading six digits off someone else's
screen and typing them. Nothing on the waiting screen can be read by a
phone, and the join form has no way in except the keyboard: on `main`
`plugins/social/client.js` draws `FaceWaitCode` (the number) and a
`fs-digits` input, `grep -c BarcodeDetector` is 0, and the only
`getUserMedia` in the repo is the microphone in `speech.js` /
`voice.js`.

A room that already exists has the second half of the same hole: no way
to invite anyone into it. `grep -c "face-invite"
plugins/social/client.js` is 0 on `main`, the client has no link shape
to paste or scan, and the host exposes only `social/face-join` with a
6-digit code. Bot Social's side is `Birfy/bot-social#39` / `#40` (`POST
/v1/face-rooms/:id/invites`, `DELETE …/invites/:ticket`, `GET
…/invites/:ticket`, `POST /v1/face-rooms/join-invite`, advertised as
`face_room_invites`).

## What changed

- `plugins/social/client.js`: a self-contained QR encoder (byte mode,
error correction level M, versions 1–10 picking the smallest that fits)
plus `QrImage`, an `svg` with one `path` over the dark modules, and
`FaceQr` as the room-number wrapper. The room-code payload is `FLYBOT-`
+ the six digits and nothing else: a deadline inside the image would
re-encode every second and a screenshot would carry a stale number. The
invitation payload is the invite URL itself, so a phone camera opens the
same room.
- `FaceWaitCode` takes `qrAt` / `qrOffsetMs` and draws the QR under the
number, from Bot Social's deadline (corrected by the clock offset), in
the dialog and in the room panel. The code goes when joining ends and as
soon as the room opens.
- Scanning: a **Scan a code** button reads frames with the platform
`BarcodeDetector` and the camera with `getUserMedia`. The decoder is
checked **before** the camera prompt, a refused camera gets one
sentence, a payload that is neither `FLYBOT-<six digits>` nor an invite
link is refused, and the camera is released on every path. A scan only
fills the same field and calls the same `join()` (`join` gained an
optional `{ code }`), never a second way in.
- **Camera fixes from the INC** (`#774` review,
[6352294330](#774 (comment))):
`new BarcodeDetector({ formats: ['qr_code'] })` now sits in a
`try`/`catch` — a platform that has the decoder but refuses the format
used to leave the camera running with the prompt stuck at `Point the
camera at a FlyBot room code.` and one unhandled rejection; now it
answers `This browser cannot scan codes. Type the 6-digit number
instead.` through the same `finish` that stops the stream. And
`startFaceScan` releases the previous scan's camera before opening a new
one, so tapping **Scan a code** twice no longer orphans the first stream
behind a module-level `faceScanStop`.
- **Invite by link** on an open room (`FaceInviteCard`,
`data-flybot=face-invite`): **Create link** mints a ticket (`POST
/v1/face-rooms/{id}/invites`), the card draws that link as the QR, and
shows the link as text, **Copy link**, the server deadline and
**Withdraw link** (`DELETE …/invites/{ticket}`). The URL is built by the
host from its own base (`faceInviteUrl`), never trusted from the reply.
An expired link and a withdrawn one each say so and draw no image.
- One shape in and out: `https://…/r/<ticket>` (`parseFaceInviteLink`).
Pasting or scanning anything else is `That is not an invite link. It
looks like https://…/r/…` and the 6-digit number stays the way in.
Joining is `POST /v1/face-rooms/join-invite`, and each refusal keeps its
own sentence: `invite_not_found`, `expired` and `revoked` each ask for a
new one, `room_full`, `ended` (the room has closed), `already_member`.
The ticket is Bot Social's 32-byte base64url (43 characters, inside the
`[A-Za-z0-9_-]{16,64}` shape this client accepts); the public preview
(`GET /v1/face-rooms/invites/{ticket}`) is mapped from the server's own
`member_count` / `max_members`.
- **Both invite paths are gated**: mint, revoke, preview and
`social/face-join-invite` all go through `serverInvites()` and answer `{
unsupported: true }` on a server whose `GET /v1/platform` features lack
`face_room_invites`, so no request is made to a route that is not there
(this is the third INC item,
[6352294330](#774 (comment))).
- `docs/subsystems/social.md` and
`changelog.d/773-face-room-qr.added.md`.

This tip is rebuilt on current `main` (`fd205c40`): `social.js`,
`social.test.js` and `docs/subsystems/social.md` carry `main`'s newer
content plus this PR's additions (three-way merged), so merging does not
revert `#776` / `#777`.

## What I ran

At `14a13fcc61e5bf3cbc0845d1a1711cb657506899`, on a tree that is exactly
`main` `fd205c40` + these seven files (tarball of `main` with the PR's
files copied over, `git init` + commit so `ds-bot-patches` can run):

- `plugins/social`: `node --import ./test/resolve.mjs --test
"test/*.test.js"` → **354 tests, 354 pass, 0 fail** (baseline on `main`:
330/330). All 24 new tests are named `#773:`.
- `node .github/scripts/changelog.mjs check` → 3 fragments well formed.
- `node .github/scripts/testing-layers.mjs --check` → `315 test file(s)
in 12 workflow(s)`, all classified.
- `node scripts/ds-bot-patches.mjs check` → three ok (pin, 10 patches
apply, `core/` equals `ds-bot/` + patches).
- `node scripts/lint-plugins.mjs social` → 0 errors, 34 warnings, all
pre-existing.
- `core/scripts/check-arch-docs.mjs` → `OK (7 changed file(s))`.
- `node --test ".github/scripts/*.test.mjs"` → **227/227**, including
the `check-empty-catch` guard that failed the first tip.

The QR matrices are pinned against an independent encoder
(`node-qrcode`, byte mode, level M): 441 modules for `FLYBOT-482913` at
version 1, and for the invite link the sha256 of the drawn `path` over
the 33×33 version-4 matrix (mask 2).

## Red without the source change

Each line is the mutation and the tests that failed
(`--test-name-pattern "#773"`):

- Do not render `FaceQr` under the number → 3 red (matrix, deadline,
panel).
- Make `qrJoinable` ignore the deadline → 3 red (dialog, panel, and an
expired invite keeps its image).
- Write the format bits without their BCH mask (`^ 0x5412`) → 1 red (the
matrix test).
- Ask for the camera before checking `BarcodeDetector` → 1 red.
- Let the scan call `social/face-join` itself → 1 red (only the shared
`join` moves the dialog on).
- Accept any payload as a room code → 4 red (a foreign QR or pasted text
would join).
- Never release the camera → 1 red.
- Drop the invite card from the open room → 4 red (invite QR, Create
link, older-server sentence, expired/withdrawn).
- Treat any text as an invite link → 4 red.
- Let the invite endpoints ignore the feature list → 1 red (a POST to a
route that is not there).
- Give `expired` and `revoked` the same sentence → 1 red.
- Construct the detector without `try`/`catch` → 1 red (`a decoder that
refuses the qr_code format releases the camera and says so`).
- Drop the "release the previous scan" step → 1 red (`tapping Scan twice
releases the camera the first tap opened`).
- Remove the `serverInvites()` gate from `face-join-invite` → 1 red
(`joining by ticket on a server without face_room_invites never reaches
the route`).

## Not run

- No real camera and no real `BarcodeDetector` here: both are driven
through stubs, and the encoder is checked against a reference
implementation rather than a scan of a printed code. The first real scan
will be in the app.
- No live Bot Social carrying `#40` here: the feature gate and the REST
calls are tested against stubbed servers (with and without
`face_room_invites`). On this repo's servers the card is expected to say
*Invites need a newer Bot Social* until `#40` is deployed — that is the
designed answer, not a failure.
- **CI on this tip is blocked by the account billing lock** (`The job
was not started because your account is locked due to a billing
issue.`), which affects every PR. The local run above is on the same
tree CI would build; the tip can be re-run unchanged once billing is
restored.
- `npm run verify` as a whole was not run; `plugins/tree`,
`plugins/timeline` and `core` are untouched by these seven files.

## Risk

**T3** (client, host glue, tests, one docs page, one changelog
fragment).

The image is drawn from a payload this app chooses, so a wrong matrix
can only produce an unscannable code; the room code's payload *is* the
number the panel prints, so it cannot point at another room. A foreign
QR or pasted text cannot join anything: both are refused with one
sentence before any request. The camera is a permission surface, so the
decoder check runs first, the stream is stopped on every exit (including
a second tap and a detector that refuses the format), and the button is
disabled while a join is in flight. An invite link is a bearer
credential for as long as the room is open — the same window the 6-digit
number already had — and **Withdraw link** revokes it server-side. On a
server without `face_room_invites` nothing new is reachable and the
typed number behaves as before.

Deliberately out of scope, per the review and the owner decision:
`face-invite-preview` / `previewInvite` stays wired end to end but is
not called by any screen yet (follow-up issue records the "show the room
before joining" step, including cleaning the server's `name` before
rendering); `serverInvites()` still re-probes `GET /v1/platform` on each
call instead of using the shared probe window — a one-line change left
for that follow-up rather than folded into the camera fix.
HugoXK pushed a commit to HugoXK/FlyBot that referenced this pull request Oct 24, 2026
ThinkFlowLab#931)

Owner: Dev3
Reviewer: Reviewer2

Fixes ThinkFlowLab#928

## Reproduce

On `main` `137cd2fd`, with `review-policy.json` carrying `selfReview:
["Birfy", "hsliuustc0106"]` (what ThinkFlowLab#926 adds), `decide()` is fed the real
comments of ThinkFlowLab#926's head `b80823ef`. The PASS by `hsliuustc0106` reports
`counts: false` with `author association CONTRIBUTOR is not OWNER,
MEMBER or COLLABORATOR, so it is not a conclusion`, and it is the head's
only report.

The cause is ordering, not the list: `ASSOCIATIONS`
(`review-gate.mjs:36`) is checked at `:162`, `selfReview` is read at
`:144` and only consulted at `:178` — after the association gate has
already dropped the report. So adding the login changes nothing, which
is what Reviewer measured on ThinkFlowLab#926.

## What changed

- `.github/scripts/review-gate.mjs` (+5/−1): at the association gate,
`const selfOnly = selfReview.has(login(r)) && login(r) === authorLogin`,
and `if (!ASSOCIATIONS.has(association) && !selfOnly)`. One exemption,
for one semantic: a listed login judging **its own** pull request. Every
other check is untouched — `hold`, stale tip, `Written-by:`, `Ran:`, the
reviewer list, the newest-word rule.
- `.github/scripts/review-gate.test.mjs` (+23): one test, three cases —
listed + `CONTRIBUTOR` + own pull request → `counts: true`; unlisted
`passer-by` + `CONTRIBUTOR` → `counts: false`; listed + `CONTRIBUTOR`
judging someone else's pull request → `counts: false`. The third case is
what keeps the exemption from becoming a second reviewers list.
- `AGENTS.md:150` and `docs/autonomous-dev.md:147`/`:163`: the exception
written next to the rule it changes, dated as the owner decision it
executes.

Not in this PR: ThinkFlowLab#926 itself (a one-line JSON change on someone else's
branch), and no other gate. `selfReview` is still a subset of
`reviewers`; the boolean this adds is narrower than the association
check it excuses.

## What I ran

- `cd .github/scripts && node --test "*.test.mjs"` → **333 pass / 0
fail**.
- `cd .github/scripts && node --test review-gate.test.mjs` → **40 pass /
0 fail** (the new test is ThinkFlowLab#40).
- `node .github/scripts/changelog.mjs check` → 45 fragments well formed
(no fragment here: the gate is not user-visible, same as ThinkFlowLab#912).
- `node core/scripts/check-arch-docs.mjs --base 3c711b3` → `OK (17
changed file(s))`; no `docs/subsystems` page owns `.github/scripts/`,
`AGENTS.md` or `docs/autonomous-dev.md`, and both policy documents are
updated in this branch anyway. (The local base is stale — CI judges the
real base.)
- Before pushing, each of the four files was diffed against its
**current `main`** content fetched through the API (`137cd2fd`): the
only differences are the hunks above, so the branch cannot revert
anything that landed on `main`.

## Red without the source change

- Mutation A — delete `&& !selfOnly` from the guard: `node --test
review-gate.test.mjs` → `not ok 40 - ThinkFlowLab#928: a listed self-reviewer who is
a CONTRIBUTOR counts, only on their own pull request`, **39 pass / 1
fail**.
- Mutation B — widen to `selfReview.has(login(r))`: same test red, **39
pass / 1 fail**.
- Restored file is byte-identical to the branch version (`diff -q`
clean), `40 pass / 0 fail`.
- With `review-gate.mjs` at `main` and the new test kept, case 1
(`mine.ok`) is false, so the test fails — the source change is what
makes it pass, not the fixture.

## Not run

- Full `npm run verify`: this box has no `core/node_modules` / harness
install, so `core` and plugin suites are not run here — CI runs them.
Nothing in this branch touches `core/`, `plugins/` or `client.js`.
- No smoke test: no `index.js` or `core/src/host/` change.
- No live re-run against ThinkFlowLab#926's data after the change (its head is
unchanged and still carries the old conclusion); the fixture in the test
reproduces those comment records instead.

## Risk

- The exemption is keyed on `selfReview` membership **and** `login ===
authorLogin`, so a login added to `selfReview` now also gets the
association exemption on its own pull request. That is exactly the owner
decision recorded in `AGENTS.md`, but it means `selfReview` is no longer
purely "may PASS its own PR" — it also says "may be a `CONTRIBUTOR`
while doing so". Anyone else's pull request is unaffected (pinned by the
third case).
- `merge-gate.mjs` imports this `decide`, so a queue entry is judged by
the same rule; a `CONTRIBUTOR` who is not listed is still refused at the
queue, as before.
- ThinkFlowLab#926 stays open and unchanged by this PR; per the Chief it goes in
together with this one, so the policy change and the code that makes it
mean anything land as a pair.

Docs-not-needed: no `docs/subsystems` page owns `.github/scripts/`,
`AGENTS.md` or `docs/autonomous-dev.md` (checked against their
`owned_paths`), and the rule itself is updated in `AGENTS.md` +
`docs/autonomous-dev.md` in this branch.
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.

2 participants