fix(mt#4901): Credit an inline gloss, and resolve a truncated ref from contextRefs - #3571
Conversation
…m contextRefs Two advisory ask-form-lint checks judged the question body in isolation and fired on asks that already carried the remedy the warning asked for. domain-jargon: a term GLOSSED inline at its first use now suppresses its class. The rule is structural and punctuation-anchored — a parenthetical, or a matched dash-pair apposition, both requiring CLOSURE. An unclosed opener stays a fire, which is what keeps this from suppressing the shape the check exists to catch. Deliberately not a semantic gloss detector: that is the unbounded natural-language axis form-lint.ts:170-176 already records as belonging to embedding rather than regex. unlinkified-reference: the ask's own contextRefs are now a resolution source. A body citing a page by a short id prefix, with the full URL in contextRefs, is reachable — resolving it makes the PERSISTED body carry the URL, which is mt#2918's actual goal, and the warning then falls silent as a consequence rather than by exemption. The fix is at the TEXT, not at the check, per the decision recorded at asks.ts:1239-1254; FormLintInput gains no field. Harvesting is scoped to Notion-hosted URLs so a truncated cue can never resolve against a Minsky entity id of the same shape, and an ambiguous prefix resolves to nothing rather than guessing. Replayed over the real 51-record corpus: 2 cleared (exactly the two measured false positives), 4 still firing (the true positives preserved), 0 unfetchable. Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_017FKnD9tAMUFGYWg36keBvz
Minsky Reviewer StatusVerdict: APPROVED — no blocking findings Commands
|
There was a problem hiding this comment.
Independent adversarial review (Chinese-wall)
Reviewer: minsky-reviewer[bot] via openai:gpt-5
Tier: 2
One blocking inconsistency remains. The PR correctly adds inline-gloss suppression for domain-jargon and extends linkifyExternalRefs to resolve truncated Notion ids against contextRefs; create-time normalization is wired through normalizeQuestionForLint and tests are comprehensive. However, validateFormLintNotViolated still normalizes with linkifyExternalRefs(question) without supplying knownRefs/contextRefs, so the validation path can still judge against an un-normalized body (particularly via asks.edit), violating SC2’s requirement that the fix live at the TEXT across both call paths. Please update validateFormLintNotViolated to use the same normalization (e.g., call normalizeQuestionForLint or pass knownRefs) so behavior is consistent. Other aspects look solid and tests preserve recall as required; live replay evidence is out-of-repo and was noted as unverifiable.
Findings
- [BLOCKING] src/adapters/shared/commands/asks.ts:1320 — Normalization in
validateFormLintNotViolatedignorescontextRefs, violating SC2 and creating inconsistent behavior across call paths
validateFormLintNotViolatedstill normalizes vialinkifyExternalRefs(params.question)without supplying the ask'scontextRefsas a resolution source. See the code block under the mt#2918 comment where it assignsconst { text: normalizedQuestion } = linkifyExternalRefs(params.question);— this path never consultscontextRefs.
Per the spec (SC2), the normalization step must resolve a truncated Notion id in question against the ask’s own contextRefs and do so at the TEXT layer in both call paths. While normalizeQuestionForLint was updated to pass knownRefs (and callers like asks.create correctly use it), the validation path here remains out of sync, meaning:
- In
asks.create’svalidatehook (which callsvalidateFormLintNotViolated(normalizeQuestionForLint(params))), the missingknownRefsis masked by the prior normalization — but this function’s own contract (“normalizes on its own path too”) remains unfulfilled. - In other call sites that invoke
validateFormLintNotViolateddirectly (e.g.,validateEditFormLintAgainstExistingAskforasks.edit), the same truncated-id-in-body + URL-in-contextRefscase will still be judged against an un-normalized body, reintroducing the false-positive the PR claims to fix.
Fix: thread contextRefs (or precomputed knownRefs) into this normalization path — either by calling normalizeQuestionForLint here (recommended for parity) or by passing { knownRefs } to linkifyExternalRefs so this function’s normalization is consistent with the create path. This also aligns the implementation with the spec’s explicit requirement that the fix live at the text, not in the checker, across both call paths.
Spec verification
| Criterion | Status | Evidence |
|---|---|---|
SC1 — domain-jargon does not fire when the term is glossed inline at first use via a punctuation-anchored apposition (parenthetical or matched dash-pair). The rule is structural, not semantic. |
Met | packages/domain/src/ask/form-lint.ts:170-214 adds INLINE_GLOSS_PATTERN and firesUnglossed(), and computeFormLintMatches() now uses firesUnglossed(question, ...) for all three jargon classes instead of bare .test(...) (packages/domain/src/ask/form-lint.ts:733-744 → 768+). New tests in packages/domain/src/ask/form-lint.test.ts add AT1 and related negatives (lines ~700-795 in diff) demonstrating suppression on first-use gloss and preserved recall on unglossed cases. |
SC2 — A bare artifact id in question whose URL already exists in contextRefs is resolved and linkified BEFORE persistence. The fix is at the TEXT (normalization) not at the check; do NOT add contextRefs to FormLintInput; do NOT modify the unlinkified-reference matcher itself. Also, both normalization call sites (create path and validation path) should apply the same transform. |
Not Met | Met in part: (a) linkifyExternalRefs now accepts knownRefs and can resolve truncated Notion ids against Notion URLs in contextRefs (packages/domain/src/ask/external-refs.ts:113-176, 214-247), and (b) the create path uses normalizeQuestionForLint to pass contextRefs (src/adapters/shared/commands/asks.ts:1058-1090 and 2062-2075). Not met for the validation path: validateFormLintNotViolated still normalizes via linkifyExternalRefs(params.question) with NO knownRefs (src/adapters/shared/commands/asks.ts around the const { text: normalizedQuestion } = linkifyExternalRefs(params.question); line). Per the spec, this call site should use the same normalization (either normalizeQuestionForLint or linkifyExternalRefs(..., {knownRefs})) so the persisted body and the validated body match. The unlinkified-reference branch remained unmodified and FormLintInput was not extended — both as required. |
SC3 — Recall preserved: a bare decision-record reference with no gloss still fires, and a bare artifact id with no matching contextRefs still fires. |
Met | Negative-control tests were added and pass: packages/domain/src/ask/form-lint.test.ts includes two AT3 cases where unglossed ADR references still fire, and packages/domain/src/ask/external-refs.test.ts includes an AT2 negative control showing unlinkified still reported when no refs are supplied. The unlinkified-reference matcher itself is unchanged (packages/domain/src/ask/form-lint.ts near the linkifyExternalRefs(question) call), preserving recall absent normalization. |
SC4 — Replay over the real calibration corpus: all 5 lifetime domain-jargon and the 1 unlinkified-reference record re-judged, with before/after verdicts recorded. |
Unverifiable | A new script scripts/replay-ask-form-lint-calibration.ts was added to perform the replay, but the criterion requires the re-judged results, which live outside the repo. The PR body references an out-of-repo path ~/.local/state/minsky/.../ask-form-lint-calibration.jsonl and shows sample output; this reviewer cannot fetch or verify those live-run results from the diff alone. |
Documentation impact
- no-update-needed — Internal behavior changes to form-lint normalization and linkification; no public CLI surface or documented contract appears to change. I checked only code comments and in-file docs; no separate docs/ files were modified by this PR. If there is a doc describing ask-form-lint semantics, it was not included in the diff and I did not scan the entire docs tree in this round.
…hared seam The reviewer was right, and the finding is stronger than "inconsistent": it was a false HARD-REJECT on the asks.edit surface. validateFormLintNotViolated called linkifyExternalRefs(params.question) bare, so it resolved nothing against contextRefs. The create path masked that — its caller already normalizes — and the edit path did not: validateEditFormLintAgainstExistingAsk fetches the existing ask (contextRefs included) and passed everything BUT them. That surface is where it bites, because unlinkified-reference is advisory but portal-no-link BLOCKS: an authorization.approve question naming a portal action with no URL is exactly a question whose only citation is a page id the transform was about to resolve. mt#2918's originating case, reintroduced on the one call site it had not been checked on. - validateFormLintNotViolated takes contextRefs and normalizes via normalizeQuestionForLint, fulfilling its own docblock's "normalizes on its own path too" rather than only claiming it. - validateEditFormLintAgainstExistingAsk passes existing.contextRefs. Negative control: with the bare call restored, the new edit test is rejected with "portal-no-link: portal action with no direct link"; with the seam, it passes. Class scan: these were the only two remaining sites. createAskWithFormLint and the asks.create validate hook already route through normalizeQuestionForLint, and form-lint's own re-run is covered by harvesting candidates from the text. Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_017FKnD9tAMUFGYWg36keBvz
There was a problem hiding this comment.
Independent adversarial review (Chinese-wall)
Reviewer: minsky-reviewer[bot] via openai:gpt-5
Tier: 2
R2 verification: the prior blocking issue remains. The create path now threads contextRefs into normalization via normalizeQuestionForLint and tests look solid, and SC1/SC3 are met. However, validateFormLintNotViolated still normalizes with linkifyExternalRefs(question) without supplying knownRefs/contextRefs, so the validation/edit path can still misjudge a truncated Notion id whose full URL is present in contextRefs. This violates SC2’s requirement that the fix live at the text across both call paths. Please update validateFormLintNotViolated to use the same normalization (e.g., call normalizeQuestionForLint or pass { knownRefs }) to restore parity. Live-replay evidence (SC4) remains unverifiable from the diff but is not blocking. No new defects beyond this inconsistency were found.
Findings
- [BLOCKING] src/adapters/shared/commands/asks.ts:1239 — Validation path still normalizes without
contextRefs, leaving SC2 unmet and creating inconsistent behavior across call paths
InvalidateFormLintNotViolated, normalization still callslinkifyExternalRefs(params.question)without passingknownRefsderived from the ask’scontextRefs(src/adapters/shared/commands/asks.ts:1233-1248; specificallyconst { text: normalizedQuestion } = linkifyExternalRefs(params.question);).
Per SC2, the normalization must resolve a truncated Notion id in question against the ask’s own contextRefs at the TEXT layer, and crucially it must do so across BOTH call paths (create and validation) to avoid false positives on edits and any other direct consumer of this validator. While normalizeQuestionForLint was updated to pass knownRefs and the asks.create path now uses it, the validation path remains out-of-sync, so:
asks.edit(which invokesvalidateEditFormLintAgainstExistingAsk→validateFormLintNotViolated) can still judge against an un-normalized body when the body contains a truncated Notion id and the URL is present incontextRefs.- This silently reintroduces the exact unlinkified false-positive the PR intends to eliminate.
Fix: Either (a) have validateFormLintNotViolated call normalizeQuestionForLint({question, contextRefs}) so both paths share identical normalization logic, or (b) pass { knownRefs } to linkifyExternalRefs here by harvesting contextRefs alongside question from the same input. This preserves the recorded decision to fix at the text, not in the checker, and aligns both call paths.
Spec verification
| Criterion | Status | Evidence |
|---|---|---|
SC1 — domain-jargon does not fire on a term that is glossed inline at its first use in question via a punctuation-anchored apposition (parenthetical or matched dash-pair). Rule is structural, not semantic. |
Met | packages/domain/src/ask/form-lint.ts:154-214 adds INLINE_GLOSS_PATTERN and firesUnglossed(), and compute path at packages/domain/src/ask/form-lint.ts:768-777 switches the three jargon checks to firesUnglossed(...). Tests in packages/domain/src/ask/form-lint.test.ts:696-790 cover AT1/AT3/AT4 and related negatives, demonstrating suppression on first-use gloss and preserved recall. |
SC2 — A bare artifact id in question whose URL already exists in contextRefs is resolved and linkified before persistence, at the TEXT layer; no FormLintInput changes; do not modify the unlinkified-reference matcher; both normalization call paths (create and validation) apply the same transform. |
Not Met | Create path: Met — normalizeQuestionForLint now harvests contextRefs and passes { knownRefs } to linkifyExternalRefs (src/adapters/shared/commands/asks.ts:1102-1114), and asks.create validate uses normalizeQuestionForLint(params) (asks.ts:2506-2515). Validation path: Not Met — validateFormLintNotViolated still re-normalizes with linkifyExternalRefs(params.question) WITHOUT knownRefs (asks.ts:1233-1248 region; specifically the line const { text: normalizedQuestion } = linkifyExternalRefs(params.question);). asks.edit relies on this function (asks.ts:1705-1731), so truncated-id + URL-in-contextRefs remains misjudged on that path. |
SC3 — Recall preserved: a bare decision-record reference with no gloss still fires; a bare artifact id with no matching contextRefs still fires. |
Met | unlinkified-reference matcher remains unchanged in packages/domain/src/ask/form-lint.ts (call site still delegates to linkifier; no suppression). Negative controls in packages/domain/src/ask/external-refs.test.ts ("AT2 negative control") and packages/domain/src/ask/form-lint.test.ts (two AT3 tests around lines 730-760) confirm recall is preserved when no gloss/refs are present. |
SC4 — Replay over the calibration corpus: all 5 domain-jargon and the 1 unlinkified-reference lifetime records re-judged with before/after verdicts recorded. |
Unverifiable | scripts/replay-ask-form-lint-calibration.ts was added and emits the required replay, but the results are produced from an out-of-repo corpus path (see PR body: ~/.local/state/minsky/.../ask-form-lint-calibration.jsonl). This review cannot fetch or run the live replay; evidence remains the script implementation rather than recorded outputs. |
Documentation impact
- no-update-needed — This PR changes internal normalization behavior and advisory lint behavior for asks; no new public CLI flags or command contracts were added, and existing command shapes remain the same. No docs/ files were modified in the diff, and the changes align with an existing recorded decision (mt#2918) rather than introducing new user-visible options. I did not find any specific docs describing
ask-form-lintnormalization semantics to update.
There was a problem hiding this comment.
Independent adversarial review (Chinese-wall)
Reviewer: minsky-reviewer[bot] via openai:gpt-5
Tier: 2
Re-verified the prior BLOCKING finding: the edit path was normalizing without considering contextRefs, leading to a false hard-reject. The latest commit threads contextRefs through the shared normalization seam and updates validateFormLintNotViolated to use normalizeQuestionForLint, aligning create and edit. Tests were added to assert the non-reject when a truncated Notion id is resolvable via contextRefs and reject otherwise. I found no new critical defects introduced by this fix. Spec criteria SC1–SC3 are met; SC4’s live-replay evidence is out-of-repo and thus unverifiable here. Documentation impact is none. Verdict: APPROVE.
Spec verification
| Criterion | Status | Evidence |
|---|---|---|
| domain-jargon does not fire on a term that is glossed inline at its first use in question. The rule must be structural and punctuation-anchored — an em-dash or parenthetical apposition immediately following the term — and must be written down rather than left to the matcher's incidental behavior. Do NOT build a semantic gloss detector. | Met | The structural-gloss handling shipped earlier in this PR (packages/domain/src/ask/form-lint.ts and its tests) remains in place; no regressions introduced by this fix commit. New changes do not touch that branch. Live tests referenced in the PR body show AT1/AT3/AT4 passing; this fix commit is edit-surface normalization only. |
| A bare artifact id in question whose URL the ask already carries in contextRefs is resolved and linkified before the body is persisted, so unlinkified-reference stops firing as a consequence rather than by being taught to look away. The fix belongs at the TEXT, not at the check; extend linkifyExternalRefs with the ask's own refs as a resolution source, and thread it through normalizeQuestionForLint and both create/edit validation paths. Do NOT add a contextRefs field to FormLintInput. | Met | src/adapters/shared/commands/asks.ts:1061-1072 extends normalizeQuestionForLint to accept contextRefs and passes knownRefs into linkifyExternalRefs. src/adapters/shared/commands/asks.ts:1269-1287 now normalizes via normalizeQuestionForLint(params) instead of calling linkifyExternalRefs bare. src/adapters/shared/commands/asks.ts:2064-2071 threads existing.contextRefs into validateFormLintNotViolated for the edit path. Tests at src/adapters/shared/commands/asks-edit-form-lint.test.ts:219-261 assert non-reject when URL is carried in contextRefs and reject when absent. No changes were made to FormLintInput (out of file scope) or to the unlinkified-reference check itself. |
| Recall preserved, load-bearing: a bare decision-record reference with no gloss still fires, and a bare artifact id with no matching contextRefs entry still fires. | Met | Negative-control tests are present per PR body; this fix commit adds only normalization plumbing and does not relax filterBlockingFormLintMatches nor computeFormLintMatches. The added negative-control test at src/adapters/shared/commands/asks-edit-form-lint.test.ts:247-261 explicitly expects rejection when no contextRefs URL is available. |
| Every one of the 5 lifetime domain-jargon records and the 1 unlinkified-reference record is re-judged against the change, with the before/after verdict recorded. | Unverifiable | Live replay evidence is described in the PR body under “Live verification,” but the replay script output and calibration log path are out-of-repo (~/.local/state/...). The diff adds no repo artifact proving the live run. Per constitution, out-of-repo claims are unverifiable here. |
Documentation impact
- no-update-needed — Change is a bugfix to internal normalization and validation paths for asks.edit and ask form-lint plumbing. No new commands, flags, or user-facing contract changes; behavior aligns both paths with existing documented intent (normalize text before lint). No docs in-repo appear to describe the prior inconsistent edit-surface behavior.
There was a problem hiding this comment.
Independent adversarial review (Chinese-wall)
Reviewer: minsky-reviewer[bot] via openai:gpt-5
Tier: 2
Verification pass: the prior BLOCKING issue (validation path normalizing without contextRefs) is addressed. validateFormLintNotViolated now normalizes via the shared normalizeQuestionForLint(params) seam and validateEditFormLintAgainstExistingAsk threads existing.contextRefs, aligning create and edit semantics. SC1 and SC3 remain satisfied; SC2 is now satisfied across both call paths; SC4 remains unverifiable from the diff due to out-of-repo corpus. I found no new critical defects introduced by the fix. Tests cover the added behaviors, and the unlinkified check remains unmodified per spec. Approving this iteration.
Spec verification
| Criterion | Status | Evidence |
|---|---|---|
SC1 — domain-jargon does not fire on a term that is glossed inline at its first use in question. The rule must be structural and punctuation-anchored (parenthetical or matched dash-pair), not semantic. |
Met | packages/domain/src/ask/form-lint.ts:154-214 adds INLINE_GLOSS_PATTERN and firesUnglossed(question, pattern); packages/domain/src/ask/form-lint.ts:768-777 switches the three jargon checks to firesUnglossed(...). Tests covering AT1/AT3/AT4 and negatives are added at packages/domain/src/ask/form-lint.test.ts:696-790. |
SC2 — A bare artifact id in question whose URL already exists in contextRefs is resolved and linkified before persistence at the TEXT layer; no FormLintInput changes; do not modify the unlinkified-reference matcher; both normalization call paths (create and validation) apply the same transform. |
Met | src/adapters/shared/commands/asks.ts:1058-1114 updates normalizeQuestionForLint to harvest contextRefs and pass { knownRefs } to linkifyExternalRefs. src/adapters/shared/commands/asks.ts:1217-1271 updates validateFormLintNotViolated to normalize via normalizeQuestionForLint(params) (threading contextRefs) instead of calling linkifyExternalRefs bare. src/adapters/shared/commands/asks.ts:2034-2064 threads existing.contextRefs into validateEditFormLintAgainstExistingAsk. unlinkified-reference branch in packages/domain/src/ask/form-lint.ts remains unmodified. Tests asserting create/edit behavior added at src/adapters/shared/commands/asks.external-refs.test.ts:131-207 and src/adapters/shared/commands/asks-edit-form-lint.test.ts:178-240. |
SC3 — Recall preserved: a bare decision-record reference with no gloss still fires; a bare artifact id with no matching contextRefs still fires. |
Met | The domain-jargon checks now use firesUnglossed(...) which still fires when there is no gloss (packages/domain/src/ask/form-lint.ts:768-777). Negative-control tests in packages/domain/src/ask/form-lint.test.ts around lines 731-760 assert bare ADR still fires; packages/domain/src/ask/external-refs.test.ts adds “AT2 negative control” confirming that without knownRefs the body still reports unlinkified. |
SC4 — Replay over the calibration corpus re-judges all 5 domain-jargon and the 1 unlinkified-reference lifetime records with before/after verdicts recorded. |
Unverifiable | scripts/replay-ask-form-lint-calibration.ts implements the replay, but it reads from an out-of-repo path resolved via resolveCalibrationLogDir or --log. The corpus path cited in the PR body is ~/.local/state/minsky/.../ask-form-lint-calibration.jsonl, which this review cannot access; live outputs are not present in the diff. |
Adoption sweep
| Symbol | Kind | Consumers found | Classification | Notes |
|---|---|---|---|---|
| collectNotionIdsFromUrls | function | packages/domain/src/ask/external-refs.test.ts:line ~222 — imports and asserts extraction from Notion URLs | Adopted | New helper exported from packages/domain/src/ask/external-refs.ts; currently used in tests to verify behavior. No production consumers required by spec. |
Documentation impact
- no-update-needed — The PR refines internal lint behavior and text normalization for asks without changing public command shapes, flags, or user-facing APIs. No docs files were modified, and the behavior aligns with an existing recorded design (normalize at the text layer per mt#2918). I checked for docs describing ask-form-lint or asks.create/asks.edit contracts in-repo and found no specific prose that would be invalidated by these internal adjustments.
Summary
Two advisory
ask-form-lintchecks judged thequestionbody in isolation, so both fired on asksthat already contained the remedy the warning asked for. Measured in the 2026-09-02
/calibration-reviewwindow (8 unreviewed records, 9 matches): 2 of the 5 false positives were these.domain-jargonwarned "say what it means, or move the reference to contextRefs" on ask#10650,whose first sentence read "Decide whether ADR-042 — the record of which planning gates get a
mechanical backstop — should be marked Accepted." The author said what it means, in the same
clause. Its
metadata.formWarningDispositionrecords the rebuttal contemporaneously, includingthe second half: ADR-042 is the decision's SUBJECT, so the "move it" branch was unavailable too.
unlinkified-referencewarned "the reader cannot open them from the ask. Supply the fullURL" on ask#10647, which cited
Notion 34f937f0in the body and carriedhttps://app.notion.com/p/34f937f03cb48108a95bdf3813f5ca84incontextRefs— the full URL forthat exact id. The two checks gave contradictory advice because neither could see what the other
recommended.
Key changes
domain-jargoncredits an inline gloss at first use (form-lint.ts). The rule is structuraland punctuation-anchored — a parenthetical, or a matched dash-pair apposition — and requires
CLOSURE. An unclosed opener ("ADR-042 — required measuring its trigger") stays a fire, which is
what stops the rule from suppressing the shape the check exists to catch. Deliberately not a
semantic gloss detector:
form-lint.ts:170-176already records that an unbounded natural-languagesurface is the axis ADR-024 assigns to embedding rather than regex.
The ask's own
contextRefsbecome a resolution source (external-refs.ts,asks.ts). Atruncated cued id that is a unique prefix of a Notion URL the ask carries is resolved and the URL
appended, so the persisted body gains a working link.
Two design constraints worth calling out, because they were the whole planning finding:
asks.ts:1239-1254(mt#2918, PR feat(mt#2918): Make external artifact citations in ask bodies reachable #2755 R1) alreadydecided this: "any present or future check that reads for a URL inherits the same mismatch, so
the fix belongs at the text, not at the check."
FormLintInputtherefore gains no field, andthe
unlinkified-referencebranch itself is unmodified. Teaching the check to look away wouldhave silenced the warning while leaving the body unreadable — defeating mt#2918's stated goal that
"every downstream reader … carries the URL rather than a bare page id."
id are the same shape, so a candidate set built from every id-shaped run could resolve a truncated
cue against a Minsky entity and append a dead URL. An ambiguous prefix resolves to nothing rather
than guessing.
Idempotence across both call paths is carried by harvesting candidates from the text itself as well
as from
contextRefs:computeFormLintMatchesre-runs the transform with no options over thealready-normalized question, and without that second source it would re-report a reference the
normalization step had just fixed.
scripts/replay-ask-form-lint-calibration.tsreplays the corpus against the current matchers. Itlabels each row with body provenance (
as-filed/original-content/edited-since) because anask body is mutable — mt#3584 lost a real false positive to exactly that conflation.
Testing
Execution evidence:
SC1 + SC2 + SC3 — 17 new tests, 100 pass / 0 fail across the three suites (
bun test packages/domain/src/ask/external-refs.test.ts packages/domain/src/ask/form-lint.test.ts src/adapters/shared/commands/asks.external-refs.test.ts):AT1 = the first row; AT2 = the
linkifyExternalRefsrows plus thecreateAskWithFormLintrows (which read the PERSISTED question back out of the repository, so they assert the URL is in the
body rather than only that the warning fell silent — the rejected fix shape would pass the weaker
assertion); AT3 = the two "still fires" rows; AT4 = the possessive row.
No regression across the ask family — 950 pass / 0 fail across 52 files, including
form-lint.jargon-and-lede.test.ts(the mt#4516 suite that owns this check):Typecheck — 0 errors across 8 projects (
.,packages/domain,packages/shared,services/reviewer,services/site,src/cockpit/web,tsconfig.hooks.json,tsconfig.scripts.json). Lint — 0 errors, 0 warnings over 4324 files.Negative control: reverted all three source files (
external-refs.ts,form-lint.ts,asks.ts) viagit stash push, leaving the tests in place, and observed the new tests FAIL.Reported honestly rather than as a clean 17-for-17: the
external-refs.test.tsfile does not LOADagainst the pre-fix tree (it imports a symbol the fix introduces), so its 6 tests are unrunnable
there rather than failing. The 4 named failures are the real control. Note also that the
recall-floor tests (AT3, AT4) pass both before and after — correct, since they must not change.
This is a full revert of the fix, not a one-line revert (mt#4512).
Live verification
AT5 / SC4 — replayed over the real 51-record corpus at
~/.local/state/minsky/projects/a0809beec3ba7e98/ask-form-lint-calibration.jsonl, against the liveask store:
cleared: 2 are exactly the two matches classified false in the calibration window. still
fires: 4 are the three true positives plus ask#10647's
ask-kind nameclass, which the passclassified uncertain and this change deliberately does not touch. 0 unfetchable, so every record
was actually re-judged.
[edited-since]on ask#10650 is the honest label: that ask was edited after its record, and theedit touched
metadataonly (itseditHistoryrecordsfields: ["metadata"]), so the replayedquestion is the judged text.
One thing the replay could not do from this session:
resolveCalibrationLogDirkeys on thecurrent working directory, so run from a session workspace it resolves to that workspace's own empty
project key. That is mt#4885, which already owns the general fix; the script takes an explicit
--logoverride rather than re-solving it here, and refuses to silently report a clean zero.Deploy verification
isDeploySurfaceFilereturns true for 6 of the 7 changed files — run over this diff, notSo this is a deploy-surface PR and no
[no-deploy-impact]claim is made. Post-merge I will rundeployment_wait-for-latestwithnotBeforeset to the merge timestamp andexpectCommitShasetto the merge commit, and read
buildIdentityrather than treating SUCCESS alone as verification.No new external-system integration: no new permission, scope, credential, outbound host, or webhook.
Notes
missing-force-immediatein the same file — adjacentbranches, different causes. Not merged into this change; that task additionally carries a reserved
SEVERITY_TRANSPORT_CHECK_KINDSquestion for the operator.src/adapters/shared/commands/asks.ts. Verified line-disjointagainst its real diff: 8 single-line edits (an import plus seven catch-block
error:lines), noneinside
normalizeQuestionForLint,validateFormLintNotViolated, orcreateAskWithFormLint.Whoever lands second rebases.
src/cockpit/sweepers.test.ts > an overrunning tick is not run concurrently with the next tick (mt#4335)(maxInFlight2 vs 1). It passes 3/3 in isolation and passed on the gated re-run thatlet this push through; it fails only under the 64-file parallel partition. Not caused by this diff
— no file it touches is in this change — and no task currently owns it.
🤖 Generated with Claude Code
https://claude.ai/code/session_017FKnD9tAMUFGYWg36keBvz