fix(spec): a stack whose mapping authors connectorSource validates and lints again — the live ledger row carries no author warning (#21127) - #21176
Conversation
…`authorWarn` The author-side lint's describe() throws on a warned `live` row by design, which turns `os validate` / `os lint` into exit 1 for every stack that authors the key. The graded walk never reads a container row that drills into `children`, so the gate now walks the raw rows at every depth, refuses the combination, and prints the warned-row census every run. Red at this commit on purpose: the shipped `mapping.connectorSource` row is the one offender, re-graded in the next commit. Claude-Session: https://claude.ai/code/session_017VaLJnYwhPsanVCe9dMCJU Co-authored-by: Claude <noreply@anthropic.com>
…arning, so `os validate` / `os lint` judge a stack that authors it The liveness lint has no verdict for a warned `live` row and throws its ledger-integrity error, which made both commands exit 1 on every stack whose mapping authors the binding. The row drops `authorWarn` / `authorHint`; the caveat they carried (nothing schedules a pull until a job can drive one) moves to the key's description. The retired `connector.syncConfig` prescription, the `connector-sync-keys-retired` upgrade entry (registry regenerated), SYNC_ARCHITECTURE.md, the ledger README, the pending connector-source changeset and two lint comments no longer say authoring the binding warns. Pins: the spec ledger pin now asserts no row of the binding warns; the lint suite and the runtime door judge the card's binding silent, with a warned `planned` row still warning as the control; a CLI integration test runs the fixture through `os validate --json` / `os lint --json` (exit 0). Claude-Session: https://claude.ai/code/session_017VaLJnYwhPsanVCe9dMCJU Co-authored-by: Claude <noreply@anthropic.com>
… the connectorSource description Claude-Session: https://claude.ai/code/session_017VaLJnYwhPsanVCe9dMCJU Co-authored-by: Claude <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_017VaLJnYwhPsanVCe9dMCJU Co-authored-by: Claude <noreply@anthropic.com>
…nnector-source-live-row
📓 Docs Drift CheckThis PR changes 2 package(s): 1 hand-written doc(s) NAME something this change touched and may need an implementation-accuracy re-verification:
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 b6ed1851f47fad8414e834a77d9f453750c82426 && git checkout b6ed1851f47fad8414e834a77d9f453750c82426
# afterwards, rebuild it from the two parents, which stay fetchable
git fetch origin d34aa58a2affc87ded426dc6a326edb03534cb62 b6d58dd04427126553d781fc78e05778642bee65 && git checkout -B drift-repro d34aa58a2affc87ded426dc6a326edb03534cb62 && git merge --no-ff b6d58dd04427126553d781fc78e05778642bee65
node scripts/docs-audit/affected-docs.mjs --json d34aa58a2affc87ded426dc6a326edb03534cb62
|
Contract reviewServed-tier: Rendered at 2026-10-01T13:11Z by an isolated reviewer subagent of the ① Derived judgmentsAccept set and public surface, item by item:
Check-runs on the head, read at 2026-10-01T13:09Z: 33 runs. 20 success, 2 skipped as expected ( ② Semver level
③ Boundary flags
The seat's question 4: the Nothing escalated: the diff forks no product semantics and no public contract shape; correcting a pending note is the ruled in-seat path. Implemented-by: VERDICT: PASS Generated by Claude Code |
|
Designed red, recorded before enqueue ·
Generated by Claude Code |
Fixes #21127
Clause-②: no
What this changes
os validate --jsonandos lint --jsonexited 1 on any stack whosemappings[]entry authorsconnectorSource. The whole answer was the liveness lint's integrity sentinel:lintLivenessProperties: ledger entry has unrecognised status "live". The ledger rowmapping.connectorSourcehad been re-gradedliveand keptauthorWarn: true.describe()inpackages/lint/src/lint-liveness-properties.tsthrows on a warnedliverow by design, and that throw stays as it is.packages/spec/liveness/mapping.json):connectorSourcestaysliveand dropsauthorWarn/authorHint. Itsnoterecords why.packages/spec/src/data/mapping.zod.ts). TheconnectorSource.describe()now reads: "Pulled when a job drives it; nothing schedules it yet, so the binding alone moves no rows — schedule the pull with ajobonce a job can drive one". The docblock no longer says the ledger keepsauthorWarn.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 intochildren, andconnectorSourceis such a row, so the new rule walks the raw ledger rows at every depth. It fails onstatus: "live"withauthorWarn: 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.content/docs/references/data/mapping.mdxandintegration/connector.mdx(gen:docs), andpackages/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
connectorSourcedescribe, 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 retiredconnector.syncConfigprescription, 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.tsis 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: "authoringconnectorSourcestill warns".packages/spec/liveness/README.md: the mapping row's note, plus a thirdauthorWarnrule (aliverow 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. Amappingwrite that authorsconnectorSourceused to get anauthoring-rule-threwadvisory 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..changeset/20919-spec-connector-source-live.mdbelongs to PR #21084. It has not been released yet, and it said "connectorSourcerows areliveand keepauthorWarn". This PR makes that false, so the sentence now reads "rows arelive, 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/mainis 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, andskip-changesetis not applied..changeset/20281-connector-sync-moved-to-mapping.mdcarried a similar claim. PR #21150 has since rewritten it onmainwithout the warn claim, and this PR does not touch it.Premise check
665cab338f, which contains PR feat(lint): a ledger-dead or live-elsewhere key warns without an authorWarn opt-in, and never shows the ledger note (#16094) #21092b616c0a63d). The card's fixture is one objectfx_accountwithsharingModel: 'private', plus one mapping withsourceFormat: 'json',targetObject: 'fx_account',mode: 'upsert', afieldMappingandconnectorSource: { connector: 'crm_api', action: 'request' }.os validate --jsonandos lint --jsonboth exited 1, and the only error was the sentinel.b6d58dd04:validateexits 0 with"valid": true.lintexits 0 with"passed": trueand one unrelated warning (protocol/missing-engines-range). Neither output namesconnectorSourceor contains the sentinel.sharingModel, the same object getssecurity-owd-unset, so the fixture declares it.check:liveness. Run against the unfixed ledger, the gate exits 1 with exactly one ✗ block: "1liveledger row(s) opt intoauthorWarn— the author-side lint throws on them: mapping/connectorSource".authorWarn: true, bothplanned(object.externalSharingModel,translation.flows). None islive. Before the fix,mapping.connectorSourcewas the onlyliveone, so no other row has this defect.Pins
packages/spec/src/data/mapping-connector-source.test.ts: every key of the binding islive, and no row of it, at any depth, carriesauthorWarn/authorHint. The description still says nothing schedules a pull. The old assertionauthorWarn === truepinned the defect.packages/spec/scripts/liveness/check-liveness.test.tsruns the real gate via--ledger-root:plannedrows and none on aliverow (the control);livecontainer row withchildrenopts in (the regression's shape);livechild opts in.packages/lint/src/lint-liveness-properties.test.tsruns against the real ledger. The card's fixture lints without throwing and draws noconnectorSourcefinding. Control:object.externalSharingModel(planned+authorWarn) still warns asliveness-planned-property.packages/lint/src/runtime-gate.inert-type-writes.test.ts: amappingwrite that authorsconnectorSourcegets no errors and no advisories at the runtime door.packages/cli/test/validate-lint-mapping-connector-source.test.tsis in the integration tier and spawns the CLI:os validate --jsonexits 0 withvalid: true, andos lint --jsonexits 0 withpassed: true;externalSharingModelproduces aliveness-planned-propertywarning, 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 themainmerge atb6d58dd04.node scripts/ablation-replace.mjsput"authorWarn": trueback on theconnectorSourcerow. The anchor count went 1 → 0, and the blob changed49cc72e394b8→65665b90b21d. With the defect back, every leg went red:validateexit 1 andlintexit 1, with the sentinel in both;check:livenessexit 1 (1 on a live row — FORBIDDEN);The tool restored the file and proved it: the blob equals HEAD and
git diff HEADis empty. The ledger is read frompackages/spec/liveness/at runtime, not fromdist/, so no rebuild was involved.Verification (all at
b6d58dd04, the PR head)origin/mainfde553c50was merged in withbash scripts/pm/os-regen-merge.sh. The merge was clean.registry.tsauto-merged as text, andcheck:migration-registrythen 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:generatedreports all 15 generated artefacts up to date. The delta againstmainis unchanged: 19 files, +538 / −42.pnpm --filter @objectstack/spec buildpnpm --filter @objectstack/spec run check:generatedpnpm exec turbo run build --filter=@objectstack/cli... --concurrency=2os validate --json/os lint --jsonconnectorSource0 timespnpm --filter @objectstack/spec run check:livenessliverow"pnpm --filter @objectstack/spec run check:strictness-ledgervitest run scripts/liveness src/data src/integration/connector-sync-retirement.test.ts src/migrationspnpm --filter @objectstack/spec typecheckpnpm --filter @objectstack/lint exec vitest run+typecheckvitest run --project unit test/lint test/validate src/commands/validate src/commands/lintvitest run --project integration test/validate-lint-mapping-connector-source.test.tspnpm exec eslint --no-inline-config --format jsonon all 19 changed paths.md/.mdx/.json) as "no matching configuration"; 0 errors, 0 warningsdispatch-gates.mjs --commands(117), each run, then--rancheck-empty-changeset --base origin/main, the deliberate correction above.--ran: "117 run, 0 NOT-MEASURED, 0 UNRUN".check:pm-dispatch-gateswas 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 boxThe eslint narrowing is a measurement, not a skip:
eslint.config.mjshas no configuration for.--format jsonoutput.parserOptions.project), so this diff cannot move the verdict on any file it did not touch.Acceptance notes
AGENTS.mdbefore the merge. It appended its managedturborepo-agent-rulesblock on every AI-attributed turbo run in this worktree: 3 builds, and once duringcheck:type-check-debt. Each time the file was restored withgit checkout HEAD -- AGENTS.md, andgit diff HEADwas confirmed empty. Files were staged by path only, so the block was never staged and is not in this PR. PR chore(turbo): opt out of the agent-guidance block in the root turbo.json #21151 (agentGuidance: falseinturbo.json) came in with the merge. Since then,AGENTS.mdstayed unmodified across the 59-task CLI closure build and all 117 gates.@objectstack/lintgets no changeset. Its source change is comments only. Measured: tsup keeps comments, so the comment text does reachdist/*.jsbytes. The seat can override this.os lint/os validatecrash on any stack whose mapping authorsconnectorSource: the ledger row islivewithauthorWarn: true, and the liveness rule throws its integrity sentinel #21127 is cited only where agents and reviewers read: theauthoring-rules.tscomment, and the ledger'snoteand README prose. Author-facing text (.describe(), the retired-key prescription, the upgrade entry) cites no tracker.Generated by Claude Code