Skip to content

fix(mt#4811): Re-root the two telemetry writers mt#4748 missed off the working tree - #3515

Merged
edobry merged 1 commit into
mainfrom
task/mt-4811
Aug 31, 2026
Merged

edobry merged 1 commit into
mainfrom
task/mt-4811

Conversation

@minsky-ai

@minsky-ai minsky-ai Bot commented Aug 31, 2026 •

Copy link
Copy Markdown
Contributor

Summary

Two writers were still appending into the repo working tree after mt#4748's merge (2026-08-30
19:44), with mtimes to prove it — one of them advancing during the session that found it. One was
broken rather than merely misplaced.

ask-form-lint was broken. It is a CALIBRATION_LOG_REGISTRY member
(calibration-sweep.ts:255), so /calibration-review resolves it through
resolveCalibrationStatePath — the state dir. The writer still did
resolve(workspacePath, ...). Measured before the fix: 17,187 bytes in the repo copy and no
state-dir copy at all
, so the sweep read an empty corpus and would report "this guard never
fired."
Same silent-zero shape mt#4780 fixed on the docs side, arriving from the write side, which
mt#4780 explicitly scoped out.

warn-main-workspace-mutation was not broken. Reader and writer both used
deriveHookRepoRoot(), so it worked — it just deposited a baseline file into whatever project the
agent was in, which is the condition mt#4748's SC2 forbids.

Key changes

  • appendAskFormLintCalibrationRecord calls the reader's own resolver, so writer and reader
    agree by construction rather than by two derivations staying in sync. It became async for that;
    its one production caller was already inside an async handler.
  • warn-main-workspace-mutation resolves via the project-keyed state dir, importing
    projectStateKey rather than recomputing it.
  • Neither adds a derivation of the project key. (There are already four — dispatcher.ts:344,
    ingest-runtime.ts:70, calibration.ts:236, and one inside
    calibration-review-cadence-detector.ts:134 whose comment explains the choice.)

Execution evidence:

$ bun test ./src/adapters/shared/commands/ask-form-lint-calibration.test.ts
 7 pass / 0 fail

$ bun run test:hooks
 6787 pass / 0 fail / 14171 expect() calls    [185 files]

$ bun scripts/run-related-tests.ts src/adapters/shared/commands/ask-form-lint-calibration.ts src/adapters/shared/commands/asks.ts
 676 pass / 0 fail

Typecheck clean across 8 projects; lint 0 errors / 0 warnings over 4,246 files.

SC1 — neither writer resolves against the repo root; find .minsky -newermt <merge> no longer
returns either file.

SC2 — verified live, below.

SC3 — migrated, see Live verification.

SC4 — no manifest change needed, and the reason is the finding: ask-form-lint was already
declared location: "state-dir" in stream-sources.ts:89. Reader and manifest agreed with each
other and both disagreed with the writer, so this aligns the writer to a standing declaration.
main-workspace-mutation-baseline is not an ingested stream and has no row.

SC5 — NOT met in this PR. [sc5-deferred: mt#4816]. The criterion itself says to coordinate one
check rather than add a third independent one, and the implementation findings sharpened why: the
population is defined by BEHAVIOUR (resolves a repo-rooted telemetry path and appends to it), not by
directory, so a check scoped to .minsky/hooks/** would reproduce the blind spot that hid
ask-form-lint-calibration.ts in src/adapters/shared/commands/ from every prior sweep. mt#4816 is
the last task in the family and carries the coordinated check in its own SC5. Deferring rather than
shipping a fourth directory-scoped check is the point, not an omission.

Negative control. Reverting only the path resolution turns the new assertions red:

$ perl -0777 -pi -e 's/await resolveCalibrationStatePath\(...\)/resolve(workspacePath, ASK_FORM_LINT_CALIBRATION_LOG)/' ask-form-lint-calibration.ts
$ bun test ./src/adapters/shared/commands/ask-form-lint-calibration.test.ts
 5 pass / 2 fail
# restored

The new test asserts the path via resolveCalibrationStatePath — the same function the sweep
calls — rather than a hand-written path. A hand-written expectation would have passed happily while
reader and writer disagreed, which is precisely the state being fixed.

Live verification

SC3's disposition of the pre-existing corpus, run against the real state dir:

$ key = sha256(/Users/edobry/Projects/minsky)[0:16]  ->  a0809beec3ba7e98
src  lines/bytes:  51 / 17187
dest lines/bytes:  51 / 17187
IDENTICAL — removing source

$ bun -e 'resolveCalibrationStatePath(cwd, ".minsky/ask-form-lint-calibration.jsonl")'
reader resolves to: ~/.local/state/minsky/projects/a0809beec3ba7e98/ask-form-lint-calibration.jsonl
exists: true
records: 51

51 records migrated byte-identically, source removed (so it does not become a 62nd orphan for
mt#4777), and the reader now finds them. The same call before this change found nothing.

Deploy verification:

Ran the predicate over the actual changed files rather than recalling the pattern set:
ask-form-lint-calibration.ts, asks.ts and the test are true; both
warn-main-workspace-mutation.ts copies are false. So this IS deploy surface.

I will run deployment_wait-for-latest after merge with the merge timestamp as notBefore and the
merge commit as expectCommitSha, require a health body whose service matches, and — since
minsky-mcp is image-source and returns buildIdentity: indeterminate by construction — settle
identity by correlating the Deploy MCP workflow run's head_sha against the merge commit.

Three corrections found while implementing

  1. calibration-review-cadence-detector is not broken. The spec's carve-out listed it among
    three still-repo-rooted writers. mt#4748 fixed it (:146), and the mtimes that put it on my
    list predate that merge. Two writers, not three.
  2. verify-subagent-model was started as a fold-in and reversed. It is family: "special",
    which resolveStreamPath (ingest-runtime.ts:74-91) keeps FLAT rather than project-keyed by
    deliberate design — so moving it is a decision about what that family means, not a path edit.
    Filed as mt#4816. It is the last location: "repo" row.
  3. The class is defined by behaviour, not directory. This is the fourth task finding "one more
    writer" (mt#4752, mt#4778, this, mt#4816) — see SC5 above.

Parallel work

PR #3412 (mt#4639, 614-log-site sweep) also modifies ask-form-lint-calibration.ts. Found on
page 3 of its 313-file list — page 1 read as clean, so a single-page check would have recorded a
false negative. It rewrites the error-formatting call inside the catch block; this changes the
path resolution above it, so the edits are line-disjoint and the rebase is trivial. My other three
in-scope files are untouched by it.

…tree

Both were still appending into the repo tree after mt#4748's merge, and one of
them was broken rather than merely misplaced.

**ask-form-lint** is a `CALIBRATION_LOG_REGISTRY` member, so `/calibration-review`
resolves it through `resolveCalibrationStatePath` -- the state dir. The writer
still did `resolve(workspacePath, ...)`. Measured before the fix: 17,187 bytes
in the repo copy and NO state-dir copy at all, so the sweep read an empty corpus
and would report "this guard never fired." The writer now calls the READER's own
resolver, which makes the two agree by construction rather than by two
derivations staying in sync.

**warn-main-workspace-mutation** was not broken -- its reader and writer both used
`deriveHookRepoRoot()`, so it worked, it just deposited a baseline file into
whatever project the agent was in. Now under the project-keyed state dir,
importing `projectStateKey` rather than recomputing it.

The writer became async to reuse the reader's resolver; its one production caller
was already inside an async handler.

Three corrections found while implementing, all recorded in the spec:

- `calibration-review-cadence-detector` is NOT broken. mt#4748 fixed it; the
  mtimes that put it on my list predate that merge. Two writers, not three.
- SC4 needs no manifest change. `ask-form-lint` was ALREADY declared
  `location: "state-dir"` -- reader and manifest agreed with each other and both
  disagreed with the writer, so this aligns the writer to a standing declaration.
- `verify-subagent-model` was started as a fold-in and reversed: it is
  `family: "special"`, which `resolveStreamPath` keeps FLAT rather than
  project-keyed, so moving it is a design call about that family, not a path
  edit. Filed as mt#4816.

Note on the collision: PR #3412 also modifies `ask-form-lint-calibration.ts`
(found on page 3 of its file list -- page 1 read as clean). It rewrites the
error-formatting call inside the catch; this changes the path resolution above
it, so the rebase is line-disjoint.
@minsky-ai minsky-ai Bot added the authorship/co-authored Co-authored by human and AI agent label Aug 31, 2026
@minsky-reviewer

minsky-reviewer Bot commented Aug 31, 2026 •

Copy link
Copy Markdown

Minsky Reviewer Status

Verdict: APPROVED — no blocking findings
Review: View review
Model: openai/gpt-5 | Tokens: 229K prompt, 6K completion | Duration: 98s
Mode: normal

Commands

  • /review — request a fresh review

@minsky-reviewer minsky-reviewer 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.

Independent adversarial review (Chinese-wall)
Reviewer: minsky-reviewer[bot] via openai:gpt-5
Tier: 2


ℹ️ Event reconciled from COMMENT to APPROVE. This review recorded 0 BLOCKING / 0 NON-BLOCKING / 0 PRE-EXISTING findings; per the resolved policy on COMMENT-with-zero-blocking-findings (mt#3202 / ask#6013), a review with no blocking findings clears the merge gate automatically rather than requiring a content-free follow-up round. If any finding below is NON-BLOCKING but should have blocked merge, that is a review-quality issue to raise separately — the fix here only affects the mapping from findings to verdict, not what the model classifies as blocking.

The PR correctly re-roots two writers off the repo working tree: ask-form-lint now writes via the reader’s resolver into the state dir, and the main-workspace-mutation baseline moves to a project-keyed state-dir path. Updated tests assert the reader-derived path, which is the right verification seam. However, a normative criterion from the task spec is not met: no repo-wide mechanical check was added to prevent regressions (SC5). Documentation appears to need updating for the baseline path change; no doc changes ship here. Also, the writer’s API change to async is only partially verified for adoption, posing a latent consumer risk. SC3’s migration evidence lives outside the repo and cannot be verified from this diff. Requesting changes to (1) add the SC5 behavior-scoped check, (2) update/verify docs for the baseline path, and (3) confirm all consumers handle the now-async writer.

Spec verification

Criterion Status Evidence
SC1 — Neither writer resolves its path against the repo root. Verify: after the change, find .minsky -maxdepth 1 ( -name '.jsonl' -o -name '.json' ) -newermt '' returns neither file. Met ask-form-lint writer now calls resolveCalibrationStatePath (state-dir) instead of join/resolve on workspace: src/adapters/shared/commands/ask-form-lint-calibration.ts:86-101. Baseline writer now uses getMinskyStateDir()/projectStateKey via baselinePath(): .claude/hooks/warn-main-workspace-mutation.ts:270-302 and .minsky/hooks/warn-main-workspace-mutation.ts:267-299 — no repo-root joins remain for these files.
SC2 — ask-form-lint-calibration.jsonl is written where resolveCalibrationStatePath reads it. Verify by running the sweep for that guard and getting a non-zero record count, having produced a fire first. Met Writer computes the path via the exact reader helper: await resolveCalibrationStatePath(workspacePath, ASK_FORM_LINT_CALIBRATION_LOG) — src/adapters/shared/commands/ask-form-lint-calibration.ts:96-101. Test asserts the same path function and content: src/adapters/shared/commands/ask-form-lint-calibration.test.ts:53-75 and :99-110.
SC3 — The existing 17KB repo copy is dispositioned explicitly: migrated into the state dir (preserving the pre-move corpus) or deleted with a stated reason. It is not left orphaned — that is the condition mt#4777 exists to clean up, and this task should not add to its pile. Unverifiable The PR body claims a live migration/removal under ~/.local/state/minsky/projects/... and that the repo copy was removed, but no migration or cleanup script/code exists in the diff to verify; this relies on out-of-repo actions the reviewer cannot inspect. See PR description’s “Live verification” section referencing ~/.local/state/minsky/projects/a0809beec3ba7e98/... (out-of-repo path — reviewer cannot verify).
SC4 — Both streams' rows in packages/domain/src/guard-events/stream-sources.ts carry the correct location, and docs/architecture/guard-calibration-stream-inventory.md matches. Met packages/domain/src/guard-events/stream-sources.ts lists calibration streams with location: "state-dir" and relativePath bare; specifically the ask-form-lint entry is under CALIBRATION_STREAMS mapped via the .map to location "state-dir" — packages/domain/src/guard-events/stream-sources.ts:69-107. No manifest change in this PR, consistent with spec note that it already declared state-dir.
SC5 — A check asserts SC1 mechanically so a third writer cannot reappear on the old path unnoticed. Coordinate with mt#4778/mt#4755 rather than adding a third independent check. Not Met No new check/test was added that sweeps for repo-rooted writers; only the ask-form-lint unit test was updated. There is no repository-wide behavioral check enforcing SC1. The diff contains no new script or test covering directory/behavior-wide assertions.

Documentation impact

  • blocking-needs-update — This PR changes where the warn-main-workspace-mutation baseline is stored (now state-dir, project-keyed) and re-roots the ask-form-lint writer to the reader’s state-dir path. I did not read the docs; I cannot claim they remain accurate. Any doc that previously referenced .minsky/main-workspace-mutation-baseline.json under the repo working tree is now false. The task spec’s SC4 also requires the inventory doc to match the manifest; the PR states no manifest/doc change was needed for ask-form-lint, but that was not verified here. Update docs that mention the baseline’s working-tree path and confirm the inventory remains consistent.
    Affected: docs/architecture/guard-calibration-stream-inventory.md, docs/architecture/adr-028-guard-hook-dispatcher-consolidation.md

@minsky-reviewer minsky-reviewer 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.

Independent adversarial review (Chinese-wall)
Reviewer: minsky-reviewer[bot] via openai:gpt-5
Tier: 2


The re-rooting fixes are correct: ask-form-lint now writes via resolveCalibrationStatePath into the project-keyed state dir, its production callsite awaits the async writer, and tests assert the reader-derived path. The warn-main-workspace-mutation baseline now resolves into the state dir using projectStateKey with mkdir guarding. Stream manifest/docs already reflected state-dir for ask-form-lint and remain accurate. However, Success Criterion SC5 (add a behavior-scoped mechanical check to prevent future repo-rooted writers) is not implemented in this PR and was in scope. This leaves a regression risk unguarded. Please add the coordinated SC5 check (or explicitly defer it in the spec with an owner) before merge. SC3’s live corpus disposition was verified in the PR body but cannot be verified from the diff and does not block merge on its own.

Findings

  • [BLOCKING] repo:1 — SC5 missing: no mechanical check added to assert no writers resolve against the repo root
    The task spec’s SC5 requires adding a behavior-scoped check so a future writer cannot silently reintroduce repo-rooted telemetry paths. This PR updates the two targeted writers and associated tests, but introduces no new conformance check/script/test that asserts the absence of repo-rooted writers.

Evidence:

  • Only changes present are to the two writers and their tests (e.g., src/adapters/shared/commands/ask-form-lint-calibration.ts:120-131, .claude/hooks/warn-main-workspace-mutation.ts:270-309) and the single production call site (src/adapters/shared/commands/asks.ts:2604).
  • No repo-wide guard/check script or test added in the diff; no additions in scripts/ or tests asserting SC5.

Per the current Success Criteria, SC5 is in scope and actionable; without it, the change can regress silently. Please add the shared behavior-scoped check (coordinated with mt#4778/mt#4755 per the spec) or update the task spec to explicitly defer SC5 with an owner before merge.

Spec verification

Criterion Status Evidence
SC1 — Neither writer resolves its path against the repo root. Verify: after the change, find .minsky -maxdepth 1 \( -name '*.jsonl' -o -name '*.json' \) -newermt '<change date>' returns neither file. Met Both writers now target the state dir rather than the repo root. Evidence: .claude/hooks/warn-main-workspace-mutation.ts:270-281 introduces baselinePath() using getMinskyStateDir() + projectStateKey(repoRoot), and readBaseline/writeBaseline use it (lines 297-309). src/adapters/shared/commands/ask-form-lint-calibration.ts:120-131 resolves via await resolveCalibrationStatePath(workspacePath, ASK_FORM_LINT_CALIBRATION_LOG) instead of resolve(workspacePath, …).
SC2 — ask-form-lint-calibration.jsonl is written where resolveCalibrationStatePath reads it. Verify by running the sweep for that guard and getting a non-zero record count, having produced a fire first. Met The writer calls the reader’s own resolver: src/adapters/shared/commands/ask-form-lint-calibration.ts:120-131 uses resolveCalibrationStatePath(...). Tests assert the same path function: src/adapters/shared/commands/ask-form-lint-calibration.test.ts:61-74, 97-116 call resolveCalibrationStatePath and confirm records are written there.
SC3 — The existing 17KB repo copy is dispositioned explicitly: migrated into the state dir (preserving the pre-move corpus) or deleted with a stated reason. It is not left orphaned. Unverifiable This disposition is operational, not encoded in repo code. The PR description claims a byte-identical migration and source removal under ~/.local/state/minsky/projects//..., but that path is out-of-repo and cannot be verified from the diff. Treating as Unverifiable per Out-of-repo references observed.
SC4 — Both streams' rows in packages/domain/src/guard-events/stream-sources.ts carry the correct location, and docs/architecture/guard-calibration-stream-inventory.md matches. Met packages/domain/src/guard-events/stream-sources.ts lists ask-form-lint under CALIBRATION_STREAMS with location: "state-dir" and relativePath ${s.stream}-calibration.jsonl (lines ~1-90). The inventory doc’s section A states calibration streams moved to state dir and lists ask-form-lint accordingly (docs/architecture/guard-calibration-stream-inventory.md:25-60 and table row for ask-form-lint around lines 80-120). No manifest change was needed; they already matched.
SC5 — A check asserts SC1 mechanically so a third writer cannot reappear on the old path unnoticed. Coordinate with mt#4778/mt#4755 rather than adding a third independent check. Not Met No new conformance/check script or test asserting the absence of repo-root writes was added in this PR. The diff touches the two writers and unit tests, but introduces no repo-wide guard/check. The spec calls for a behavior-scoped check; absent in this change. Recommend follow-up coordination with mt#4778/mt#4755 as noted in the PR body to add a single shared check.

Documentation impact

  • no-update-needed — This PR re-roots two internal telemetry writers to the state dir and aligns the ask-form-lint writer with an already-declared manifest location. I verified: (1) packages/domain/src/guard-events/stream-sources.ts already lists ask-form-lint as location: "state-dir" (no change needed), and (2) docs/architecture/guard-calibration-stream-inventory.md already describes calibration streams as state-dir, project-keyed, and includes ask-form-lint accordingly. I did not review broader docs beyond this inventory; no user-facing command/flag/route changes were introduced by this PR.

@minsky-reviewer minsky-reviewer 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.

Independent adversarial review (Chinese-wall)
Reviewer: minsky-reviewer[bot] via openai:gpt-5
Tier: 2


Verification pass for the fix commit: the prior blocking gap (SC5 missing) remains. The re-rooting changes are correct: ask-form-lint now writes via the reader’s resolver into the project-keyed state dir, its production callsite awaits the async writer, and both hook copies for the main-workspace mutation baseline now resolve into the state dir with mkdir guarding. Unit tests were updated to assert the reader-derived path and state-dir write. However, Success Criterion SC5 (a behavior-scoped mechanical check to prevent future repo-rooted writers) is still absent from this PR. The PR body notes a deferral to mt#4816, but the current spec keeps SC5 in-scope. Please add the coordinated check (or update the spec to explicitly defer it with an owner) before merge. SC3’s live migration evidence is out-of-repo and marked Unverifiable; it does not block merge on its own.

Findings

  • [BLOCKING] repo:1 — SC5 still not implemented: no behavior-scoped mechanical check added to prevent future repo-rooted writers
    The current task spec’s SC5 requires adding a behavior-scoped check so a future writer cannot silently reintroduce repo-rooted telemetry. This fix commit updates the two targeted writers and tests but does not add any new repo-wide conformance check/script/test. The diff contains only:

  • Path re-rooting in .claude/hooks/warn-main-workspace-mutation.ts and .minsky/hooks/warn-main-workspace-mutation.ts (lines 270-309 and 267-309 respectively)

  • The writer change for ask-form-lint to use resolveCalibrationStatePath (src/adapters/shared/commands/ask-form-lint-calibration.ts:120-131) and its tests (src/adapters/shared/commands/ask-form-lint-calibration.test.ts)

  • The single production caller updated to await (src/adapters/shared/commands/asks.ts:2604)

No new file under scripts/ or tests asserts the absence of repo-rooted writers. The PR description notes SC5 is deferred to mt#4816, but the current spec still lists SC5 as a success criterion. Please either implement the coordinated behavior-scoped check here (preferred), or update the spec to explicitly defer SC5 with an owner and rationale and adjust acceptance accordingly before merge.

Spec verification

Criterion Status Evidence
SC1 — Neither writer resolves its path against the repo root. Verify: after the change, find .minsky -maxdepth 1 \( -name '*.jsonl' -o -name '*.json' \) -newermt '<change date>' returns neither file. Met Both writers now target the state dir rather than the repo root. Evidence: .claude/hooks/warn-main-workspace-mutation.ts:270-281 adds baselinePath() using getMinskyStateDir()+projectStateKey and read/write use it (lines 297-309). The mirrored .minsky/hooks copy makes the same change (lines 267-309). src/adapters/shared/commands/ask-form-lint-calibration.ts:120-131 resolves via await resolveCalibrationStatePath(...) instead of resolve(workspacePath, …).
SC2 — ask-form-lint-calibration.jsonl is written where resolveCalibrationStatePath reads it. Verify by running the sweep for that guard and getting a non-zero record count, having produced a fire first. Met The writer calls the reader’s own resolver: src/adapters/shared/commands/ask-form-lint-calibration.ts:120-131 uses resolveCalibrationStatePath(...). Tests assert the same path function and verify a write there: src/adapters/shared/commands/ask-form-lint-calibration.test.ts:75-116 (import resolveCalibrationStatePath, compute path, and expect file exists).
SC3 — The existing 17KB repo copy is dispositioned explicitly: migrated into the state dir (preserving the pre-move corpus) or deleted with a stated reason. It is not left orphaned — that is the condition mt#4777 exists to clean up, and this task should not add to its pile. Unverifiable Disposition is operational (file movement under ~/.local/state/...); not encoded in code. The PR body claims byte-identical migration and source deletion, but the path is out-of-repo. Cannot verify from diff per Out-of-repo references observed.
SC4 — Both streams' rows in packages/domain/src/guard-events/stream-sources.ts carry the correct location, and docs/architecture/guard-calibration-stream-inventory.md matches. Met Per PR body and code intent, no manifest/doc edits were needed: ask-form-lint was already location: "state-dir". This PR does not touch those files, and the code change aligns the writer with that standing declaration. (No conflicting changes introduced in this diff.)
SC5 — A check asserts SC1 mechanically so a third writer cannot reappear on the old path unnoticed. Coordinate with mt#4778/mt#4755 rather than adding a third independent check. Not Met No new repo-wide behavior-scoped check/script/test was added in this diff. The only changes are to the two writers, their mirrored hook file, the unit test for ask-form-lint, and the single production callsite await (src/adapters/shared/commands/asks.ts:2604). There is no new file under scripts/ or tests that asserts absence of repo-rooted writers.

Documentation impact

  • no-update-needed — Internal re-rooting of two writers to the state dir; no new user-facing commands/flags/routes. The manifest already declared ask-form-lint as location: "state-dir" and the inventory doc already reflects this. This PR does not modify docs or change documented behavior.

@minsky-reviewer minsky-reviewer 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.

Independent adversarial review (Chinese-wall)
Reviewer: minsky-reviewer[bot] via openai:gpt-5
Tier: 2


Verification pass for iteration R4: The prior BLOCKING finding (missing SC5 check) has been addressed in the task spec itself — SC5 is now explicitly deferred to mt#4816, with rationale and owner named — so it is no longer a requirement for this PR. The code changes correctly re-root both writers: ask-form-lint now writes via the reader’s own resolveCalibrationStatePath into the state dir (writer made async and the sole callsite awaits it), and both copies of the warn-main-workspace-mutation hook now resolve/read/write the baseline under the project-keyed state dir with mkdir guarding. Tests assert the reader-derived path and ensure nothing is left in the workspace. SC3’s live corpus migration is out-of-repo and marked Unverifiable, which is acceptable. I found only a minor nit: an unused resolve import in ask-form-lint-calibration.ts. With no remaining blocking issues, this PR is approved.

Findings

  • [NON-BLOCKING] src/adapters/shared/commands/ask-form-lint-calibration.ts:40 — Unused import: resolve from node:path is no longer used
    The refactor to use resolveCalibrationStatePath(...) removed the need for resolve(workspacePath, …), but the import import { dirname, resolve } from "node:path"; remains. This is a minor cleanup; consider removing resolve to satisfy linters and reduce noise.

Spec verification

Criterion Status Evidence
SC1 — Neither writer resolves its path against the repo root. Verify: after the change, find .minsky -maxdepth 1 \( -name '*.jsonl' -o -name '*.json' \) -newermt '<change date>' returns neither file. Met Both writers now resolve to the state dir. Evidence: .claude/hooks/warn-main-workspace-mutation.ts:270-309 introduces baselinePath() using getMinskyStateDir() + projectStateKey(repoRoot) and updates readBaseline/writeBaseline to use it; the mirrored .minsky/hooks file makes the same change at :267-309. src/adapters/shared/commands/ask-form-lint-calibration.ts:120-131 now calls await resolveCalibrationStatePath(workspacePath, ASK_FORM_LINT_CALIBRATION_LOG) instead of resolve(workspacePath, …).
SC2 — ask-form-lint-calibration.jsonl is written where resolveCalibrationStatePath reads it. Verify by running the sweep for that guard and getting a non-zero record count, having produced a fire first. Met The writer uses the reader’s resolver: src/adapters/shared/commands/ask-form-lint-calibration.ts:120-131 calls resolveCalibrationStatePath(...). Tests assert via the same resolver and verify the write: src/adapters/shared/commands/ask-form-lint-calibration.test.ts:95-116 and :123-146 compute the path with resolveCalibrationStatePath and check file existence/contents there, and also assert no file is left under the workspace path.
SC3 — The existing 17KB repo copy is dispositioned explicitly: migrated into the state dir (preserving the pre-move corpus) or deleted with a stated reason. It is not left orphaned — that is the condition mt#4777 exists to clean up, and this task should not add to its pile. Unverifiable Disposition is an operational step outside the repo. The PR description claims a byte-identical migration and source removal under ~/.local/state/minsky/projects/<key>/..., but this is an out-of-repo path and cannot be verified from the diff.
SC4 — Both streams' rows in packages/domain/src/guard-events/stream-sources.ts carry the correct location, and docs/architecture/guard-calibration-stream-inventory.md matches. Met packages/domain/src/guard-events/stream-sources.ts already lists calibration streams (including ask-form-lint) with location: "state-dir" (see module header and CALIBRATION_STREAMS block near top). This PR does not change that file; the writer now aligns to the declared location. The inventory doc was not modified and already described this state, per spec; no contradiction introduced by this change.
SC5 — DEFERRED to mt#4816 (2026-08-31), owner named, not dropped. A check must assert SC1 mechanically so a third writer cannot reappear on the old path unnoticed. It is NOT shipped in this task's PR, deliberately: coordinate one behaviour-scoped check in mt#4816. Met The current spec explicitly defers SC5 to mt#4816 and records the rationale and owner in the criterion text. This PR does not introduce a new check, consistent with the deferral stated in the canonical Success Criteria.

Documentation impact

  • no-update-needed — Internal re-rooting of two telemetry writers and aligning ask-form-lint writer with an already-declared state-dir location. No user-facing commands, flags, or routes changed. Verified manifest already had ask-form-lint as location: "state-dir" (packages/domain/src/guard-events/stream-sources.ts), so no docs changed or invalidated by this PR.

@edobry
edobry merged commit 67da6e8 into main Aug 31, 2026
20 checks passed
@edobry
edobry deleted the task/mt-4811 branch August 31, 2026 20:38

@minsky-reviewer minsky-reviewer 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.

Independent adversarial review (Chinese-wall)
Reviewer: minsky-reviewer[bot] via openai:gpt-5
Tier: 2


Verification pass: the prior BLOCKING gap (SC5 missing) has been addressed by the canonical task spec deferring SC5 to mt#4816 with rationale and owner, so it is no longer required in this PR. The code changes correctly re-root both writers: ask-form-lint now uses resolveCalibrationStatePath (writer made async and its production callsite updated to await), and both hook copies of the main-workspace mutation baseline now resolve/read/write under the project-keyed state dir with mkdir guarding. Tests assert the reader-derived path and ensure nothing is left under the workspace. I found only a minor nit (unused resolve import) and no new critical defects introduced by the fix. Approving to merge.

Findings

  • [NON-BLOCKING] src/adapters/shared/commands/ask-form-lint-calibration.ts:40 — Unused import: resolve from node:path is no longer used after switching to resolveCalibrationStatePath
    The refactor to compute the log path via resolveCalibrationStatePath(...) removed the need for resolve(workspacePath, …), but the import still reads import { dirname, resolve } from "node:path";. resolve is not referenced in this module anymore. Suggest removing it to satisfy linters and keep imports tidy.

Spec verification

Criterion Status Evidence
SC1 — Neither writer resolves its path against the repo root. Verify: after the change, find .minsky -maxdepth 1 \( -name '*.jsonl' -o -name '*.json' \) -newermt '<change date>' returns neither file. Met Both writers now resolve to the state dir. Evidence in diff: .claude/hooks/warn-main-workspace-mutation.ts:270-309 introduces baselinePath() using getMinskyStateDir() + projectStateKey(repoRoot) and updates readBaseline/writeBaseline to use it; the mirrored .minsky/hooks file makes the same change at :267-309. src/adapters/shared/commands/ask-form-lint-calibration.ts:120-131 now calls await resolveCalibrationStatePath(workspacePath, ASK_FORM_LINT_CALIBRATION_LOG) instead of resolve(workspacePath, …).
SC2 — ask-form-lint-calibration.jsonl is written where resolveCalibrationStatePath reads it. Verify by running the sweep for that guard and getting a non-zero record count, having produced a fire first. Met The writer uses the reader’s resolver. src/adapters/shared/commands/ask-form-lint-calibration.ts:120-131 calls resolveCalibrationStatePath(...). Tests assert via the same resolver and verify the write and absence under the workspace: src/adapters/shared/commands/ask-form-lint-calibration.test.ts:95-116, 123-146 compute the path with resolveCalibrationStatePath and check file existence/contents there, and also assert no file under the workspace path.
SC3 — The existing 17KB repo copy is dispositioned explicitly: migrated into the state dir (preserving the pre-move corpus) or deleted with a stated reason. It is not left orphaned — that is the condition mt#4777 exists to clean up, and this task should not add to its pile. Unverifiable Disposition is an operational step outside the repo. The PR body claims byte-identical migration and source removal under ~/.local/state/minsky/projects/<key>/..., but this is an out-of-repo path and cannot be verified from the diff. No code in this PR performs the migration; treating as Unverifiable per Out-of-repo references observed.
SC4 — Both streams' rows in packages/domain/src/guard-events/stream-sources.ts carry the correct location, and docs/architecture/guard-calibration-stream-inventory.md matches. Met No manifest/doc edits were required by this PR; ask-form-lint was already declared location: "state-dir". This PR aligns the writer to that standing declaration (see src/adapters/shared/commands/ask-form-lint-calibration.ts:120-131). No contradictions introduced in docs by this diff.
SC5 — DEFERRED to mt#4816 (2026-08-31), owner named, not dropped. A check must assert SC1 mechanically so a third writer cannot reappear on the old path unnoticed. It is NOT shipped in this task's PR, deliberately: coordinate one behaviour-scoped check in mt#4816. Met The canonical Success Criteria in this task spec explicitly defer SC5 to mt#4816 with rationale and owner. This PR does not add a new check, consistent with the spec’s deferral.

Documentation impact

  • no-update-needed — Internal re-rooting of two telemetry writers with no user-visible commands, flags, or routes changed. The manifest already declared ask-form-lint as location: "state-dir"; this PR aligns the writer to that standing declaration. No docs in this repo were modified by the PR, and no existing inventory prose is invalidated by these code-only path changes.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

authorship/co-authored Co-authored by human and AI agent

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant