Repository navigation
fix(spec): the pending connector-sync note matches the executor, and the error-code ledger lists its two refuse() codes (#21106) - #21150
Conversation
…r @objectstack/service-automation's ledger key MAPPING_NOT_FOUND and UNSUPPORTED_TRANSFORM are stamped onto ConnectorPullError.code through connector-pull.ts's local refuse(...) helper, a call-site form check:error-code-provenance declares itself blind to; the gate's own test pins both rows by hand and pins the blind spot itself. The new spec note carries the provenance-not-identity sentence for this release's ledger face changes. Claude-Session: https://claude.ai/code/session_017VaLJnYwhPsanVCe9dMCJU Co-authored-by: Claude <noreply@anthropic.com>
…ads connectorSource, not that nothing executes it A deliberate correction of the stage-1 pending note before the next changeset version, so the version that carries the executor does not also say nothing executes the binding. The clause about os validate / os build warning is dropped: at this tree the liveness lint throws on the binding's live + authorWarn row instead of warning. Claude-Session: https://claude.ai/code/session_017VaLJnYwhPsanVCe9dMCJU Co-authored-by: Claude <noreply@anthropic.com>
…tes-ledger Claude-Session: https://claude.ai/code/session_017VaLJnYwhPsanVCe9dMCJU Co-authored-by: Claude <noreply@anthropic.com>
📓 Docs Drift CheckThis PR changes 1 package(s): 5 hand-written doc(s) NAME something this change touched and may need an implementation-accuracy re-verification:
⛔ 4 release-owned page(s) also name something this change touched. These are read-only:
What this run could not see
Coarse fallback — 137 page(s) merely mention a changed package (the pre-#9192 predicate, kept for the deliberately-wide backstop): Which tree this was computed onThis run read A worktree cut from an older # while this PR is open — GitHub drops the merge commit once it closes
git fetch origin ebc0968c1491ed1d1141e52ec1409921f3d30875 && git checkout ebc0968c1491ed1d1141e52ec1409921f3d30875
# afterwards, rebuild it from the two parents, which stay fetchable
git fetch origin e952cff578cc936daab3241570c4c2c36804bbd6 5748c8ddd10f9d056f143ad470a9dec1a3c80d52 && git checkout -B drift-repro e952cff578cc936daab3241570c4c2c36804bbd6 && git merge --no-ff 5748c8ddd10f9d056f143ad470a9dec1a3c80d52
node scripts/docs-audit/affected-docs.mjs --json e952cff578cc936daab3241570c4c2c36804bbd6
|
Contract reviewServed-tier: PR #21150 (card #21106; the three follow-ups the at-tier review of PR #21084, comment ① Derived judgments
Gates (the head's check-runs are the verdicts, read at 2026-10-01T10:18Z): 33 check-runs on ② Semver level
③ Boundary flagsRead from the dev report
Implemented-by: VERDICT: PASS Nothing is blocking. The stage-① note's correction is true of the code at Generated by Claude Code |
|
Designed red, recorded before enqueue ·
Generated by Claude Code |
…and lints again — the `live` ledger row carries no author warning (objectstack-ai#21127) (objectstack-ai#21176) Fixes objectstack-ai#21127 Clause-②: no ## What this changes `os validate --json` and `os lint --json` exited 1 on any stack whose `mappings[]` entry authors `connectorSource`. The whole answer was the liveness lint's integrity sentinel: `lintLivenessProperties: ledger entry has unrecognised status "live"`. The ledger row `mapping.connectorSource` had been re-graded `live` and kept `authorWarn: true`. `describe()` in `packages/lint/src/lint-liveness-properties.ts` throws on a warned `live` row by design, and that throw stays as it is. - **The row** (`packages/spec/liveness/mapping.json`): `connectorSource` stays `live` and drops `authorWarn` / `authorHint`. Its `note` records why. - **The caveat moves to where an author reads it** (`packages/spec/src/data/mapping.zod.ts`). The `connectorSource` `.describe()` now reads: "Pulled when a job drives it; nothing schedules it yet, so the binding alone moves no rows — schedule the pull with a `job` once a job can drive one". The docblock no longer says the ledger keeps `authorWarn`. - **The existing integrity check refuses the combination, inside its current gate** (`check:liveness`, `packages/spec/scripts/liveness/check-liveness.mts`). No new gate or script was added. The graded walk never reads a container row that drills into `children`, and `connectorSource` is such a row, so the new rule walks the raw ledger rows at every depth. It fails on `status: "live"` with `authorWarn: true`, prints a prescription, and prints a census line on every run: `author warnings: 2 ledger row(s) opt into authorWarn, at any depth (planned 2); 0 on a live row.` - **Regenerated:** `content/docs/references/data/mapping.mdx` and `integration/connector.mdx` (`gen:docs`), and `packages/spec/src/migrations/registry.ts` (`gen:migration-registry`). ## Files beyond the claim's listed surface (each one is text this change made false) The claim lists the ledger row, the `connectorSource` describe, the existing integrity check, the regenerated artefacts, the pins and one changeset. These files are outside that list. Each one said that authoring the binding warns, and that stopped being true with the row fix: - `packages/spec/src/integration/connector.zod.ts`: the retired `connector.syncConfig` prescription, which an author sees in the refusal. - `packages/spec/src/migrations/entries/semantic/18.connector-sync-keys-retired.ts`: the upgrade entry's acceptance text. `registry.ts` is regenerated from it. - `packages/spec/src/integration/connector-sync-retirement.test.ts`: a one-line pin on that prescription text. - `packages/spec/docs/SYNC_ARCHITECTURE.md`: "authoring `connectorSource` still warns". - `packages/spec/liveness/README.md`: the mapping row's note, plus a third `authorWarn` rule (a `live` row carries none). - `packages/lint/src/authoring-rules.ts`: comments only. - `packages/lint/src/runtime-gate.inert-type-writes.test.ts`: a comment, and a pin. A `mapping` write that authors `connectorSource` used to get an `authoring-rule-threw` advisory at the runtime door, and now gets none. - `packages/cli/test/validate-lint-mapping-connector-source.test.ts`: the door pin, a new file. - `.changeset/20919-spec-connector-source-live.md`: see the next section. ##⚠️ One deliberate correction of a pending release note (needs confirming) `.changeset/20919-spec-connector-source-live.md` belongs to PR objectstack-ai#21084. It has not been released yet, and it said "`connectorSource` rows are `live` and keep `authorWarn`". This PR makes that false, so the sentence now reads "rows are `live`, with no author warning: that nothing schedules a pull yet is said on the key's description". `node scripts/check-empty-changeset.mjs --base origin/main` is therefore red by design. It says: "This PR changes a changeset it did not add … DELIBERATE CORRECTION -- … do NOT restore it -- say so on the PR and get it confirmed". This section is that statement, and `skip-changeset` is not applied. `.changeset/20281-connector-sync-moved-to-mapping.md` carried a similar claim. PR objectstack-ai#21150 has since rewritten it on `main` without the warn claim, and this PR does not touch it. ## Premise check - **H1, the crash** (measured at the dispatch base `665cab338f`, which contains PR objectstack-ai#21092 `b616c0a63d`). The card's fixture is one object `fx_account` with `sharingModel: 'private'`, plus one mapping with `sourceFormat: 'json'`, `targetObject: 'fx_account'`, `mode: 'upsert'`, a `fieldMapping` and `connectorSource: { connector: 'crm_api', action: 'request' }`. - At base, `os validate --json` and `os lint --json` both exited 1, and the only error was the sentinel. - After the fix, on the merged head `b6d58dd04`: `validate` exits 0 with `"valid": true`. `lint` exits 0 with `"passed": true` and one unrelated warning (`protocol/missing-engines-range`). Neither output names `connectorSource` or contains the sentinel. - The crash had been hiding a real finding. Without `sharingModel`, the same object gets `security-owd-unset`, so the fixture declares it. - **H2, the integrity check.** Yes, inside `check:liveness`. Run against the unfixed ledger, the gate exits 1 with exactly one ✗ block: "1 `live` ledger row(s) opt into `authorWarn` — the author-side lint throws on them: mapping/connectorSource". - **H3, census** (re-run on the merged head). Across all 41 governed ledgers, 924 rows were walked at every depth. Two carry `authorWarn: true`, both `planned` (`object.externalSharingModel`, `translation.flows`). None is `live`. Before the fix, `mapping.connectorSource` was the only `live` one, so no other row has this defect. - **H4, describe text.** Done as above. Author-facing text cites no tracker number. ## Pins - `packages/spec/src/data/mapping-connector-source.test.ts`: every key of the binding is `live`, and no row of it, at any depth, carries `authorWarn` / `authorHint`. The description still says nothing schedules a pull. The old assertion `authorWarn === true` pinned the defect. - `packages/spec/scripts/liveness/check-liveness.test.ts` runs the real gate via `--ledger-root`: - green on the shipped ledgers, with the census line showing warned `planned` rows and none on a `live` row (the control); - red when a `live` container row with `children` opts in (the regression's shape); - red when a drilled `live` child opts in. - The carriers are picked from the shipped ledgers by shape, not by name. - `packages/lint/src/lint-liveness-properties.test.ts` runs against the real ledger. The card's fixture lints without throwing and draws no `connectorSource` finding. Control: `object.externalSharingModel` (`planned` + `authorWarn`) still warns as `liveness-planned-property`. - `packages/lint/src/runtime-gate.inert-type-writes.test.ts`: a `mapping` write that authors `connectorSource` gets no errors and no advisories at the runtime door. - `packages/cli/test/validate-lint-mapping-connector-source.test.ts` is in the integration tier and spawns the CLI: - the card's fixture: `os validate --json` exits 0 with `valid: true`, and `os lint --json` exits 0 with `passed: true`; - control: adding `externalSharingModel` produces a `liveness-planned-property` warning, still at exit 0. ## Reverse verification (one-time, not a permanent file) This was run twice on the committed fix, with identical results: once at `7bc7c5c26`, and again after the `main` merge at `b6d58dd04`. `node scripts/ablation-replace.mjs` put `"authorWarn": true` back on the `connectorSource` row. The anchor count went 1 → 0, and the blob changed `49cc72e394b8` → `65665b90b21d`. With the defect back, every leg went red: - door: `validate` exit 1 and `lint` exit 1, with the sentinel in both; - `check:liveness` exit 1 (`1 on a live row — FORBIDDEN`); - spec pins: 2 failed; - lint pins: 3 failed; - CLI door pin: 3 failed. The tool restored the file and proved it: the blob equals HEAD and `git diff HEAD` is empty. The ledger is read from `packages/spec/liveness/` at runtime, not from `dist/`, so no rebuild was involved. ## Verification (all at `b6d58dd04`, the PR head) `origin/main` `fde553c50` was merged in with `bash scripts/pm/os-regen-merge.sh`. The merge was clean. `registry.ts` auto-merged as text, and `check:migration-registry` then confirmed it. Main had not touched the two reference pages, so they kept the branch's bytes. No regeneration commit was needed: after a fresh spec build, `check:generated` reports all 15 generated artefacts up to date. The delta against `main` is unchanged: 19 files, +538 / −42. | what | command | result | |---|---|---| | spec build | `pnpm --filter @objectstack/spec build` | exit 0 | | generated artefacts | `pnpm --filter @objectstack/spec run check:generated` | exit 0, "All 15 generated artifacts are up to date" | | CLI closure build | `pnpm exec turbo run build --filter=@objectstack/cli... --concurrency=2` | exit 0, 59/59 tasks | | the card's fixture | `os validate --json` / `os lint --json` | exit 0 / exit 0, sentinel 0 times, `connectorSource` 0 times | | ledger integrity | `pnpm --filter @objectstack/spec run check:liveness` | exit 0, "0 on a `live` row" | | strictness ledger | `pnpm --filter @objectstack/spec run check:strictness-ledger` | exit 0 | | spec tests | `vitest run scripts/liveness src/data src/integration/connector-sync-retirement.test.ts src/migrations` | exit 0, 130 files, 4269 passed, 1 todo | | spec typecheck | `pnpm --filter @objectstack/spec typecheck` | exit 0 | | lint, whole package | `pnpm --filter @objectstack/lint exec vitest run` + `typecheck` | exit 0, 118 files, 5489 passed; typecheck exit 0 | | CLI unit tier | `vitest run --project unit test/lint test/validate src/commands/validate src/commands/lint` | exit 0, 11 files, 125 passed | | CLI door pin | `vitest run --project integration test/validate-lint-mapping-connector-source.test.ts` | exit 0, 3/3 | | eslint, narrowed | `pnpm exec eslint --no-inline-config --format json` on all 19 changed paths | exit 0. eslint linted 12 and reported 7 (`.md` / `.mdx` / `.json`) as "no matching configuration"; 0 errors, 0 warnings | | derived gates | `dispatch-gates.mjs --commands` (117), each run, then `--ran` | 117 run: 116 exit 0, and 1 exit 1. That one is `check-empty-changeset --base origin/main`, the deliberate correction above. `--ran`: "117 run, 0 NOT-MEASURED, 0 UNRUN". `check:pm-dispatch-gates` was killed by a timeout at 400s and then at 540s. It was then run to completion and exited 0; its battery took 1432s on this box | **The eslint narrowing is a measurement, not a skip:** - The population comes from eslint's own answer for each changed path: 12 linted, and 7 that `eslint.config.mjs` has no configuration for. - The file count comes from the `--format json` output. - The config enables no type-aware linting (no `parserOptions.project`), so this diff cannot move the verdict on any file it did not touch. ## Acceptance notes - **turbo 2.11.5 wrote into `AGENTS.md` before the merge.** It appended its managed `turborepo-agent-rules` block on every AI-attributed turbo run in this worktree: 3 builds, and once during `check:type-check-debt`. Each time the file was restored with `git checkout HEAD -- AGENTS.md`, and `git diff HEAD` was confirmed empty. Files were staged by path only, so the block was never staged and is not in this PR. PR objectstack-ai#21151 (`agentGuidance: false` in `turbo.json`) came in with the merge. Since then, `AGENTS.md` stayed unmodified across the 59-task CLI closure build and all 117 gates. - `@objectstack/lint` gets no changeset. Its source change is comments only. Measured: tsup keeps comments, so the comment text does reach `dist/*.js` bytes. The seat can override this. - objectstack-ai#21127 is cited only where agents and reviewers read: the `authoring-rules.ts` comment, and the ledger's `note` and README prose. Author-facing text (`.describe()`, the retired-key prescription, the upgrade entry) cites no tracker. --- _Generated by [Claude Code](https://claude.ai/code/session_017VaLJnYwhPsanVCe9dMCJU)_ --------- Co-authored-by: Claude <noreply@anthropic.com>
Fixes #21106
Clause-②: yes
Three release-text follow-ups from the at-tier contract review of PR #21084 (comment
5926057594), all due before Version Packages #20639 next picks up PR #21084. Each sentence was checked against the code at PR #21084's merge commit8368f1c0. The target files are byte-identical between8368f1c0and this branch's base (git diff --statprinted nothing). No package source changes..changeset/20281-connector-sync-moved-to-mapping.mdsaidconnectorSourcewas "declared, not yet executed" and that "Nothing executes it in this release". The stage-② note.changeset/20919-spec-connector-source-live.mdsays the executor reads it. Both compile into the same@objectstack/specCHANGELOG version.ERROR_CODE_LEDGERface changes, in a new spec note,.changeset/21106-error-code-ledger-provenance-rows.md.@objectstack/service-automationprovenance rows,MAPPING_NOT_FOUNDandUNSUPPORTED_TRANSFORM, inpackages/spec/src/api/error-code-ledger.zod.ts. A hand pin in the provenance gate's own test,packages/spec/scripts/check-error-code-provenance.test.ts, guards them.1 · The stage-① note correction
os validate/os buildwarn when it is authored."@objectstack/service-automation'spullConnectorSource(#20919), reads it; nothing schedules a pull until thejobstage lands."Everything else in the file is byte-identical: the front matter, the summary line, the BREAKING banner, the FROM → TO table and the retirement kit. The diff is +4 / −3 lines in one paragraph.
Readings at
8368f1c0:packages/services/service-automation/src/connector-pull.tspullConnectorSource(:209) reads the mapping throughgetMetaItemand itsconnectorSource. It makes one action call and writes throughrunImport. The liveness rows say the same:packages/spec/liveness/mapping.json,connectorSourcelive, evidenceconnector-pull.ts#pullConnectorSource.jobstage lands". Outside tests,pullConnectorSourcehas three places in its own package: the definition, the index re-export and the plugin method (plugin.ts:621). No package source calls the plugin method.os validate/os buildwarn when it is authored" is NOT kept. It is false at8368f1c0, measured:livewithauthorWarn: true.lintLivenessProperties'sdescribe()(packages/lint/src/lint-liveness-properties.ts) has nolivebranch. It throws its sentinel for that pair, by design: its own header calls the pair "a ledger authoring mistake".runAuthoringRules('validate', …), the callos validatemakes (packages/cli/src/commands/validate.ts:522), THREWlintLivenessProperties: ledger entry has unrecognised status "live"for a stack whosemappings[]carriesconnectorSource. The control withoutconnectorSourcegave 0 findings.runRuntimeAuthoringRules) answered oneauthoring-rule-threwadvisory in place of the liveness warning.99398542band again at this head.lint-liveness-properties.ts,authoring-rules.ts,runtime-gate.tsandliveness/mapping.jsonhave no diff between8368f1c0and99398542b. The CLI process itself was not run: its closure was not built here.2 · The ledger sentence, and the counts behind it
Measured on
ERROR_CODE_LEDGERat8368f1c0against its parent2742e537, comments stripped:8368f1c0@objectstack/restAMBIGUOUS_MATCH,BLANK_MATCH_KEY,CONCURRENT_UPDATE,ERR_DATASOURCE_UNAVAILABLE,NO_MATCH,SUMMARY_RECOMPUTE_FAILED,UNIQUE_VIOLATION@objectstack/coreAMBIGUOUS_MATCH,BLANK_MATCH_KEY,NO_MATCH,SUMMARY_RECOMPUTE_FAILED,UNSUPPORTED_TRANSFORM@objectstack/typesCONCURRENT_UPDATE,ERR_DATASOURCE_UNAVAILABLE,UNIQUE_VIOLATIONErrorCode)The card and the review say rest lost −8. The measurement is −7. Eight codes moved (5 to core and 3 to types), but rest kept
UNSUPPORTED_TRANSFORM, whichresolveNamedMappingstill stamps. Literal counts inpackages/rest/srcnon-test source at8368f1c0: 0 for each of the seven, and 1 forUNSUPPORTED_TRANSFORM. The note says seven.The sentence follows the #20206 (
5f9d7d78) and #19441 (3f9e2eaa) paragraphs. It names both steps of this release's face change, the #20919 move and this PR's two rows, and says the union, the wire and the HTTP answers are unchanged.3 · The two rows, and why a pin rather than a wider gate
8368f1c0(unchanged since).connector-pull.ts:234refuse('MAPPING_NOT_FOUND', 404, 'mapping_not_found', …)and:303-304refuse('UNSUPPORTED_TRANSFORM', 400, 'unsupported_transform', …). Both go ontoConnectorPullError.code, and the class is exported from the package index.@objectstack/rest, andUNSUPPORTED_TRANSFORMunder@objectstack/coretoo. Neither is inerrors.zod.ts. The executor's other five codes are standard-catalog members and owe no row:VALIDATION_ERROR,EXTERNAL_SERVICE_ERROR,INTEGRATION_ERROR,SERVICE_UNAVAILABLE,INVALID_FIELD.MAPPING_NOT_FOUNDafterINVALID_SIGNAL, andUNSUPPORTED_TRANSFORMlast. One comment records the stamp sites, the statuses and the reachability reading: no HTTP door on this tree, so the thrown value is the boundary. No other package's rows were touched.check:error-code-provenance's header declares it blind to a helper indirection (amakeError(code, …)call site). It also says "Widening is a gate-population change with an unmeasured blast radius — its own card, never a rider". So this PR keeps the gate's patterns and pins the two rows by hand instead.refuse('CODE', …)call-site form stamps a registered code at 7 sites in 3 packages: coreartifact-packages.ts×4, runtimeartifact-collections.ts×1, and these two. Before this PR, these two were the only unlisted ones; after it, none is unlisted.scanSourceTextfinds no site in arefuse('X', …)call. The other asserts thatERROR_CODE_LEDGER['@objectstack/service-automation']lists each code. It reads the ledger module insidepackages/spec, so the suite still reads nothing outside its package.scripts/ablation-replace.mjsin WRAP mode, run from the committed state atc227eb366:MAPPING_NOT_FOUNDrow gave1 failed | 16 passed (17): "expected [ …(9) ] to include 'MAPPING_NOT_FOUND'".UNSUPPORTED_TRANSFORMrow gave1 failed | 16 passed (17), on that code's case.229345964e13= HEAD,git diff HEADempty).Changeset gate: no
skip-changeset, andCheck Changesetstays red by designThis PR edits a pending changeset that it did not add.
node scripts/check-empty-changeset.mjs --base origin/mainexits 1 and refuses.changeset/20281-connector-sync-moved-to-mapping.mdas the DELIBERATE CORRECTION class. The precedents are PR #20991 and PR #21012. Ruling D on #18375 saysskip-changesetis never applied to a PR that edits an existing changeset, so no label is applied.Check Changesetis not a required context.Confirmation requested in writing on this PR: the stage-① note's
connectorSourceparagraph now says the executor reads the binding and nothing schedules a pull yet. It no longer says nothing executes it or thatos validate/os buildwarn.Clause-②: yes, not the claim'snoThe claim (
5926939917) and the dispatch saypatchwithClause-②: no. The dispatch also says not to keepnosilently if the diff widens a public surface, and it does:ERROR_CODE_LEDGER['@objectstack/service-automation'], a publishedas constface.no, #15963 landsyes, and they are the same class #16404 ruling) names this ledger, together withStandardErrorCode, as the published contract face for error codes.recordsOf(stack.packages)readers treat a non-arraypackagesas "no packages" instead of refusing it — the packages/lint half of #19925 (ruling #15293-A) #20206 and [finding]plugin-security四处错误码发射点未登记 ledger,且免登记的理由注释经实测为假(NOT_OVERRIDABLE不在 StandardErrorCode、在 ledger 里) #19441, each declared a provenance-row addition as@objectstack/specminorwithClause-②: yes. Both say "What widens is the per-package face".So the new note is
minorwithClause-②: yes, and this body's second line matches it. No accept set changes: theErrorCodeunion is unchanged. Every package is in the onefixedgroup, and@objectstack/specalready has a pendingminor, so the released version is the same either way. The seat can flip it back if it reads the precedent differently.Verification at
5748c8ddd(base99398542b, merged withorigin/main39ab2940e)node scripts/pm/dispatch-gates.mjs --commands --repo objectstack-ai/objectstack(exit 0) derived 87 commands from the four changed paths. Each ran on this head, with its exit code captured before any pipe:check:error-code-provenance("scanned 2636 files; 335 registered-code stamp site(s): 316 listed, 19 waived" / "OK"),check-adr-0087-registration.mjs --base origin/main("this PR adds no declared-breaking changeset (2 non-breaking changeset(s) seen)"),check-changeset-no-major.mjs --base origin/main("This diff introduces nomajorbump"),check:api-surface,check:authorable-surface,check:docs,check:liveness,check:error-code-casing,check:dispatcher-error-vocabulary,check:cross-package-test-inputs,check:nul-bytes,check:query-options-erasureandcheck:type-check-debt.check-empty-changeset.mjs --base origin/main, the DELIBERATE CORRECTION class above.PREREQUISITE NOT MET):check:dual-build-cjs-loads(needs a fullpnpm build) andcheck:lean-entry-closure(needs@objectstack/objectqlbuilt). CI builds the tree. Reason: a built tree was not produced here.dispatch-gates.mjs --ranexit 0, "87 derived famil(ies) accounted for — 85 run, 2 NOT-MEASURED".pnpm --filter @objectstack/spec build:VERDICT command-exit 0. Thenpnpm --filter @objectstack/spec check:generated: "All 15 generated artifacts are up to date".vitest run --project localonsrc/apiplusscripts/check-error-code-provenance.test.ts: 47 files / 1546 tests passed. The 12 other spec test files that read the ledger: 182 tests passed.pnpm --filter @objectstack/spec typecheck: exit 0. That coverstsc,check:scripts-typecheck, andcheck:test-typecheck("52 file(s) / 246 error(s) / 135 pinned signature(s) held", unchanged).origin/maingained 13 commits after the branch point. None touches the four files. The delta against39ab2940eis exactly them (+70 / −4).Acceptance notes
syncConfig/fieldMappings), and it stays true of them.jobsets that)." This describes the design; the corrected clause says nothing schedules a pull until thejobstage lands.connectorSource. Thelive+authorWarnrow reachesdescribe()'s sentinel throw, soos validate/os buildstop with an internal lint error, and the runtime door answersauthoring-rule-threw, instead of warning on an authoredconnectorSource. The comments inauthoring-rules.tsandruntime-gate.inert-type-writes.test.tsstill say it warns. The fix is a choice for its own card: teachdescribe()a caveat branch forlive, or change the row.turbo2.11.5 editsAGENTS.md. It arrived with the development-dependencies bump (840ec9dab, now onmain). On every turbo invocation it sees as an AI agent's, it appends a managedturborepo-agent-rulesblock toAGENTS.md, a Tier H governed surface, andturbo.jsondeclares noagentGuidance: false. Measured here:pnpm exec turbo run build --filter='@objectstack/lint...'andpnpm check:type-check-debteach leftM AGENTS.md, +11 lines. Each time it was restored withgit checkout HEAD -- AGENTS.md(blobe9e211fc= HEAD) and never committed. An agent that commits with-awould carry it into its PR.Generated by Claude Code