leerness 1.36.188 → 1.36.297
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/CHANGELOG.md +648 -0
- package/CONTRIBUTING.md +12 -4
- package/README.ko.md +6 -3
- package/README.md +58 -8
- package/bin/leerness.js +2997 -2262
- package/docs/agent-bench-output.md +65 -0
- package/docs/agent-chat-stream.md +56 -0
- package/docs/audit-env-storage.md +67 -0
- package/docs/audit-readme-storage.md +83 -0
- package/docs/audit-text-storage.md +74 -0
- package/docs/authoring-language.md +66 -0
- package/docs/brief-text-storage.md +66 -0
- package/docs/bugfix-areas.md +81 -0
- package/docs/context-reading.md +45 -0
- package/docs/efficient-testing.md +66 -0
- package/docs/encoding-diagnostics.md +67 -0
- package/docs/env-snapshot-storage.md +13 -0
- package/docs/env-sync-text-storage.md +13 -0
- package/docs/execution-ledger-storage.md +34 -0
- package/docs/feature-graph-text-storage.md +15 -0
- package/docs/generation-text-storage.md +59 -0
- package/docs/github-login.md +38 -0
- package/docs/handoff-history-text-storage.md +13 -0
- package/docs/handoff-text-storage.md +47 -0
- package/docs/harness-text.md +37 -0
- package/docs/history-retention.md +68 -0
- package/docs/install-text-storage.md +60 -0
- package/docs/installed-handoff-lifecycle.md +47 -0
- package/docs/managed-text-storage.md +139 -0
- package/docs/memory-candidate-budget.md +76 -0
- package/docs/memory-checked-input.md +44 -0
- package/docs/memory-command-policy.md +75 -0
- package/docs/memory-footprint.md +80 -0
- package/docs/memory-guard-order.md +46 -0
- package/docs/memory-input-preflight.md +58 -0
- package/docs/memory-item-admission.md +137 -0
- package/docs/memory-legacy-retention.md +58 -0
- package/docs/memory-migration-observation.md +73 -0
- package/docs/memory-migration-plan.md +69 -0
- package/docs/memory-migration-write.md +87 -0
- package/docs/memory-publication-policy.md +65 -0
- package/docs/memory-recovery-transfer.md +77 -0
- package/docs/memory-restore-canonical.md +24 -0
- package/docs/memory-utf8-admission.md +23 -0
- package/docs/memory-write-admission.md +83 -0
- package/docs/memory-write-budget.md +90 -0
- package/docs/memory-write-preparation.md +74 -0
- package/docs/mode-text-storage.md +79 -0
- package/docs/openai-response-retrieval.md +27 -0
- package/docs/openai-ui-review-dispatch.md +56 -0
- package/docs/openai-ui-review-observation.md +68 -0
- package/docs/openai-ui-review-publication.md +84 -0
- package/docs/openai-ui-review-receipt.md +52 -0
- package/docs/plan-text-storage.md +66 -0
- package/docs/quality-system.md +51 -0
- package/docs/reminder-text-storage.md +13 -0
- package/docs/review-checkpoint-api.md +102 -0
- package/docs/review-checkpoint-example.json +19 -0
- package/docs/review-checkpoint-transport.md +93 -0
- package/docs/review-control-api.md +152 -0
- package/docs/review-feedback.md +282 -0
- package/docs/review-snapshot-api.md +109 -0
- package/docs/review-snapshot-transport.md +57 -0
- package/docs/role-agent-routing-v2.md +11 -0
- package/docs/rule-applicability.md +50 -0
- package/docs/rule-text-storage.md +66 -0
- package/docs/rule-verification.md +50 -0
- package/docs/runtime-compatibility-api.md +22 -0
- package/docs/session-close-text-storage.md +64 -0
- package/docs/session-start-hooks.md +48 -0
- package/docs/state-scopes.md +14 -0
- package/docs/state-store-locking.md +59 -0
- package/docs/store-diagnostics-api.md +9 -0
- package/docs/teams-text-storage.md +13 -0
- package/docs/test-execution-plan.md +140 -0
- package/docs/ui-boundary-api.md +112 -0
- package/docs/ui-boundary-browser-api.md +138 -0
- package/docs/ui-boundary-contracts.md +136 -0
- package/docs/ui-boundary-scanner.md +169 -0
- package/docs/ui-boundary-trials-api.md +93 -0
- package/docs/ui-information-quality.md +39 -0
- package/docs/ui-review-api.md +180 -0
- package/docs/ui-review-authority-floor.md +32 -0
- package/docs/ui-review-authority-host.md +63 -0
- package/docs/ui-review-authorization.md +51 -0
- package/docs/ui-review-cli.md +69 -0
- package/docs/ui-review-ledger-api.md +123 -0
- package/docs/ui-review-observation-api.md +144 -0
- package/docs/ui-review-proof-use.md +32 -0
- package/docs/ui-review-recovery.md +44 -0
- package/docs/ui-review-run-api.md +93 -0
- package/docs/ui-review-target.md +59 -0
- package/lib/agent-bench-output.js +4 -0
- package/lib/agent-chat-stream.js +137 -0
- package/lib/agent-registry.js +2 -2
- package/lib/agents.js +30 -35
- package/lib/audit.js +219 -66
- package/lib/authoring-language.js +56 -0
- package/lib/auto-update-hooks.js +58 -0
- package/lib/bugfix.js +77 -8
- package/lib/catalogs.js +7 -8
- package/lib/claims-baseline.js +3 -1
- package/lib/context-current.js +203 -0
- package/lib/context-reading-guidance.js +233 -0
- package/lib/copy-tree.js +32 -0
- package/lib/crud-check.js +232 -0
- package/lib/dashboard.js +0 -1
- package/lib/drift.js +4 -1
- package/lib/encoding-diagnostics.js +177 -0
- package/lib/env-snapshot-text.js +92 -0
- package/lib/env-sync-text.js +53 -0
- package/lib/error-language.js +17 -0
- package/lib/feature-graph-text.js +56 -0
- package/lib/feature.js +11 -9
- package/lib/git.js +13 -8
- package/lib/github-login-http.js +69 -0
- package/lib/github-login.js +121 -0
- package/lib/handoff-history-text.js +45 -0
- package/lib/health.js +2 -2
- package/lib/history-retention-cli.js +51 -0
- package/lib/history-retention-write.js +400 -0
- package/lib/history-retention.js +259 -0
- package/lib/io.js +104 -36
- package/lib/machine-cache.js +78 -0
- package/lib/managed-text.js +83 -0
- package/lib/mcp-tools.js +11 -7
- package/lib/memory-archive.js +269 -0
- package/lib/memory-candidate-budget.js +65 -0
- package/lib/memory-command-policy.js +95 -0
- package/lib/memory-footprint-capture.js +61 -0
- package/lib/memory-footprint.js +20 -0
- package/lib/memory-input-bytes.js +25 -0
- package/lib/memory-input.js +194 -0
- package/lib/memory-items.js +30 -0
- package/lib/memory-json-size.js +75 -0
- package/lib/memory-language.js +24 -0
- package/lib/memory-migration-budget.js +55 -0
- package/lib/memory-migration-bundle.js +65 -0
- package/lib/memory-migration-execute.js +94 -0
- package/lib/memory-migration-material.js +28 -0
- package/lib/memory-migration-observe.js +77 -0
- package/lib/memory-migration-plan.js +120 -0
- package/lib/memory-migration-storage.js +60 -0
- package/lib/memory-migration-transport.js +46 -0
- package/lib/memory-migration-withdraw.js +47 -0
- package/lib/memory-migration-write-transport.js +34 -0
- package/lib/memory-migration-write.js +83 -0
- package/lib/memory-output.js +451 -0
- package/lib/memory-parent.js +16 -0
- package/lib/memory-projection.js +62 -0
- package/lib/memory-publication-read.js +54 -0
- package/lib/memory-publication-result.js +43 -0
- package/lib/memory-recovery-inventory.js +93 -0
- package/lib/memory-recovery-sink.js +55 -0
- package/lib/memory-recovery-transfer.js +76 -0
- package/lib/memory-recovery.js +234 -0
- package/lib/memory-write-admission.js +115 -0
- package/lib/memory-write-budget-plan.js +117 -0
- package/lib/memory-write-budget.js +40 -0
- package/lib/memory-write-preparation.js +128 -0
- package/lib/migrate.js +7 -9
- package/lib/openai-response-http.js +114 -0
- package/lib/openai-response-retrieval.js +13 -0
- package/lib/openai-ui-review-dispatch.js +157 -0
- package/lib/openai-ui-review-journal.js +132 -0
- package/lib/openai-ui-review-observation-record.js +59 -0
- package/lib/openai-ui-review-observation.js +132 -0
- package/lib/openai-ui-review-publication.js +169 -0
- package/lib/openai-ui-review-request.js +71 -0
- package/lib/plain-language-reporting.js +74 -0
- package/lib/portable-process.js +81 -4
- package/lib/process-output.js +129 -0
- package/lib/pure-utils.js +170 -31
- package/lib/reminder-text.js +48 -0
- package/lib/retired-guidance-sections.js +22 -0
- package/lib/review-checkpoint-transport.js +226 -0
- package/lib/review-checkpoint.js +267 -0
- package/lib/review-control-contract.js +112 -0
- package/lib/review-control-git.js +123 -0
- package/lib/review-control.js +50 -0
- package/lib/review-feedback-contract.js +262 -0
- package/lib/review-feedback-guidance.js +19 -0
- package/lib/review-feedback-report.js +290 -0
- package/lib/review-feedback-transport.js +60 -0
- package/lib/review-feedback.js +110 -0
- package/lib/review-request.js +107 -48
- package/lib/review-snapshot-transport.js +86 -0
- package/lib/review-snapshot.js +163 -0
- package/lib/role-agent-schema.js +10 -1
- package/lib/role-catalog.js +1 -1
- package/lib/role-fallback.js +97 -27
- package/lib/role-file-identity.js +40 -0
- package/lib/role-store.js +18 -15
- package/lib/rule-applicability.js +141 -0
- package/lib/rule-assessment-cli.js +41 -0
- package/lib/rule-verification.js +85 -0
- package/lib/runtime-layout.js +58 -16
- package/lib/runtime-writes.js +151 -1
- package/lib/session-close.js +111 -59
- package/lib/session-next.js +53 -0
- package/lib/state-lock.js +489 -0
- package/lib/store-diagnostic-read.js +67 -43
- package/lib/store-display.js +57 -0
- package/lib/team.js +5 -9
- package/lib/teams-text.js +78 -0
- package/lib/test-execution-plan.js +129 -0
- package/lib/test-firebase-hub-probe.js +72 -0
- package/lib/test-firestore-probe.js +138 -0
- package/lib/test-http-probe.js +110 -0
- package/lib/test-node-runner-transport.js +96 -0
- package/lib/test-node-runner.js +230 -0
- package/lib/test-node-selection-reporter.mjs +11 -0
- package/lib/test-npm-script-probe.js +151 -0
- package/lib/test-npm-script-runner.js +112 -0
- package/lib/test-plan-transport.js +123 -0
- package/lib/test-prerequisite-probe.js +80 -0
- package/lib/test-process-tree.js +20 -0
- package/lib/test-suite-list-runner.js +181 -0
- package/lib/toggles.js +6 -1
- package/lib/ui-boundary-browser.js +236 -0
- package/lib/ui-boundary-contracts.js +140 -0
- package/lib/ui-boundary-scanner.js +194 -0
- package/lib/ui-boundary-trials.js +88 -0
- package/lib/ui-boundary.js +128 -0
- package/lib/ui-copy-boundary.js +78 -0
- package/lib/ui-information-quality.js +78 -0
- package/lib/ui-review-attempt.js +94 -0
- package/lib/ui-review-authority-floor.js +101 -0
- package/lib/ui-review-authority-host.js +89 -0
- package/lib/ui-review-authority-policy.js +47 -0
- package/lib/ui-review-authorization-contract.js +37 -0
- package/lib/ui-review-authorization.js +117 -0
- package/lib/ui-review-ledger.js +237 -0
- package/lib/ui-review-observation.js +217 -0
- package/lib/ui-review-proof-use.js +113 -0
- package/lib/ui-review-provider-receipt.js +70 -0
- package/lib/ui-review-recovery-bundle.js +130 -0
- package/lib/ui-review-result.js +50 -0
- package/lib/ui-review-run-context.js +19 -0
- package/lib/ui-review-run-contract.js +94 -0
- package/lib/ui-review-run.js +186 -0
- package/lib/ui-review-target.js +58 -0
- package/lib/ui-review-transport.js +119 -0
- package/lib/ui-review.js +224 -0
- package/package.json +124 -10
- package/scripts/agent-chat-stream-probe.js +211 -0
- package/scripts/agents-bench-output-probe.js +178 -0
- package/scripts/api-skill-match-probe.js +194 -0
- package/scripts/audit-env-text-probe.js +264 -0
- package/scripts/audit-readme-text-probe.js +250 -0
- package/scripts/audit-text-probe.js +213 -0
- package/scripts/authoring-language-probe.js +169 -0
- package/scripts/auto-update-hooks-probe.js +122 -0
- package/scripts/brief-text-probe.js +198 -0
- package/scripts/bugfix-areas-probe.js +337 -0
- package/scripts/claim-runtime-cache-probe.js +116 -0
- package/scripts/claim-sweep-git-probe.js +158 -0
- package/scripts/command-flags-probe.js +14 -1
- package/scripts/context-current-probe.js +164 -0
- package/scripts/context-reading-probe.js +480 -0
- package/scripts/copy-tree-probe.js +61 -0
- package/scripts/crud-check-probe.js +238 -0
- package/scripts/dead-flags-probe.js +35 -16
- package/scripts/decision-fence-offset-probe.js +80 -0
- package/scripts/done-status-probe.js +181 -0
- package/scripts/dry-run-refusal-probe.js +179 -0
- package/scripts/e2e-child-diagnostics-probe.js +11 -4
- package/scripts/e2e-concurrency.js +215 -11
- package/scripts/e2e-lived-in-harness.js +260 -0
- package/scripts/e2e-repo-guard.js +78 -0
- package/scripts/e2e.js +240 -115
- package/scripts/encoding-diagnostics-probe.js +260 -0
- package/scripts/encoding-selftest-probe.js +2 -1
- package/scripts/env-snapshot-text-probe.js +144 -0
- package/scripts/env-sync-text-probe.js +140 -0
- package/scripts/execution-ledger-sync-probe.js +189 -0
- package/scripts/feature-graph-text-probe.js +183 -0
- package/scripts/fix-evidence-language-probe.js +125 -0
- package/scripts/fixtures/legacy-guidance-1.36.289.json +21 -0
- package/scripts/free-text-args-probe.js +220 -0
- package/scripts/generation-text-probe.js +133 -0
- package/scripts/git-resolution-cache-probe.js +116 -0
- package/scripts/github-login-probe.js +251 -0
- package/scripts/handoff-history-text-probe.js +104 -0
- package/scripts/handoff-i18n-probe.js +292 -0
- package/scripts/handoff-preservation-probe.js +98 -0
- package/scripts/handoff-readonly-probe.js +34 -0
- package/scripts/handoff-text-probe.js +154 -0
- package/scripts/harness-text-probe.js +113 -0
- package/scripts/history-retention-probe.js +190 -0
- package/scripts/history-retention-write-probe.js +380 -0
- package/scripts/i18n-next-cluster-probe.js +16 -24
- package/scripts/install-text-probe.js +139 -0
- package/scripts/installed-cleanroom-probe.js +62 -16
- package/scripts/installed-handoff-lifecycle-probe.js +204 -0
- package/scripts/lint.js +24 -1
- package/scripts/lock-heartbeat-probe.js +132 -0
- package/scripts/lock-probe.js +34 -4
- package/scripts/managed-text-probe.js +171 -0
- package/scripts/mcp-presence-probe.js +3 -1
- package/scripts/memory-archive-check-probe.js +354 -0
- package/scripts/memory-archive-retention-probe.js +567 -0
- package/scripts/memory-candidate-budget-probe.js +87 -0
- package/scripts/memory-candidate-isolation-probe.js +40 -0
- package/scripts/memory-checked-input-probe.js +170 -0
- package/scripts/memory-command-policy-mcp-probe.js +43 -0
- package/scripts/memory-command-policy-probe.js +140 -0
- package/scripts/memory-command-size-probe.js +30 -0
- package/scripts/memory-footprint-probe.js +55 -0
- package/scripts/memory-footprint-race-probe.js +74 -0
- package/scripts/memory-guard-order-probe.js +136 -0
- package/scripts/memory-input-preflight-probe.js +243 -0
- package/scripts/memory-input-unit-probe.js +56 -0
- package/scripts/memory-item-admission-probe.js +109 -0
- package/scripts/memory-items-unit-probe.js +36 -0
- package/scripts/memory-language-probe.js +168 -0
- package/scripts/memory-legacy-retention-probe.js +182 -0
- package/scripts/memory-migration-boundary-probe.js +69 -0
- package/scripts/memory-migration-concurrency-probe.js +55 -0
- package/scripts/memory-migration-failure-probe.js +77 -0
- package/scripts/memory-migration-isolation-probe.js +127 -0
- package/scripts/memory-migration-observe-probe.js +83 -0
- package/scripts/memory-migration-plan-probe.js +193 -0
- package/scripts/memory-migration-race-probe.js +86 -0
- package/scripts/memory-migration-test-support.js +61 -0
- package/scripts/memory-migration-transport-probe.js +111 -0
- package/scripts/memory-migration-write-probe.js +92 -0
- package/scripts/memory-migration-write-support.js +25 -0
- package/scripts/memory-output-parent-race-probe.js +199 -0
- package/scripts/memory-output-posix-probe.js +119 -0
- package/scripts/memory-output-publication-probe.js +301 -0
- package/scripts/memory-output-unit-probe.js +162 -0
- package/scripts/memory-projection-retention-probe.js +167 -0
- package/scripts/memory-publication-cli-probe.js +98 -0
- package/scripts/memory-publication-policy-probe.js +183 -0
- package/scripts/memory-recovery-external-probe.js +113 -0
- package/scripts/memory-recovery-receipt-probe.js +243 -0
- package/scripts/memory-recovery-transfer-probe.js +114 -0
- package/scripts/memory-restore-canonical-probe.js +262 -0
- package/scripts/memory-utf8-admission-probe.js +178 -0
- package/scripts/memory-write-admission-probe.js +175 -0
- package/scripts/memory-write-budget-cli-probe.js +49 -0
- package/scripts/memory-write-budget-meter.js +38 -0
- package/scripts/memory-write-budget-probe.js +109 -0
- package/scripts/memory-write-budget-race-probe.js +79 -0
- package/scripts/memory-write-budget-support.js +35 -0
- package/scripts/memory-write-dry-run-probe.js +24 -0
- package/scripts/memory-write-preparation-cli-probe.js +46 -0
- package/scripts/memory-write-preparation-probe.js +85 -0
- package/scripts/mode-text-probe.js +230 -0
- package/scripts/mutation-integrity-probe.js +25 -3
- package/scripts/openai-response-retrieval-probe.js +246 -0
- package/scripts/openai-ui-review-dispatch-probe.js +275 -0
- package/scripts/openai-ui-review-fixture.js +43 -0
- package/scripts/openai-ui-review-observation-probe.js +251 -0
- package/scripts/openai-ui-review-observation-record-probe.js +81 -0
- package/scripts/openai-ui-review-receipt-probe.js +172 -0
- package/scripts/openai-ui-review-worker.js +55 -0
- package/scripts/plain-language-reporting-probe.js +91 -0
- package/scripts/plan-text-probe.js +174 -0
- package/scripts/platform-smoke.js +13 -19
- package/scripts/release-runtime-probe.js +15 -4
- package/scripts/reminder-text-probe.js +128 -0
- package/scripts/review-checkpoint-probe.js +272 -0
- package/scripts/review-checkpoint-transport-probe.js +347 -0
- package/scripts/review-control-probe.js +478 -0
- package/scripts/review-feedback-probe.js +711 -0
- package/scripts/review-request-labels-probe.js +133 -0
- package/scripts/review-request-signals-probe.js +183 -0
- package/scripts/review-snapshot-probe.js +258 -0
- package/scripts/review-snapshot-transport-probe.js +305 -0
- package/scripts/role-fallback-probe.js +46 -25
- package/scripts/role-file-identity-probe.js +204 -0
- package/scripts/rule-applicability-probe.js +243 -0
- package/scripts/rule-text-probe.js +199 -0
- package/scripts/rule-verification-probe.js +144 -0
- package/scripts/runtime-admission-probe.js +2 -1
- package/scripts/runtime-cost-probe.js +241 -0
- package/scripts/runtime-descriptor-identity-probe.js +176 -0
- package/scripts/runtime-git-write-probe.js +3 -0
- package/scripts/runtime-layout-probe.js +38 -10
- package/scripts/runtime-replacement-probe.js +36 -0
- package/scripts/runtime-write-probe.js +49 -1
- package/scripts/secret-scan-scope-probe.js +109 -0
- package/scripts/session-close-text-probe.js +183 -0
- package/scripts/shared-state-lock-probe.js +190 -0
- package/scripts/smoke.js +3 -4
- package/scripts/state-scopes-probe.js +2 -1
- package/scripts/store-diagnostic-identity-probe.js +178 -0
- package/scripts/store-values-probe.js +389 -0
- package/scripts/task-sync-roundtrip-probe.js +467 -0
- package/scripts/teams-text-probe.js +108 -0
- package/scripts/temp-cleanup-probe.js +76 -0
- package/scripts/temp-cleanup.js +23 -0
- package/scripts/test-execution-plan-probe.js +155 -0
- package/scripts/test-firestore-probe.js +268 -0
- package/scripts/test-http-probe.js +160 -0
- package/scripts/test-node-runner-probe.js +191 -0
- package/scripts/test-npm-script-probe.js +151 -0
- package/scripts/test-npm-script-runner-probe.js +198 -0
- package/scripts/test-prerequisite-probe.js +135 -0
- package/scripts/test-suite-list-runner-probe.js +169 -0
- package/scripts/title-args-probe.js +272 -0
- package/scripts/tracker-write-language-probe.js +344 -0
- package/scripts/ui-boundary-browser-probe.js +337 -0
- package/scripts/ui-boundary-contracts-probe.js +305 -0
- package/scripts/ui-boundary-dashboard-probe.js +134 -0
- package/scripts/ui-boundary-probe.js +251 -0
- package/scripts/ui-boundary-scanner-probe.js +350 -0
- package/scripts/ui-boundary-trials-probe.js +61 -0
- package/scripts/ui-copy-boundary-probe.js +132 -0
- package/scripts/ui-information-quality-probe.js +48 -0
- package/scripts/ui-review-attempt-probe.js +176 -0
- package/scripts/ui-review-attempt-worker.js +44 -0
- package/scripts/ui-review-authority-floor-probe.js +220 -0
- package/scripts/ui-review-authority-floor-worker.js +24 -0
- package/scripts/ui-review-authority-host-probe.js +219 -0
- package/scripts/ui-review-authorization-fixture.js +37 -0
- package/scripts/ui-review-authorization-probe.js +209 -0
- package/scripts/ui-review-fixture.js +39 -0
- package/scripts/ui-review-ledger-probe.js +271 -0
- package/scripts/ui-review-observation-probe.js +319 -0
- package/scripts/ui-review-probe.js +354 -0
- package/scripts/ui-review-proof-use-probe.js +189 -0
- package/scripts/ui-review-provider-receipt-probe.js +79 -0
- package/scripts/ui-review-publication-probe.js +272 -0
- package/scripts/ui-review-publication-worker.js +44 -0
- package/scripts/ui-review-recovery-probe.js +214 -0
- package/scripts/ui-review-result-probe.js +148 -0
- package/scripts/ui-review-run-fixture.js +68 -0
- package/scripts/ui-review-run-probe.js +329 -0
- package/scripts/ui-review-target-probe.js +209 -0
- package/scripts/ui-review-transport-probe.js +207 -0
- package/scripts/verify-code-cross-runtime-probe.js +13 -0
- package/scripts/write-path-language-probe.js +565 -0
- package/scripts/write-primitive-language-probe.js +324 -0
- package/docs/PUBLISH_PRECHECK.md +0 -93
package/CHANGELOG.md
CHANGED
|
@@ -1,5 +1,653 @@
|
|
|
1
1
|
# Changelog
|
|
2
2
|
|
|
3
|
+
## 1.36.297 - 2026-10-11
|
|
4
|
+
|
|
5
|
+
- Fixed: on Windows, `decision`, `lesson` and `memory` writes that replace an existing file could take 20 s or more per file, or fail with "Windows metadata-preserving replacement failed: spawnSync ... powershell.exe ETIMEDOUT" (T-0343). This happened when Leerness ran in an environment with no PSModulePath.
|
|
6
|
+
- Cause: the replacement starts Windows PowerShell, and its command began with the cmdlet `New-Object`. To find that cmdlet, PowerShell analyzed every module on the machine module path.
|
|
7
|
+
- Measured on a GitHub Windows runner with 5 or 10 environment variables kept: 21.5-52 s per launch.
|
|
8
|
+
- The command now creates the same encoding, `[Activator]::CreateInstance([System.Text.UTF8Encoding])` (no BOM), with a .NET call, and contains no command invocation. On the same runner, the .NET call launched in 0.2 s in every environment tested. The call also works on PowerShell 2-4.
|
|
9
|
+
- On that runner image, with the change, the memory-guard-order probe took 50 s; with the old command it took 8 min 46 s.
|
|
10
|
+
- On the 1.36.296 public CI, the slow launches made replacements pass the 30 s launch limit. Six concurrent writers then waited past the 35 s lock limit, and stopped without losing data.
|
|
11
|
+
- Fixed: on Linux and macOS, commands no longer act on a file that another writer is publishing (T-0343). Publication there renames the file away and links the new bytes while it holds the file's lock, so for a moment the file is missing. These commands checked whether the file exists before taking that lock. Each one now checks under the lock:
|
|
12
|
+
- `plan init` ran a full install without the lock and lost its goal.
|
|
13
|
+
- `plan remove` reported `plan_not_found` for a plan that still had the milestone.
|
|
14
|
+
- `task add` missed an active task with the same request and added a duplicate. On every platform, two `task add` commands with the same text running at once both added the task; the duplicate check now runs under the lock that assigns the ID.
|
|
15
|
+
- `idempotency audit --auto-fix` (also used by `drift check --auto-fix`) skipped the tracker deduplication.
|
|
16
|
+
- `env sync` reported that `.env.example` was missing.
|
|
17
|
+
- `task update` and `task drop` reported `task_not_found` for a task that existed.
|
|
18
|
+
- `task add` and `lazy detect --auto-track` assigned a task ID that only the plan held.
|
|
19
|
+
- `task sync` gave a new item the ID of an existing row and replaced that row, which lost the existing task.
|
|
20
|
+
- Each of these now assigns the ID and writes the row under the tracker lock, then the plan lock. The tasks that `release pack` and `init` add use the same ID assignment and were changed the same way; no race was run for those two.
|
|
21
|
+
- `task sync` imported items that already had a row as new tasks. It now also skips an item whose text gained a row since it read the tracker, and reports it as ambiguous.
|
|
22
|
+
- `lazy detect --auto-track` registered new TODOs even when every one of them was in a file that a task already referenced. A batch that mixes such files with untracked ones still registers all of them, as before; that is a separate follow-up.
|
|
23
|
+
- `anchors draft --apply` left an empty Goal or Purpose unfilled and reported it as written. `task relink --apply` reported no unlinked milestone. `task fix-evidence --set` reported no candidates. `rule verify` reported no active rule.
|
|
24
|
+
- `session close` wrote a handoff without the tracker's tasks (measured: the in-progress task was missing, exit 0).
|
|
25
|
+
- `task export --to` (and `--json`) saved an empty export and an empty sync baseline.
|
|
26
|
+
- `bugfix start` reported `task_not_found` for a task that existed.
|
|
27
|
+
- `verify-claim baseline create` reported `boundary_not_found`. It now builds the baseline from one tracker snapshot read under the lock, and judges every claim against that snapshot. `verify-claim --all` judges its claims against one snapshot too.
|
|
28
|
+
- The commands that only print, such as `task relink` without `--apply`, `task fix-evidence` without `--set` and every `--dry-run`, still take no lock.
|
|
29
|
+
- Read-only reports such as `handoff`, the summary that `session close` prints, and generated views can still read a file as missing for that moment, as before.
|
|
30
|
+
- Fixed: memory footprint, memory write admission and `encoding check` now see a file added to a directory while they scan it, even when the directory's timestamps do not change (T-0343). Each now lists the scanned directories again and compares the names. Before, these checks compared the directory's lstat only. Measured over 2,000 adds, that lstat stayed the same 1,986-1,990 times on Linux (4 ms timestamp ticks) and 1,478 times on Windows. Before, `encoding check` could report complete coverage while it missed such a file.
|
|
31
|
+
- The memory recheck also checks the recovery directory again after opening it and after listing it, so a junction put in its place in between is rejected instead of followed.
|
|
32
|
+
- Recovery content is still never read. A same-size rewrite of a recovery file within one tick is therefore still not seen; it changes no measured value.
|
|
33
|
+
- Fixed: on Windows with Node 22.23.3, `selftest` crashed (exit 139 in Git Bash, 3221225477 from Node: an access violation) when the temp directory's path had non-ASCII letters, as it does for a Windows user name in Korean (T-0343).
|
|
34
|
+
- Cause: its fixture copies used `fs.cpSync`, and Node 22.23.3 ends the process that way when a source or destination path has non-ASCII letters.
|
|
35
|
+
- Measured on Windows: 18.20.8, 20.20.2, 22.11.0 and 26.3.0 copy such paths.
|
|
36
|
+
- The copies now use `lib/copy-tree.js`, a recursive copy of directories, files and links that never overwrites a file. With a Korean temp path on Node 22.23.3, `selftest` passes 355/355; before, it crashed.
|
|
37
|
+
- Found by the public CI of the 1.36.297 candidate: `tracker-write-language-probe`, whose fixture folders have Korean names, failed on Windows Node 22. Three more probes build their fixtures the same way.
|
|
38
|
+
- Not fixed here (T-0350): a decisions or lessons restore with an explicit write policy (`--write-policy-json`, or `writePolicyJson` in MCP) is refused with "snapshot does not belong to this file" when the project path is spelled differently from its real path.
|
|
39
|
+
- On Windows, a lowercase drive letter, a junction and an 8.3 short name all trigger it. The refused restore publishes nothing.
|
|
40
|
+
- A restore without a write policy works with each of these spellings.
|
|
41
|
+
- Found while reproducing the conditions of GitHub's Windows runners for the tests below.
|
|
42
|
+
- Tests (T-0343):
|
|
43
|
+
- `scripts/runtime-layout-probe.js` compares fixture snapshots itself and fails with its own message. Node 18-22's `assert.strictEqual` drops the message for long strings, and the check matched on that message.
|
|
44
|
+
- `scripts/mcp-presence-probe.js` initializes its fixtures with `--language ko`. Before, the project language came from the runner's locale.
|
|
45
|
+
- `scripts/memory-recovery-receipt-probe.js` also injects its fault at the POSIX hard-link install (`fs.linkSync`), so the fault fires on Linux.
|
|
46
|
+
- `scripts/memory-guard-order-probe.js` prints the end of stdout and stderr when setup fails.
|
|
47
|
+
- `scripts/runtime-replacement-probe.js` (9 checks, was 7):
|
|
48
|
+
- Counts command invocations in the replacement command with PowerShell's own parser. The count includes cmdlets, aliases such as `echo` and `%`, functions and programs.
|
|
49
|
+
- Checks that the counter itself sees cmdlets and aliases, and does not count text inside strings.
|
|
50
|
+
- Runs the replacement once with no PSModulePath.
|
|
51
|
+
- `scripts/e2e-concurrency.js` (30 races, was 11; the e2e step now expects exactly 30 and allows 600 s, since 26 of them took 181 s here):
|
|
52
|
+
- Each new race runs a command while another writer holds the file it reads renamed away.
|
|
53
|
+
- The races cover plan remove, task add deduplication and ID assignment, task update, task drop, task fix-evidence, task sync (duplicate import and ID assignment), task relink, task export, idempotency auto-fix, env sync, anchors draft, lazy detect auto-track, bugfix start, claims baseline create, rule verify and session close.
|
|
54
|
+
- All of them fail on the code before this change on Linux.
|
|
55
|
+
- It also adds the same `task add` run twice at once, which fails on the code before this change on Windows and Linux.
|
|
56
|
+
- `scripts/lock-probe.js` can now stall on a file outside `.leerness`, named by its absolute path. Relative targets still name paths inside `.leerness` only.
|
|
57
|
+
- `scripts/memory-footprint-race-probe.js` (22 checks, was 19):
|
|
58
|
+
- Adds a same-tick case: a file added while lstat timestamps are held fixed.
|
|
59
|
+
- Adds a junction put in place before the recheck listing.
|
|
60
|
+
- Splits the late recovery-file change into a size change and a timestamp change.
|
|
61
|
+
- `scripts/encoding-diagnostics-probe.js` (38 checks, was 37): adds a file written during the scan while the directory's timestamps are held fixed.
|
|
62
|
+
- `scripts/e2e.js`: `task relink --dry-run` must print the same suggestions as `task relink`.
|
|
63
|
+
- selftest: four source pins follow the new code (three lock pins and the verify-claim --all wiring pin). The task add and task drop pins now search inside the function they pin; the task drop pin used to find its own text first and was always true.
|
|
64
|
+
- Each new regression case fails on the code before this change. The counter check above tests the test itself.
|
|
65
|
+
- The `plan init` failure was not reached by CI, whose jobs stopped at earlier failures. It was found by running the full suite step by step on Linux with Node 18, 20 and 22.
|
|
66
|
+
- `scripts/copy-tree-probe.js` (5 checks, part of `npm run test:temp-cleanup`) tests `lib/copy-tree.js`: exact bytes in nested directories with ASCII and Korean paths, copying into an existing directory, no overwrite, and a missing source.
|
|
67
|
+
- `scripts/dry-run-refusal-probe.js`, `scripts/tracker-write-language-probe.js`, `scripts/write-path-language-probe.js` and `scripts/write-primitive-language-probe.js` copy their Korean-named fixture folders with `lib/copy-tree.js`. The old copy crashed on Node 22.23.3 (exit 139 for `tracker-write-language-probe`).
|
|
68
|
+
- `scripts/temp-cleanup-probe.js`: a held tree's error after the retry bound is `EBUSY` on Node 20.20.2 (the 1.36.297 candidate's public CI) and on 22.11.0, and `EPERM` on 26.3.0. The probe accepts either; before, it required `EPERM`.
|
|
69
|
+
- `scripts/role-fallback-probe.js`: the dangling-ledger test removes its fixture by the path below `os.tmpdir()`, which is the only spelling the probe's cleanup guard accepts.
|
|
70
|
+
- On GitHub's Windows runners, `os.tmpdir()` is an 8.3 short name (`C:\Users\RUNNER~1\...`).
|
|
71
|
+
- The fixture is made below the long real path, and the test passed that path, so the guard refused it: 79/80 in the second 1.36.297 candidate's public CI.
|
|
72
|
+
- With TEMP set to an 8.3 short name on this machine, the old probe gives the same 79/80, and the new one passes 80/80. The guard itself is unchanged.
|
|
73
|
+
- `scripts/memory-migration-test-support.js` makes its fixture folder below `fs.realpathSync.native(os.tmpdir())`, the spelling the product uses for memory folders.
|
|
74
|
+
- Before, it used `fs.realpathSync`, which keeps an 8.3 short name.
|
|
75
|
+
- The CI's Windows `fast` job had stopped at role-fallback, so the `test:fast` leaves after it were run here under an 8.3 TEMP: 45 of 53 passed.
|
|
76
|
+
- The 8 failures were memory probes. In 3, test hooks compare the path the product opens with the fixture path as text, so they never fired. The other 5 restore with a write policy (the problem above, T-0350).
|
|
77
|
+
- After the change, the 30 role-fallback and memory leaves pass under the 8.3 TEMP and under the normal one. The 5 policy-restore probes pass only because their fixture path is now the real path; T-0350 is still open.
|
|
78
|
+
|
|
79
|
+
## 1.36.296 - 2026-10-02
|
|
80
|
+
|
|
81
|
+
- Review control and UI review in deep project folders on Windows now stop with a clear code instead of a Git failure, and Leerness never writes a ref the user's own Git cannot read (T-0326). Every ref Leerness keeps for them (`refs/leerness/<family>/v1/project-<64 hex>/<64 hex>`: the authority floor, review runs, attempts, dispatches, results, proof use, provider observations, locators and review-control batches) has 166 to 176 characters. On Windows, Git without `core.longpaths` cannot lock a ref whose lock file path reaches 260 characters, nor read one whose file path does (measured with Git for Windows 2.54.0: `update-ref` works up to a 259-character lock path, a read up to a 259-character ref path), so with an ordinary `.git` the first calls failed from a 73-character project folder and every one from 88, as `git_failed` or `publication_uncertain`. Before such a call, Leerness now asks the user's own Git to read a ref name of the same path length that Leerness never creates (`git symbolic-ref -q`, which writes nothing); if Git cannot, the call fails `git_long_paths_required` before Git runs and writes no ref. Because Git answers itself, this follows how it combines configuration levels, the reftable format and the path spelling it uses. With `core.longpaths` on (`git config core.longpaths true`; in Git for Windows 2.54.0 a global `false` wins over the repository's `true`) those calls work. Leerness adds no long-path option to its own Git calls: measured with the same Git, the user's own Git without `core.longpaths` cannot read a ref written that way, and `git log --all` (exit 128), `git fsck` (exit 2), `git gc`, `git repack -a -d` and `git prune` (exit 128) and `git maintenance run --task=gc` (exit 1) then fail in that repository. Turning `core.longpaths` off again later brings those failures back for refs already written. In a narrow range of folder depths, where some families fit and a longer one does not, a flow can still stop partway, now with this code. Other platforms are unchanged.
|
|
82
|
+
- Found while running the full test suite from a temporary folder 11 characters deeper than usual (the authority-floor suite failed 13/13 and passed from the default folder). Tests, with the user's global and system Git configuration replaced by test files: in a project deep enough that every ref is past the limit, an authority-floor initialization and opening (`scripts/ui-review-authority-floor-probe.js`), a review-control claim and read (`scripts/review-control-probe.js`) and a UI review run observation (`scripts/ui-review-run-probe.js`) are refused on Windows without changing any file in the project, and work once `core.longpaths` is on in the repository (the first two) or in the global configuration (the third), after which the user's own `git log --all` and `git fsck` succeed (and `git gc` for the floor). At the exact boundary, without the setting, a claim whose lock path has 259 characters (with a capital dotted I in the folder name) works, one whose lock path has 260 is refused without writing a ref, and a claim whose ref path has 259 and lock path 264 characters, written with the setting on, can still be read but not advanced. With a global `true` and a repository `false`, and with a global `false` and a repository `true`, a claim is refused exactly when the user's own Git cannot lock a ref of the same length, and what is written is readable by that Git. A reftable repository in a deep folder needs no setting, a path given to `ls-tree` after `--` is not taken for a ref, and a damaged control ref in a deep folder with the setting on gets the same code as in a shallow one. A provider observation whose ref alone is past the limit (`scripts/openai-ui-review-observation-probe.js`) is refused with this code rather than `publication_uncertain`, and a later GET publishes it once the setting is on, without a second POST. On other platforms every case works without the setting. `docs/review-control-api.md` lists the new code and the limits.
|
|
83
|
+
- `lesson drop` and `decision drop` no longer refuse entries whose text the Markdown archive could not carry, so a lesson saved with surrounding spaces, only spaces, several lines or a tab can be removed and restored (T-0328). The archive is one line per field with control characters made spaces, and its reader trims, so such entries failed the lossless-archive check (`archive_lossy`) and stayed in the store for good, although `lesson save` keeps text as given. The owner chose exact preservation: an entry whose known fields hold a string (or null) the plain lines do not give back gets one more archive line right after its heading, `- Exact JSON: {...}`, holding all its known fields; DEL, C1 controls and the line and paragraph separators are escaped as well. Its plain lines follow as before for other readers, and entries the plain lines carry get no extra line, so existing archives and ordinary drops keep their bytes. `memory restore` reads such an entry from the exact line alone and brings it back exactly; a cut that removes the line also removes the plain lines after it. Both checks run on what a restore reads, the archive as stored in UTF-8 (a lone surrogate would become U+FFFD) and the selected block trimmed. A selection is refused as `archive_entry_invalid` without writes, also when its other entries are intact, when any heading section in it gives no entry: an exact line that is damaged or cut off at the marker, an exact section that differs from what the writer wrote for its entry (an edited heading or plain line, or the next entry's lines after its heading was removed), a plain section holding two entries, an entry that lost its lines, an exact line that lost its heading, or a section that is not an entry. Before, such a section was left out while the whole drop block was removed. This changes older archives with a `### Notes` section added by hand inside a drop block, or a note line starting with `- Exact JSON`: the restore now stops and names the repair (move the notes out of the block, rename the line). A bare `###` (an empty date or title whose trailing space an editor stripped, or a cut right after such a heading) starts its own section instead of joining the entry before it. A block with an exact line is read from it when the section matches what the writer wrote, line endings and trailing spaces aside; a plain decision block headed "Template" is still skipped. Hand-edited or cut archives are protected only in the tested cases: a cut right after a decision's heading still restores a heading-only decision, an indented exact line is read as plain text, and a cut that removes whole entries or falls inside a heading line cannot be noticed (the archive does not record how many entries a drop removed); T-0331 closes this class for new drops with an integrity record (below). Untouched drops of several entries whose non-final entry ends with an NBSP or another space JavaScript trims restore exactly (they were refused during review round 4). Conflict checks read the entries the restore will write, rendered like the active side, so a cut after an exact line no longer hides a duplicate; for decisions they keep titles starting with "Template", so an undated "Template x" decision, which now drops through its exact line, is not restored over an active one without `--force`. A drop by a target containing quotes is selectable, listed by `memory archive list` and counted by `memory status`, health and session close (one header reading for all of them and brainstorm). Unknown fields and values that are neither strings nor null are still refused. T-0193's two tests that pinned the refusal of multi-line values now check drop and exact restore instead.
|
|
84
|
+
- `scripts/memory-archive-retention-probe.js` (40 checks, was 11): exact round trips for both surfaces (padding, whitespace only, tabs, NEL, U+2028, DEL, a lone surrogate, an empty tag or reason, another date form, text that imitates "- Tag:" or a new heading), still refusing an unknown field and non-string values; the CLI path from a padded `lesson save` to drop and exact restore; the trimmed-text conflict rule with `--force`; nine damaged or cut-off exact lines, one damaged entry among two, a cut exact line among several selected drops and an entry left with only its heading, all refused without writes; an archive cut after an exact line or missing its last line restored exactly; an empty text at the end of a block; a drop target with quotes restored by date and by target; a non-string tag still refused (`store_item_unsupported`, before the archive); a duplicate found from an exact line alone on both surfaces (`--force` still restores); a cut right after an undated heading refused; headings an editor stripped of their trailing space restored in full; a plain decision block renamed "Template" skipped as before; an exact line that lost its heading refused; a quoted target listed and counted; fenced code in a decisions drop block not read as an entry; an exact entry unable to take over a neighbour whose heading was removed (both surfaces, both orders, also with `--force`); merged plain entries refused; an exact block whose heading was renamed refused; an undated "Template x" decision conflicting with an active one; an archive turned to CRLF with trailing spaces stripped restored exactly; a note line starting with `- Exact JSON` refused; a drop made by a target with a tab selected by the target as the header wrote it. Ablation in fresh copies: before T-0328 27 of the 38 fail, and undoing any one of 23 parts fails at least one check; a 39th check covers untouched drops with an NBSP, EM SPACE, ideographic space or BOM at the end of a non-final entry (fails on the round-4 candidate). Cross-model review (gpt-6.1-sol): rounds 1 to 3 NO-GO, two P2 and two P3 each, all fixed; round 4 NO-GO, three P2 and one P3: the P2 outside the damaged-archive class fixed, the two inside it documented as gaps under the stop rule set before that round; round 5 GO with notes (two P3, documentation and a pinning test), applied. `docs/memory-item-admission.md` describes the line.
|
|
85
|
+
- `verify-claim` shows the earlier bug fixes behind the files a task names (T-0330, from the owner's request to review a proposed quality system: its "corrective and preventive action" step). `bugfix receipt <T-ID> --areas "lib/orders.js,src/sync"` declares the files or folders a fix is about. When a later task's evidence names a file inside one of them, verify-claim prints "📚 Learned from past fixes (advisory, not a gate)" for receipts whose task is marked done (in the tracker or retained history; only the words done, completed, verified and 완료 count), with each fix's id, the files that matched, its declared root cause and the probe to re-run ("task marked done — check that it exits 0": done is a tracker status, not proof that the probe passes), newest first. The others are listed apart as "🔧 Bugfixes not known to be done" with the task status, "task not in the tracker" or "status unknown" when retained history cannot be read, and no probe line. A receipt is joined to the tracker by task ID only, so a reused or colliding ID shows that task's status (documented). `--json` has `pastFixes` (`readable`, `fixes` with `taskStatus`, `status` and `statusNote`, `skipped`). It appears whatever the task's status, never changes `ok`, `reasons` or the exit code, and does not run the probes; `verify-claim --all` and `gate --claims` do not include it. Areas are declared, never inferred (inferred hotspots were rejected when the receipt was designed): repository-relative, written one way (backslashes, a leading `./`, a trailing `/`, duplicates). The call is refused and the receipt left as it was (the usage counter in `.leerness/cache` still moves, as for every command) for a blank value or an empty list (`empty_areas`) or for `.`, an absolute path or drive letter, `..`, `.` or empty segments and control characters inside a path (`invalid_area`; whitespace around each area, line breaks and tabs included, is trimmed first); a path that does not exist is saved and reported (`missingAreas`). Matching compares repository-relative evidence paths by segment (`src/sync` holds `src/sync/a.js`, not `src/syncer.js`), ignores case on Windows and macOS, and leaves out the task's own receipt. A malformed stored `areas` skips that receipt and is reported, but does not invalidate the store, which the bugfix done gate also reads. The receipt's success lines, the `bugfix list` line (now with the areas) and the new messages follow the project language; the module's other messages are still Korean. `docs/bugfix-areas.md`.
|
|
86
|
+
- `scripts/bugfix-areas-probe.js` (`npm run test:bugfix-areas`, also in `test:commands`, 17 tests, each on its own copy of an initialized project so `--match` runs one alone, and a `--match` that selects no test fails): the area rule; storing, echoing and listing areas; whitespace around an area trimmed; blank and unusable values refused with the receipt left as it was; with normal CLI settings nothing outside `.leerness/cache` changes on a refusal while the usage counter moves; a missing path saved with a warning; fixes whose task is marked done (done, an older `verified`, `completed` or `완료` row, a task retained into history) shown as past fixes with "task marked done" wording, and the others (in progress, `unverified`, `not-done`, `미완료`, not in the tracker, retained history that cannot be read) apart, newest first, by path segment; the verdict, reasons and exit unchanged for a passing and a failing claim once the advice is present; no advice for the task's own fix, for files outside every area or without declared areas; a malformed area skipped and reported while the store stays valid; an unreadable store reported only when the evidence names files; numeric order, relative paths only and case in the lookup; the `bugfix start` hint; English output with no Korean in the new blocks and the Korean list line kept byte for byte. Ablation in fresh copies: before T-0330 all 16 then-present tests fail, and undoing any one of 35 parts fails at least one test. Cross-model review (gpt-6.1-sol): round 1 NO-GO (three P2, four P3) and round 2 NO-GO (two P2, four P3), all fixed; round 3 GO with notes (three P3) and round 4 GO with notes (one P3, a test that left a temporary folder behind on a bad `--match`), applied; the substring status test that verify-claim and verify-claim --all still use is filed as a separate task.
|
|
87
|
+
- `docs/quality-system.md` (T-0329) maps quality terms (QA, QC, quality gate, review, RCA, CAPA, NCR, traceability, policy, metrics) to the commands that already do them, states what may block (evidence Leerness checks itself; the existing heuristic checks that also block, namely verify-claim's static test count, optimism, honesty, stub and evidence checks and gate's lazy detection; other heuristics stay advisory and new ones ship as advice; new blocking switches start off), and lists the gaps (acceptance criteria per task, one quality-policy section, lessons tied to files, recorded verdicts, request-to-task links) and what is left out on purpose (a separate `quality.yaml`, `qa-plan` and `qc` commands, FMEA scores, industry quality systems in the core). Linked from the README.
|
|
88
|
+
- Memory drop archives get an integrity record (T-0331, the owner's choice after T-0328's review rounds left hand-edited or cut archives as documented gaps). Each decisions or lessons drop block starts, right after its header line, with `- Archive check: N entries, sha256 <hex>`: the number of entries the drop removed and a hash of the entry text it wrote after the record, ignoring CRLF line endings, trailing spaces or tabs and the block's ends (not a lone CR), hashed as UTF-8 as it is stored; the header line and the archive title are not hashed. `memory restore` refuses a selected block with `archive_changed`, without writes and `--force` included, when its entry text no longer matches, when the first line after the header is not an exact record and a line in the block carries the record's content (the words "archive check" followed by an entry count, or with a 64-hex hash; spaces, invisible format characters such as a byte order mark, and case ignored), or when the header line after the target or the archive title carries it; with an exact record first, the rest of the block is covered by the hash and not scanned. A line that only mentions an archive check is text, so older archives with such notes restore as before; one that carries a count or a hash where it is scanned is taken as a damaged record until it is edited. That catches T-0328's gaps in recorded blocks (a decision cut right after its heading, an indented exact line, removed entries, a cut inside a heading); with a matching record the reader must find exactly N entries. Blocks without a record (older drops) are read with the structural checks as before; deleting the record line opts an intentionally edited block out (moving it into another block does the same). Older versions skip the line (text before the first heading). Brainstorm leaves the record, only in its place, out of its archive match and preview. The record counts toward a write policy's archive input limit. Decision fence stripping (the archive reader, decisions.md parsing and the dated-block count) gives the same result in linear time; it searched to the end again from every unclosed opening. It detects accidental edits and cuts, not every combination (a record whose words were changed, not only spaced or cased, or that an editor wrapped onto two lines, reads as no record); it is not authentication. `docs/memory-item-admission.md` describes the record.
|
|
89
|
+
- `scripts/memory-archive-check-probe.js` (14 checks, in `test:memory-archive` and the `test:commands`, `test:core` and `test:fast` chains): the record's place, count and hash with the entry bytes unchanged; untouched drops restore exactly, also with CRLF and stripped trailing spaces; twenty-four edits and cuts refused without writes, `--force` included (among them an indented, joined, lowercased or title-moved record, one after a no-break space, an em space or a byte order mark, with a no-break space, a zero-width space or no space between its words, with a misspelled count word or a hash cut short, each with a changed value or a cut, and an LF changed to a lone CR); a decision heading cut refused, also with a record after a no-break space; a wrong count with a matching hash refused; a deleted record reads an edited block as before; older blocks restore next to recorded ones, also with note lines or header text that only mention an archive check, and a recorded block restores under an archive title that does; the reader skips the record; brainstorm leaves it out and still finds an older note line that starts the same way; the record counts toward the archive input limit. `scripts/memory-write-budget-cli-probe.js` builds its expected drop text with the record. Detection reads a line repeating the words 16,000 times, and the restore's four reading paths read runs of 128,000 spaces, in under a second each (the round-3 and round-4 candidates took 6.3 and 4.6 to 15 seconds); an added tab at the end of every line is ignored like a stripped space; decision fence stripping gives the original expression's result on 20,000 random texts and reads 64,000 unclosed openings in under a second (the round-5 candidate took 5.8 to 12.3 seconds; T-0335 corrected both checks, below); brainstorm finds a record-shaped line in a plan archive. Before T-0331, 4 of 14 pass (the four controls); ablation: each part undone alone fails at least one check (22 parts after review round 2; 4 after round 3, two of them the count and hash alternatives again on their rewritten line; 5 after round 4; 4 after round 5). Cross-model review (gpt-6.1-sol): round 1 NO-GO (two P1, one P2, two P3) and round 2 NO-GO (one P1, one P2, one P3), all fixed; round 3 NO-GO (two findings inside the stop rule's class, documented as limits, two outside, fixed) and round 4 NO-GO (one outside, fixed: trailing trims written as `[ \t]+$`, T-0328's exact-section comparison included, took quadratic time on long runs of spaces and now scan back); round 5 NO-GO (one P2: the decisions reader's fence stripping took quadratic time on unclosed openings; two P3: brainstorm also stripped plan archives, and this entry's ablation total), fixed and, under the stop rule set before it, not reviewed again. The T-0328 probe's hand-edit tests now delete the record first, so they keep testing the structural checks (40/40).
|
|
90
|
+
- verify-claim reads a task as done only when its tracker status is exactly `done`, `completed`, `verified` or `완료`, in any case, with the cell's spaces trimmed, also inside one pair of brackets as older trackers wrote statuses (`[완료]`): one predicate for verify-claim, `verify-claim --all` (which `gate --claims` runs), the claims baseline, lazy detection, past-fix advice, the bugfix done gate, `task fix-evidence`, session close's completion-honesty checks and the TodoWrite export (T-0332). verify-claim matched substrings, so `unverified`, `not-done`, `uncompleted`, `undone` and `미완료` rows were checked as done claims and listed by `--all`, and `--all` picked `verified` rows that the per-task check then did not check as done claims: an older or hand-written `verified` row with evidence that names nothing passed. The claims baseline took a third set (without `verified`), so such a row could not be baselined once it failed. Lazy detection now reads `완료` and the bracketed form as done work too: a `완료` row with placeholder evidence is reported, and a project whose finished tasks are marked that way has done work, so its absence signals block as they do with `done`. With the bugfix done gate on, `task update --status 완료 --force` (or `Done`, `[완료]`) is held like `done` while the reproduction still fails; before, it was recorded past the gate. `task fix-evidence` reads a done status the same way; its list of placeholder evidence stays its own (empty, `user-request`, `-` or a bare plan link, where lazy detection also reports `n/a`, `tbd` and the like). Session close's two completion-honesty checks (placeholder evidence, unresolved optimism) took its report's done bucket, which counts `finished` and `complete` but not `완료` or `[완료]`; they now take the done rows above, while its task counts and recent references keep their buckets. `task export` wrote `completed` only for `done`, so `완료`, `[완료]`, `verified` and `Done` went out as `pending`, and `task sync --from` the same file made them `planned`; every done word now exports as `completed`, and a sync leaves a row that already reads as done as it is written. Progress counters and percentages, and the active-task checks of `task add` and `idempotency audit`, keep counting the status `task update` writes. Any other status is not read as done: a word that never matched stays so (`finished`), and one that only contains a done word (`done ✓`, `done (partial)`) is no longer a done claim for verify-claim and `--all`. In a project whose claims baseline was made before T-0332, a `verified` row that now fails is a new failure, since the CLI never recreates a baseline: fix its evidence, or replace the baseline through review as for any new failure; baseline entries for rows no longer read as done stay inactive. The two selftests that pinned the old expressions now pin the shared predicate inside the function's body; searched in the whole source, each pin had matched its own string.
|
|
91
|
+
- `scripts/done-status-probe.js` (`npm run test:done-status`, also in `test:commands`, 8 tests; rows made done through the product, then only the status cell edited): the predicate's table; verify-claim checks exactly the done words as done claims (a failing claim with evidence that names nothing) and leaves the others unchecked; `verify-claim --all` lists exactly those rows, `verify-claim baseline create` takes exactly their failures, `verified` included, and `--all` then passes; lazy detection reports placeholder evidence on exactly those rows, and a project whose only finished task is `[완료]` or `완료` has done work while one with `미완료` or `not-done` does not; with the bugfix done gate on and a failing reproduction, `done`, `완료`, `[완료]` and `Done` written with `--force` are refused with the tracker unchanged while `not-done` is written; `task fix-evidence` lists exactly the done rows with placeholder evidence; session close's completion honesty counts exactly the done rows (`[완료]` with placeholder evidence reported, a `완료` row's unchecked API claim reported, `finished` and `not-done` left out) while its task counts keep their buckets; a TodoWrite export and sync round trip exports exactly the done words as `completed` and leaves those rows as written. The T-0330 status-word test adds `[완료]` (done) and `[미완료]` (not done). Before T-0332 all eight fail; ablation: each of 18 parts undone alone fails at least one test (11 parts, then 2 for the write side and 3 and 2 after review rounds 1 and 2). Cross-model review (gpt-6.1-sol): round 1 NO-GO (P2 session close's completion-honesty checks, P3 the fix-evidence wording) and round 2 NO-GO (P2 the TodoWrite export, P3 a comment), all fixed; round 3 GO. Merged with T-0331, the tree passes the whole npm test (91 steps, in two runs; e2e 468/468).
|
|
92
|
+
- `task fix-evidence` speaks the project's language (T-0333, found while testing T-0332): in an English project it printed Korean throughout (the header, the guidance, each row's suggested command, request and evidence lines, and the results of `--set` and of an empty list). Its own messages now follow the project language, chosen as for other commands (`--language`, then `LEERNESS_LANG`, then the project's manifest): English projects get English text that names what the command takes (done rows whose evidence is empty, `user-request`, `-` or only a plan link) and counts the plan links `--set` appended; the Korean output is unchanged byte for byte. Which rows are listed and what `--set` writes are unchanged. Errors raised by the shared tracker write path that `--set` goes through (the row-loss guard, in Korean, and the managed-text checks, in English) are left as they were here; T-0336 (below) makes them follow the project language in every command.
|
|
93
|
+
- `scripts/fix-evidence-language-probe.js` (`npm run test:fix-evidence-language`, also in `test:commands`, 5 tests, rows made through the product): the exact listing and `--fail-on-candidates`, `--set` with and without kept plan links (what `--no-preserve-link` writes too), and the empty list, in an English project (no Hangul) and in a Korean one (the lines the command printed before), and the language order in both directions (`--language` over `LEERNESS_LANG`, `LEERNESS_LANG` over the manifest). Before T-0333, 2 of 5 pass (the two Korean tests); ablation: each of 9 parts undone alone (8 English call sites and the language choice) fails at least one test, a changed Korean word fails the Korean test, and the 4 checks added after review round 1 each catch their variant. Cross-model review (gpt-6.1-sol): round 1 NO-GO (P2 the shared write-path errors, scoped out and filed; three P3, fixed); round 2 GO with notes (the scoped-out errors confirmed as accurately stated).
|
|
94
|
+
- Decision fences are found in one pass (T-0335, found in T-0331's last review). Two readers matched fenced code with expressions that searched to the end of the text again from every opening that never closes: decision line offsets (`_decisionBlocksWithOffset`, decisions.md read with line numbers; 64,000 such openings took 4.0 to 14.0 seconds) and fence stripping (`_stripDecisionFences`: the decisions archive reader, decisions.md parsing and the dated-block count). T-0331 had bounded the stripping by the last closing it could match, which still left openings separated by `\r`, U+2028 or U+2029 quadratic, since they share one `\n`, with a closing at the very end (64,000 took 9.1 to 14.2 seconds in the stripping and counting readers). Both readers now use one scanner that applies the expressions' own rules (an opening at a line start, its first line up to the next `\n`, the first valid closing after it) and give the same results. T-0331's random-text check drew only 889 distinct texts of its 20,000 (this probe's first version 1,193 of 30,000): their multiply-and-mask generator loses low bits in double precision, and its seed falls into a cycle of 10,466 values. Both now use xorshift, and T-0331's report and entry are corrected. Times are from two runs per reader and shape on the development machine.
|
|
95
|
+
- `scripts/decision-fence-offset-probe.js` (`npm run test:decision-fence-offset`, also in `test:commands`, 3 tests): the same results as both expressions on 30,000 random texts (more than 25,000 distinct; also 1,000,000 with 902,593 distinct in a separate run, 0 differences), a closed fence still hiding a heading with the original offsets, and seven shapes of 64,000 unclosed openings (three separated by `\r`, U+2028 or U+2029 with a closing at the end) read in under a second by the offsets, stripping and counting readers. T-0331's probe adds the `\r` shape. Before T-0335, 2 of 3 pass (the timing check fails; on the round-1 candidate the three new shapes took 7.3 to 11.5 seconds per reader in three runs; with the scanner every reader and shape takes at most 15 ms); ablation: each of 4 parts of the first version and 6 parts of the scanner undone alone fails at least one test (one variant, which searched for the next opening inside a match, failed the random texts and then ran out of memory). Cross-model review (gpt-6.1-sol): round 1 NO-GO (P2 the shapes separated by `\r`; P3 the generator), both fixed; round 2 GO with notes (no P1 or P2; P3 the distinct-text counts were mixed up between the two probes, and three time ranges were not in the attached logs), corrected after the review from a replay of both generators and two logged timing runs, and not reviewed again.
|
|
96
|
+
- `task sync --from` applies only what TodoWrite changed (T-0334, the owner's choices; found while fixing T-0332). It mapped every TodoWrite status back to one tracker status and rewrote any row that differed, so exporting with `task export` and syncing the same file back turned a dropped task into planned (bringing it back), requested and on-hold into planned, and blocked and incomplete into in-progress. Now `task export --to` and `--json` (what goes to TodoWrite; the plain summary writes nothing) record, after writing the export, each row's ID, request, tracker status and exported TodoWrite status in `.leerness/cache/task-export-baseline.json`, with the project's folder (a record copied from another folder is not read; an export that fails leaves the record as it was). Sync finds each item's row by its text and by the ID the record holds for that text (the exported text, or one a later sync saw for that row, kept in the record as an alias), so a row renamed with `task update --note` is still that row instead of coming back as a new one, and it writes only items that match one row and no other item: a text reused by another row after a rename, a text on several rows or several items, or two texts for one row is not written and is reported as ambiguous, unless its items still hold what was exported. A matched item is compared with its row's record: the status that was exported is left alone, even when the tracker row was changed since; a changed one is applied (`completed` to done, still held by the bugfix done gate; `in_progress` to in-progress; `pending` to planned; `cancelled`, which export writes for dropped, now back to dropped); if the row already exports to the new status (both sides made the same change, or the tracker holds a more specific status such as blocked) nothing is written and the record moves; a row that changed differently in the tracker since the export is not written and is reported as a conflict (ID, both sides' old and new statuses). Each decision reads the row again, and the write happens only if the row still has that status under the tracker lock, so a row another command changed meanwhile (also while sync waits on a completion probe, which runs outside the lock) is reported as a conflict instead of being overwritten. A row the record does not hold (added after the export) is compared with what its current status exports to, as the first version of this fix did, and then joins the record, as imported items do; sync never creates a record, and without one (or with a damaged one) every row is compared that way. Conflicts and ambiguous texts make sync exit 1 (`ok: false`, with `conflicts` and `ambiguous` in `--json`); the other items are applied, and syncing the same file again changes nothing. The status mapping is a `Map`, so hand-written statuses named like object keys (`constructor`, `__proto__`) export as `pending`. `commands` lists `task sync` and says what export records. Not handled: items of one text that only swapped statuses (they look unchanged); two syncs at once racing on the record (the last writer wins; the next sync settles it through the rule for alike changes); an export that never reached TodoWrite (a `--json` export that was only viewed, say) still moves the record, so TodoWrite's older statuses then read as changes and are applied over tracker edits made between the two exports; a row deleted by hand from the tracker comes back as a new row (or its item goes to another row with the same text); a project moved to another folder is read without its record until the next export.
|
|
97
|
+
- `scripts/task-sync-roundtrip-probe.js` (`npm run test:task-sync-roundtrip`, also in `test:commands`, 19 tests, an English project with a row for every status plus `완료`, `verified` and `[진행]`): what export writes for each status, and that syncing it back changes no byte of the tracker; five changed items applied and the other rows untouched; new items imported with their status (`cancelled` as dropped) and added to the record; a tracker edit after the export kept, and a change on both sides reported and not applied (also in the text output); a change both sides made alike neither written nor reported, with the record moved; an export to a path that cannot be written leaving the record as it was; a second sync of the same changed file changing and reporting nothing; duplicate request texts quiet when unchanged and reported, unwritten, when changed (rows, file items, a new text twice); a row added after the export joining the record, and items that follow a tracker rename compared with their row's record (a conflict found that way, later tracker edits kept); a text reused after a rename quiet when unchanged and reported, unwritten, when changed; a record copied from another project not read; rows changed while sync waits on completion probes (another row, the row itself, with and without a record) kept and reported; a text acknowledged after a rename kept as that row's alias, so a row that reuses it later does not get its item; the fallback without a record, and with a damaged one (left as it is); rows renamed in the tracker matched by their recorded ID (also with the new text in the file); hand-written statuses named like object keys; with the bugfix done gate on, a round trip not reaching it and a completion held on every sync. Before T-0334, 0 of 19 pass; the round-1 candidate passes the first 4, the round-2 candidate 13, the round-3 candidate 16 (not the two round-3 findings, nor the damaged-record test, which now also has a damaged alias list). Ablation: each of 3 parts of the first version and 32 parts of the final code undone alone fails at least one test (two survived until the tests held the case they matter for: accepting a damaged record item, and reading the row again before deciding, which, with the check under the lock, only keeps a row the tracker had meanwhile set to what TodoWrite says from being reported as a conflict). Cross-model review (gpt-6.1-sol): round 1 NO-GO (P2 the current status is not what TodoWrite last saw; P2 duplicate request text; P3 inherited object keys), all fixed with the owner's choice of a baseline; three more cases found before round 2 (a change both sides made alike reported as a conflict, the record written before the export file, a row renamed in the tracker imported again) fixed; round 2 NO-GO (P2 a row synced without a record never joined it, so a later tracker edit was overwritten; P2 a text reused after a rename went to the new row; P2 a record copied from another project matched an unrelated row by ID), all fixed; round 3 NO-GO (P2 decisions used the rows read when sync started, so a row changed while sync waited on a completion probe was overwritten, a regression from round 2; P2 a text acknowledged after a rename was not kept, so a row that reused it later got its item), both reproduced and fixed, and the owner chose a fourth round on these two only; round 4 GO (no findings).
|
|
98
|
+
- Errors on the shared progress-tracker write path follow the project language (T-0336, from T-0333's cross-model review). The row-loss guard (`E_PROGRESS_ROW_LOSS`), which refuses a write that would drop tracker rows it cannot read, printed Korean in English projects through the commands that rewrite tracker rows with it (`task fix-evidence --set`, `task add`, `task update`, `task sync` and others); English projects now get English, and the Korean text is unchanged byte for byte. The checks of `lib/managed-text.js` (`E_TEXT_ENCODING`, `E_TEXT_LIMIT`, `E_TEXT_LOCK`, `E_TEXT_TYPE`, `E_TEXT_CHANGED`, `E_TEXT_SNAPSHOT`), which guard every managed document Leerness edits (the tracker, plan, rules, AGENTS.md and CLAUDE.md, handoff, team and environment files and others), printed English in Korean projects; they now print Korean there, and the English text is unchanged byte for byte. `writeProgressRows`' own check for a caller without the checked text (`E_TEXT_SNAPSHOT`, English only as well) follows the project language too. The owner chose to pass the language in rather than translate at the CLI's last error handler by code, which would have missed the commands that print an error themselves: the CLI registers how to find it (`setErrorLanguage`), the same rule as the commands' own text (`--language`, then `LEERNESS_LANG`, then the manifest of the project named by `--path` or a path argument), asked when an error is built, so the text output, the `--json` `error` field and messages another command puts inside its own (as `mode set` does) all follow it. `mode set --json` keeps its own Korean text in every project (T-0164), while the managed-text part inside it follows the project. Two commands put their own sentence in place of such an error, and those follow the project language too, each existing sentence kept for its language: `memory restore` of an archive with invalid UTF-8 (`archive_corrupt`; for the plan the sentence was English, for decisions and lessons the same refusal was Korean in every project; review round 1) and `task sync --from` with an import file it cannot read as UTF-8 JSON (review round 2). A program that loads `lib/managed-text.js` without the CLI keeps the English text. Error codes are unchanged. As for the commands' own text, a project whose language is given only by `.leerness/LANGUAGE`, with no language in its manifest, counts as Korean (none installed by `init` is like this); `scripts/rule-text-probe.js` builds such projects for an English test, so it now runs its commands with `LEERNESS_LANG=en`. Still in one language: the errors of the checked reader and writer under managed-text (`E_STORE_*`, `E_OUTPUT_*`) and of the state lock; `context history`, whose own messages are all English, reports an unreadable history record (`history_record_invalid`) in English; and the note a few commands add when a later save fails after an earlier one (such as "Plan archive was saved before active-plan publication failed") stays English, so such a message mixes languages in a Korean project. These are left for a separate task.
|
|
99
|
+
- `scripts/tracker-write-language-probe.js` (`npm run test:tracker-write-language`, also in `test:commands`, 15 tests; rows made through the product, then a malformed row with six values and no closing pipe, or the bytes 0xFF 0xFE, written as a Buffer; every project folder has Hangul in its name, and the language checks read the output without the folder paths): in an English project (no Hangul) and a Korean one (the texts printed before), run from outside the project with `--path`, `task fix-evidence --set`, `task update` (also with `--json`) and `task add` stop on the row-loss message and the first two on the encoding message, leaving the tracker unchanged; the language order in both directions for both errors (`--language` over `LEERNESS_LANG` with `fix-evidence`, `LEERNESS_LANG` over the manifest with `update`); the project named by `--path`, else by a path argument, for `task update` and `mode set` run inside a project of the other language; `memory restore` of a plan, decisions or lessons archive with invalid UTF-8, and `task sync --from` with an import file holding invalid UTF-8 (code `E_TEXT_ENCODING`) or invalid JSON (`invalid_task_import`), in both languages and with `--json`, leaving the files unchanged; `mode set`, which puts the managed-text message inside its own, in both languages and with `--json`; `writeProgressRows` called directly for both row-loss messages and the missing-text check, with their codes (the second row-loss message, fewer rows to write than were read, has no command path; `writeProgressRows` is exported for this); every managed-text message in both languages with its code, and English when nothing, something that is not a function or a failing resolver is registered. Before T-0336, 4 of 15 pass (the English encoding, Korean row-loss, English `mode set` and English `task sync` tests, whose texts were already in the project's language); ablation: of 38 parts undone or altered alone (30, then 6 after review round 1 and 2 after round 2), 37 fail at least one test and one, an equivalent variant, survives as expected (without the function check a resolver that is not a function throws and reads as English); the unchanged candidate passes, and the reverting parts together pass exactly the four tests the tree before T-0336 passes. Cross-model review (gpt-6.1-sol): round 1 NO-GO (P2 the plan restore's English sentence in place of the managed-text error, with the reverse Korean-only refusal for decisions and lessons beside it; P3 no path-argument case; P3 Hangul in folder names would break the language checks), all fixed; round 2 NO-GO (P2 `task sync --from`'s English sentence in place of the managed-text error; P3 this entry's ablation count), fixed. round 3 GO with notes (attach the whole npm test). `scripts/e2e.js`'s whats-new block parsed only the first 50,000-character chunk of the MCP answer, and with this entry its answer for the two newest CHANGELOG versions (1.36.296, unreleased, and 1.36.295) no longer fits in one (51,798 characters with T-0336, 58,836 with T-0334 as well, measured before this round's sentences; 45,938 before T-0336), so it now follows `nextCursor` and joins the chunks before parsing, as an MCP client does, and fails on an MCP or tool error, a cursor that is not a string of digits, or an answer without exactly two versions; that check run alone passes on one chunk and on two, and fails with the first chunk only, a wrong limit or a failing tool call. Cross-model review of this test change (round 4): GO with notes, its three P3 (those error cases, the cursor check, this sentence's wording) applied and not reviewed again. The whole npm test on T-0333, T-0335 and T-0336 (before T-0334 and this e2e change): 189 of 191 other steps and e2e 465 of 468. Besides the whats-new block, the failures do not come from T-0336: the test runner gave TEMP with forward slashes, which `scripts/auto-update-hooks-probe.js` compares with `os.tmpdir()` (10/10 with a native path), and selftest and doctor ran past the 300-second limits of the installed cleanroom probe and two e2e blocks while the machine ran several suites at once (measured side by side there, with and without T-0336: selftest 340 and 340 seconds, doctor 397 and 397). On the tree with all four tasks the T-0336, T-0334, done-status, fix-evidence, decision-fence, bugfix-areas, rule-text, managed-text, mode-text, plan-text and memory restore probes, lint and e2e-core pass.
|
|
100
|
+
- The remaining fixed-language errors on the shared write path follow the project language (T-0337, T-0336's follow-up; the owner chose the core write path, the partial-save notes and the session handoff update). Memory input and output errors (`E_STORE_*`, `E_OUTPUT_*`: the decisions and lessons stores, the progress tracker and every managed document read or published through them) gave every project an English reason with Korean advice ("Memory input changed during operation: <file> — 원본을 보존하고 …"); an English project now gets English advice and a Korean project a Korean reason, each keeping the part it had. The diagnostic byte limit, the publication read, the handoff update in `session close` (`E_TEXT_FORMAT`: frontmatter not closed, reserved markers in the generated block, ambiguous markers) and two state-lock errors (`E_LOCK_OWNERSHIP_LOST`, `E_LOCK_BUSY`) were English everywhere and are Korean in Korean projects; the state-lock timeout (`E_LOCK_TIMEOUT`), its fail-open warning and the release failure were Korean everywhere and are English in English projects, while the reason recorded for `stateLockDiagnostics` keeps its one form. The ten notes that say what a partly finished save left behind (init file generation and installation steps, the nonsecret `.env` migration, `anchors draft --apply`, `plan remove`, `memory restore plan`, `rule remove`, `brief update`, `adapter`, `session close`) were English after errors in either language and now follow the project language. Codes are unchanged, and every existing text stays byte for byte in the language that had it. The shared modules ask `lib/error-language.js`, where the CLI registers the language of its own text (`--language`, `LEERNESS_LANG`, then the manifest of the project named by `--path` or a path argument; moved there from `lib/managed-text.js`, which still exports `setErrorLanguage`); a program that loads them without the CLI keeps the text they had before. An error from the file replacement underneath memory output (`lib/io.js`), which memory output passes on as `E_OUTPUT_CHANGED`, kept its one-language text here (a change caught by the Windows compare-and-set replacement in Korean, a hard link that could not be detached in English); T-0338 below covers it.
|
|
101
|
+
- `scripts/write-path-language-probe.js` (`npm run test:write-path-language`, also in `test:commands`, 19 tests): every memory input message (18 reasons; one only on Windows), 13 of the 17 memory output reasons, and a 14th on Windows (the other three are on the POSIX rename-away path, which only the source check below reaches), and the compare-and-publish refusals, the byte limit, the publication read and the three handoff errors, checked whole in six language states by direct calls in a child process (faults injected there); the state-lock messages the same way (timeouts on EEXIST, EPERM and ENOSPC, fail-open with its warning and recorded reason, a nested call after the owner record disappeared, releases that fail after the work succeeded with `E_LOCK_OWNERSHIP_LOST` and `E_LOCK_RELEASE` and their warnings, a busy lock); the registry's own answer in each state; a check that the sources name exactly the probe's English and Korean reason pairs, so a reason added in one language fails; through the CLI in English and Korean projects: a hard-linked tracker, decisions with invalid JSON (with `--json` and its `store_corrupt` code), a memory output race, an unclosed handoff frontmatter, eleven partial saves with their step counts compared between the languages, and the language order (`--language`, `LEERNESS_LANG`, the `--path` project rather than the cwd). `brief-text-probe.js`, `generation-text-probe.js`, `plan-text-probe.js`, `session-close-text-probe.js` and `history-retention-write-probe.js` run their CLI calls with `LEERNESS_LANG=en`: their fixtures have `.leerness/LANGUAGE=en` and no manifest, which the commands read as Korean, and they keep checking the English texts.
|
|
102
|
+
- The write primitives underneath follow the project language too (T-0338, T-0337's follow-up; the owner chose the texts that reach users and the dry-run refusal). In `lib/io.js` the compare-and-set refusal (`E_CONCURRENT_MODIFICATION`, also the one memory output passes on as `E_OUTPUT_CHANGED`) with its recovery backup and recovery artifact notes, the refusals of a symbolic link or a non-regular file (`E_UNSAFE_LINK`, `E_UNSAFE_FILE_TYPE`), the two Windows replacement failures (`E_ATOMIC_REPLACE`, `E_ATOMIC_REPLACE_UNCERTAIN`) and the notice that a damaged JSON file was moved aside were Korean in every project; the three hard-link detach failures (`E_HARDLINK_DETACH_FAILED`) were English in every project. The dry-run refusal users see (`dry_run_unsupported`, for example from `decision add --dry-run`), the dry-run guard's own text (shown inside `mode set --dry-run`) and `lib/git.js`'s text for git commands were Korean in every project. They now follow the project language; the CLI's refusal uses the rule of its other shared errors, so `mode --json` keeps its Korean text (T-0164). Codes are unchanged, every existing text stays byte for byte in the language that had it, and a program that loads these modules without the CLI keeps the old text. Left as they were (outside the owner's scope): the platform refusal and the publication buffer limit, which no current caller reaches, and two cleanup fallbacks that cannot be reached.
|
|
103
|
+
- `scripts/write-primitive-language-probe.js` (`npm run test:write-primitive-language`, also in `test:commands`, 10 tests on Windows and 8 elsewhere): every changed text in six language states by direct calls in a child process with faults injected there (the replacement cases only on Windows, where `lib/io.js` replaces files), the recovery backup and artifact notes built from the error's own fields; a source check that `lib/io.js` keeps exactly the four one-language texts left out and that each other error picks one Korean and one English text; through the CLI in English and Korean projects: `decision add --dry-run` (text and `--json`), `mode set --dry-run` (its human wrapper in the project language, its `--json` wrapper Korean, the guard's text inside in the project language), a damaged `glossary.json` moved aside by `glossary build`, and on Windows a change caught by the compare-and-set check under `task add --json`; the CLI refusal reached past `mode`'s own catch (`mode --json` keeps it Korean) and its Korean fallback when the project cannot be read; and the language order (`--language`, `LEERNESS_LANG`, the `--path` project rather than the cwd).
|
|
104
|
+
- Commands whose edits need a state lock refuse `--dry-run` with the dry-run refusal (T-0339, found while testing T-0338). Under `--dry-run` the CLI takes no state lock, since that would leave lock metadata, so `task add`, `task drop`, `task sync --from`, `plan add`, `plan remove`, `memory restore plan`, `register-pending` and `feature add` stopped with "Managed text requires its existing state lock" (`E_TEXT_LOCK`) before their first write could meet the dry-run guard, and `state start`, `record`, `verify` and `handoff` called themselves through the lock wrapper until the stack ran out ("Maximum call stack size exceeded"). The managed-text check now refuses as the guard does (`E_DRY_RUN_WRITE`, reported by the CLI as `dry_run_unsupported` and naming the file it would have written; `feature add` keeps its own error report with the guard's code), and `state` runs as the lock wrapper does under `--dry-run`, so its first write meets the guard. Nothing was written before and nothing is written now; without `--dry-run` nothing changes.
|
|
105
|
+
- `scripts/dry-run-refusal-probe.js` (`npm run test:dry-run-refusal`, also in `test:commands`, 6 tests): the managed-text check with and without the dry-run guard by direct calls; eleven commands with `--dry-run --json` on copies of a project prepared through the product (a task, a milestone, an archived milestone, a state run): `dry_run_unsupported`, the exact file, and no change in the project or in the redirected home, app data and temp folders (contents and modification times); `task add` and `plan add` in English and Korean projects, text and `--json`; `feature add` with the guard's code; and the same commands, and `feature add`, storing their result without `--dry-run`. On the tree before T-0339 it passes 1/6 (the controls).
|
|
106
|
+
- The e2e check of the `selftest --json` contract (stdout is one JSON document, stderr is empty) runs in a harness made through the product, the same on every tree (T-0341, found in the public export review). It copied the repository's own `.leerness`, `AGENTS.md` and `CLAUDE.md`; without them, as in the public repository, the copy held only `package.json`, so the paths that read the cwd's harness never ran and the check passed without covering them. In a harness, `selftest` reads the cwd's manifest and skills, and the commands it starts touch the cwd's harness and write its usage counter. `scripts/e2e-lived-in-harness.js` builds the harness with ordinary commands and checks each piece exactly: an in-progress and a planned milestone, an in-progress and a done task (the two it added, by the ids `task add` returned; init's default task and the in-progress milestone's task come first, so fixed ids would change those rows), a dated decision, a lesson, an active rule, an open user request, a handoff naming the in-progress task, the current state, a pre-wake report, the manifest, the installed skills and the usage counts. The check fails when a step fails or any of it is missing. Ablation in package copies laid out like the public export: stderr noise that appears only when the cwd tracker has a task in progress passes in the old folder and in a freshly initialized project and fails in the new harness; noise whenever the cwd has a manifest was already caught by a selftest case in every folder.
|
|
107
|
+
- `scripts/e2e-lived-in-harness.js` run directly (in `npm test` and `test:core`, next to `e2e-repo-guard.js`, 33 tests, about 30 seconds): the contract judgment against a stand-in CLI (clean output passes; text before the JSON, one byte of stderr, a lone newline on stderr, exit 1, a failed case, `ok: false`, a payload that counts every case passed but reports a failure, and one without a fail count each fail on their own part), and the fixture built with the real CLI (every step exits 0 and the added tasks got their own ids; each of the 14 pieces of state, changed alone in a copy, is the one reported missing, with changes a looser check would accept: a paused rule, also with "active" in its Last Verified cell and also under an earlier table whose header swaps Status and Last Verified, a closed request, a planned milestone, a handoff that no longer names the task or names only a longer id starting with it (`T-00030`, `T-0003x`), a manifest in another language, usage counts below what the build ran; the task named as `__T-0003__` still counts; failing steps fail the build even when the state is there; a `task add` without an id in its output fails it and the steps that need the id do not run; steps that exit 0 but leave nothing fail it). It also keeps the helper wired: the orphan-guard check of e2e flagged it while only e2e.js required it. Ablation in copies, 22 variants: going back to fixed task ids fails 22 tests, and each other loosened or removed judgment fails a named test, except two that cannot change a result: the stdout-prefix check (a payload object parses only from output that starts with `{`) and the per-step error flag (a step with an error always also lacks a passing status, since the steps that need a missing id do not run).
|
|
108
|
+
- The MCP `leerness_selftest` call gets a 720-second budget of its own instead of the 300-second long budget it shared (T-0342, found while testing the public export). That budget came from a 116-second measurement (1.36.124). With 355 cases selftest takes 238-241 seconds on Windows when the machine is quiet (CLI and MCP, measured in the 1.36.296 tree and in the tree before these changes side by side) and 227-230 seconds with the test suite running beside it. Inside e2e the MCP check failed with a bare `tools/call_isError` on 2026-10-08, with heavy steps running beside it, and again on 2026-10-09; those logs kept neither the time nor the text, and the same call passed in 238 seconds in both trees when rerun quietly, so the 300-second budget is the likely cause, not a confirmed one. As elsewhere, the limit is about three times the measurement. The selftest check of the budget table now also requires an entry whose limit is measured (not read from a source) to keep at least twice its measurement, so a new measurement without a new budget fails it. The e2e MCP check reports a timeout as a timeout with the session's seconds before it treats the result as a tool failure, shows the start of the text for a tool failure, and prints the seconds when it passes. The e2e calls that ran selftest or doctor with a 300-second limit (six direct calls and a helper that runs five more) share one 900-second limit, as does the installed-package selftest check; the e2e child-diagnostics probe, which runs one of those blocks in a sandbox, reads that limit from e2e.js instead of expecting 300 seconds.
|
|
109
|
+
|
|
110
|
+
## 1.36.295 - 2026-09-30
|
|
111
|
+
|
|
112
|
+
- Data features get the create, read, update and delete operations they need, by default (owner request). The owner chose guidance plus an automatic check at completion that never blocks, for new features and for changes to existing ones, with the four operations plus quality items as the standard.
|
|
113
|
+
- AGENTS.md (standard mode, Korean and English) has a new rule: for each entity, decide which operations it needs, implement each one end to end (storage, API, UI, permissions and validation, tests), and give the reason for any operation left out in the task evidence. Existing projects get it through `leerness update` (migrate), which keeps custom AGENTS.md text. Minimal mode, whose AGENTS.md has no rule list, is unchanged; its projects still get the checks below.
|
|
114
|
+
- `leerness lens crud`: six questions in Korean and English (which operations each entity needs and why any is left out; whether each operation reaches from storage to the UI; list and detail reading, including a missing ID and other users' records; server-side validation, partial updates and concurrent edits; what delete means; success and failure tests). The crud lens is outside the lens domain cap, so no existing lens line is displaced.
|
|
115
|
+
- `review-request` adds a "Data feature CRUD check" section, and `crudCheck` in `--json`, when the request works with stored data: an explicit term (CRUD, database, DB, an ORM or database name) or a data noun together with an operation word. A verb alone does not count, so bug fixes and cleanups stay quiet. The section does not change `proceed`.
|
|
116
|
+
- `verify-claim` adds a `crud` line to its lens block when the claimed files create and read a resource but never update or delete it ("posts — the claimed files only create and read it (no update or delete). Elsewhere, or not needed?"), and asks the first crud question on another data surface (a file that turns on the database lens, or a resource with all four operations). It reads explicit shapes only: Express-style routes and HTTP clients, fetch, Go routers, Flask, FastAPI, NestJS, Spring, Next.js route handlers and API routes, Laravel and Rails resource declarations, Django and DRF class-based views, and Prisma, Supabase and Firestore calls. A POST counts as a create only on a collection (a plural last path segment); action and infrastructure paths (login, webhooks, health, search, a POST to /jobs/:id/cancel) name no resource, and comments are skipped: `//` and `/*` in C-like files, `#` in Python, Ruby and PHP, and Ruby's `=begin` blocks, counted only at the start of a line or after whitespace (so `/[/*]/`, a URL and Python's `//` are not comments). `--json` carries the same result as an advisory `crud` object; neither changes `ok` nor the exit code.
|
|
117
|
+
- Measured before shipping, reading 30 real projects without running anything in them: counting every POST as a create turned remote calls such as `/jobs/:id/cancel` into most of the findings (136 in the three largest projects). With the collection rule and the create-and-read requirement, 51 findings remained in 7 of the 17 projects with detected resources (26 in those three). Of three checked by hand, two matched the code and one came from an example in a doc comment, which is why comments are skipped.
|
|
118
|
+
- `scripts/crud-check-probe.js` (`npm run test:crud-check`, also in `test:commands`): request signal on 21 data and 20 other requests in both languages; the operation mapping for 20 framework and data-client fixtures; actions, infrastructure endpoints, comments and non-route calls naming no resource; comments after code, markers glued to strings, regular expressions and templates, and each language's own comment syntax; the finding rule; run time on adversarial inputs, including a 256K whitespace run after each of 13 pattern openers; `lens crud` in both languages with no Korean in the English lens list; the review-request section and JSON only for a data request; verify-claim's crud line, question, silence on other code, exit code, JSON and unchanged lens lines, in both languages; the AGENTS.md rule in fresh standard projects, its absence in minimal projects, and `migrate` adding it once while keeping custom text.
|
|
119
|
+
- Free-text commands keep request text that begins with "-" after `--` (T-0321): clarify, brainstorm, review-request, intent, constraints check, skill match/search, reuse find, reuse-check, next-action add, orchestrate, register-pending, agent, agents route and release note receive it verbatim; the flag guards and JSON-mode checks no longer read past `--`; the 7 MCP free-text tools pass the text after `--`, so a bullet-list request no longer fails with text_required; release note no longer records the value of `--language` and other value flags; bugfix and referee read the tokens after `--` as operands and refuse extra ones (such as `-- --path B`) instead of acting on the current project. `scripts/free-text-args-probe.js` (`npm run test:free-text-args`, in `test:commands`).
|
|
120
|
+
- MCP title and target tools (task_add, decision_add, rule_add, plan_add, lesson_save, lesson/decision drop, plan_remove, memory_restore, feature_add, preview add, state_start/handoff, agents_record/resolve/fallback, shell_guard, pc) pass their text after `--`, so a title that begins with "-" (a markdown bullet) or "--" is kept instead of being read as an option (T-0324).
|
|
121
|
+
- CLI: text after `--` is kept verbatim by the title commands, lesson/decision drop, state start/handoff, shell-guard and agents record/resolve/fallback, and a path-like title after `--` is no longer taken as the project. Other commands still read a path after `--` as their project (T-0324; `scripts/title-args-probe.js`, `npm run test:title-args`, in `test:commands`).
|
|
122
|
+
|
|
123
|
+
Cross-model review. The owner changed the review rule on 2026-09-30 (rules.md R-0001): work by Claude is reviewed by codex (gpt-6.1-sol or gpt-6-astra) and work by codex by Claude 5.5. gpt-6.1-sol reviewed every uncommitted change of 1.36.290 to 1.36.295 read-only in an isolated copy. Round 1 returned NO-GO with nine findings; round 2, on the fixes, confirmed five of them and returned NO-GO with seven more, five of them in the first fixes. Round 3 confirmed the rest of round 2 apart from their consequences and returned NO-GO with five: three in the round-2 fixes (retirement, `--file` and the strict audit) and two variants of the two heuristics, which are recorded below as limits under a stop rule set before round 3. Round 4 confirmed the reader, the strict audit and the deduplication, and returned NO-GO on retirement again (two findings), with two more heuristic notes recorded below. Round 5 confirmed the fence fix and the documented limits and returned NO-GO on one more retirement case, which exact provenance now closes. Every finding was reproduced before it was fixed, and each fix has a test that fails on the code before it:
|
|
124
|
+
- P1, crud check (1.36.295): four patterns (fetch, NestJS and two Spring mappings) split a whitespace run between two optional-group `\s*` in quadratically many ways; `@Get(` followed by 128,000 spaces took 6.6 s in the review (13.6 s at 256K here). Each run is now consumed in one place; the probe times 13 openers at 256K spaces (limit 1.5 s).
|
|
125
|
+
- Review route to GO (1.36.291): the printed commands lacked flags that `agents record` requires (`--provider`, `--model`, `--evidence`; `--id` and `--target` for the review) and never said to submit the filled round. The route now has a `submit-round` step before the review is recorded. Round 2: that step first printed `submit --stdin < <round file>`, which PowerShell cannot run, and its test dropped the redirection; `review-feedback start|submit` now also take `--file FILE` (same size and UTF-8 rules as stdin) and the route prints `leerness review-feedback submit --file <round file>`. A probe test runs the printed commands in both languages with only their placeholders filled, a round file path with a space and Korean included, until the review reaches GO, and checks they contain no shell operator. Round 3: `--file` checked the path's size and then read whatever the path held by then, in full. It now checks and reads through one descriptor, accepts a regular file only (a FIFO is refused without blocking; the probe checks that on POSIX systems only) and stops after 65,537 bytes whatever size the file reported. Refusals (a missing file, a directory, one byte over the limit, a byte-order mark, invalid UTF-8) exit 2 and leave the history unchanged, and the printed route also runs as one script in an actual PowerShell with the round file `round 파일 2.json`.
|
|
126
|
+
- Memory write budget (1.36.293): the source phase measured an English projection with the Korean header, so an English decisions.md was refused at its exact size and an English lessons.md passed a limit 18 bytes too small. Both the budget inspection and the write admission now use the project's header; the language probe tests the exact limit and one byte under for both surfaces and languages.
|
|
127
|
+
- Upgrades (1.36.290 and 1.36.291): projects created by development builds kept the superseded context-reading section and reviewer protocol under "Preserved previous content" in six managed files (CLAUDE.md, AGENTS.md, the Cursor and Copilot adapters, session-workflow.md, review-checklist.md; CLAUDE.md 1,333 bytes fresh against 4,320 upgraded). Migrate now removes a section those builds generated (taken from their own guidance modules) only as a whole, unedited block: after the managed marker, on line boundaries, exactly once, and only when the migration backup holds the same source. Round 2: the first fix removed matching lines anywhere, including a paragraph a user had copied under their own heading, and a byte-order mark made the backup check fail. Now a copy under another heading, an edited section, a quotation, a second copy and the preserved tail stay, and a BOM file is handled and keeps its mark. Checked against whole files the real 1.36.289 CLI wrote (Korean standard and English minimal, kept as a test fixture): after migrate each managed file equals a fresh one apart from the custom line. Round 3: a section inside a fenced code block, a file whose only managed marker sat in a fence, and a section followed by a paragraph the user added after a blank line were still removed; the three helpers that retire older exact blocks now also leave a file alone when it quotes their old text in a fence. Round 4: a copy of the protocol placed after a template line (`@AGENTS.md`) under the user's own heading was still removed, and a fence "closed" by a no-break space exposed its contents (a closing fence may now be followed by spaces and tabs only). Round 5: a copied template heading and import line above a copy of the protocol passed a whole-head check that ignored order and repetition. Every rule that judged sections by their surroundings missed a case, so migrate now uses exact provenance: it drops the managed part (the head, above the preserved marker) only when that head is exactly a file one of the 80 builds from the first that wrote such a section to 1.36.289 generated, in either language, mode and authoring language (92 fingerprints in `lib/retired-guidance-sections.js`, compared after normalizing line endings, trailing spaces and tabs, and the merge's separator). Any other head, one added, copied, moved or edited line included, goes to the merge unchanged, which keeps every old line as before. The comparison is of content, not bytes: a head that differs only in line endings, trailing spaces and tabs (Markdown hard breaks included) or trailing blank lines still retires, and a verbatim copy of a whole generated file cannot be told apart from the file itself. Custom text that an earlier migration moved under "Preserved previous content" stays and does not count, so a typical upgraded project still drops the superseded sections. That also fixed a gap in the earlier fixes: the separator the merge writes before that block had kept the last section of every previously migrated file.
|
|
128
|
+
- Crud check comments (1.36.295): a trailing `// app.delete(...)` after code counted as a delete, and a `"/*"` string erased the code after it. Round 2: the string-tracking scanner that fixed this erased code after `/[/*]/` and after a nested template, counted operations in a comment inside a template interpolation, treated Python's `//` as a comment and ignored Ruby's `=begin` blocks. Comment rules now follow the file's language and count a marker only at the start of a line or after whitespace. Limit (round 3): a marker after whitespace inside a string is read as a comment, so `" // "` hides the rest of its line and `" /* "` hides the lines up to the next `*/`, possibly the rest of the file. The hidden operations can silence a finding or produce a false one (a create and a read before the marker, the update and delete after it, read as "no update or delete"); tests pin both.
|
|
129
|
+
- API-skill matching (1.36.294): documentation words matched unrelated skills (`read` in a body, `docs` in a URL path), so "Read GitHub API docs" matched Stripe and Slack skills and hid the audit warning. Documentation words are skipped and a URL contributes only its host. Round 2: Korean documentation words (`문서`, `읽기`, …) and URL paths inside a skill's body still matched, and one shared body word was enough. Both are handled, and text derived from a task now needs the skill's name, direction or host, or two different words of its body; an explicit `api-skill match` query keeps any match. Round 3: a task and its skill can share a single word ("Integrate OAuth API" and an Authentication skill whose body mentions OAuth), and then the audit warned and `audit --strict` failed. The audit now reports such an uncertain match as `api_skill_weak_match` (info, not a warning: "no confirmed match", with the candidates) and warns only when nothing matches at all; handoff still lists only the certain matches. The trade-off (round 4): an unrelated skill that shares one word also turns the warning into that info line. A word repeated in the task counts once toward the two body words.
|
|
130
|
+
- Placeholder next action (1.36.294): the default was matched as a substring, so "Implement the UI to write the next action for Stripe payments" was dropped from matching and treated as a placeholder by lazy detection. Only the whole default counts now.
|
|
131
|
+
- Review output language (1.36.291): an English manifest saved with a byte-order mark made `review-feedback` output Korean; the mark is now stripped as the CLI's own reader does.
|
|
132
|
+
- Request signal (1.36.295): database names were case-sensitive (`sqlite`, `postgres`).
|
|
133
|
+
|
|
134
|
+
## 1.36.294 - 2026-09-30
|
|
135
|
+
|
|
136
|
+
- Saved API skills (`.leerness/api-skills/`) now match the current task. handoff, `handoff --json`, `health --json` and `session close --json` built the match text from the in-progress row's `title` and `notes`, which progress rows do not have, so the text was always blank and nothing matched: handoff always printed "N API skill(s) saved (none match the current task)". The four now share one helper that uses the row's request and next action, skipping a placeholder next action such as the default `write the next action`.
|
|
137
|
+
- The matcher now ignores common words and bare URL parts (`the`, `api`, `https`, `com`, the existing keyword stopwords, …). They had matched every saved skill: once the match text was real, every saved skill would have been listed, and the audit already missed its "API task without a matching skill" warning whenever any saved skill contained a word such as "the". A Korean token is also tried without a trailing particle (`결제를` → `결제`). An explicit `api-skill match` query made only of such words still searches with them.
|
|
138
|
+
- The audit's API-task check already read the right fields but also counted a placeholder next action, whose words (`write`, `다음`, `작성`) matched any saved skill containing them and hid its warning. It now uses the same helper (plus the row's evidence, as before).
|
|
139
|
+
- The placeholder-next-action rule is shared with lazy detection's "blocked task without a next action" check, which had no test and now has one.
|
|
140
|
+
- `scripts/api-skill-match-probe.js` (`npm run test:api-skill-match`, also in `test:commands`): the four surfaces match a relevant skill and not an unrelated one, including a match through the next action only; common words, URL parts and the placeholder next action match nothing; a Korean task matches only through particle-stripped forms; explicit queries keep working; the audit warns for an API task without a relevant skill, stops once one exists, and ignores the placeholder next action in both languages; lazy detection flags placeholder next actions only. On the previous code, the matching, Korean and audit cases failed. Breaking one piece at a time in an isolated copy (each of the five text sources, the next action, the placeholder rule in matching and in lazy detection, the stopwords, the Korean stems, the explicit fallback) failed the named test in 14 of 14 cases. The handoff-i18n fixture now expects the related-skill section in both languages.
|
|
141
|
+
- `review-request --ladder` no longer prints `[object Object]` in its in-codebase rung, in text or in `--json` (T-0320). The rung labelled each reuse candidate with `name` or `id`; reuse-map rows have neither (`capability`, `where`), so each row printed as the object itself. On this repository's own workspace the rung read "reuse 후보 6건(토큰 매칭 — 확정 아님): [object Object], [object Object], [object Object]". The rung and the reuse-candidate section now share one label per kind, `[skill] <id>` and `[reuse] <capability>`; the section also shows the skill's display name and the row's location, and no longer ends a row with a bare `@` when the location cell is empty.
|
|
142
|
+
- Values from hand-edited stores are printed only when they are text. A skill.json `displayNameKo` that is an object or an array, and platform-constraints.json `docs`, `kind` or `detail` that are objects or missing, printed `[object Object]`, a comma-joined array or `undefined` in the review-request text. They are now left out (a missing `docs` still shows `-`); `--json` reports the stored values unchanged.
|
|
143
|
+
- `scripts/review-request-labels-probe.js` (`npm run test:review-request`, also in `test:commands` after the rule-applicability probe): the exact rung text in text and `--json` for mixed skill and reuse-map candidates, for reuse-map rows only (the shape observed here) and for no candidate; the section labels with and without a location; non-text store values in both sections (including a non-text constraint `kind`), with `--json` unchanged. The probe writes its own skill fixture after removing the skills `init` installed: a host skill catalog (`LEERNESS_SKILLPACK_PATH`, or an installed `leerness-skillpack`) changed the candidates and failed two of its tests. It also drops other ambient `LEERNESS_*` variables and requires `--json` stdout to be exactly one JSON object. On the original code all three tests fail. Reverting one piece at a time in an isolated copy (the rung label, the section label, the constraint lines, the text-only rule, the location rule, passing the map index as the detail flag, a raw constraint `kind`, sanitising the `--json` data) failed the expected test in 8 of 8 cases, and the unmodified copy passed.
|
|
144
|
+
- review-request now reads the fields brainstorm actually returns (T-0322). Failure lessons (`{ title, line }`) were read as `text`/`preview` and printed as a blank `[lesson]` line; task-log failures printed a blank `[task-log-failure]` line; an in-progress task printed only its id because progress rows carry `request`, not `title`. They now show the evidence heading, the task-log line and the id with the request text, and the conflict lines keep their indentation. On this repository's workspace copy, 20 short keyword requests produced 138 conflict and past-context entries with no title or preview before, and none after. The MCP tool description and the efficiency hint no longer say conflicts include failure lessons.
|
|
145
|
+
- brainstorm `--json` milestone hits now include `status`, read from the milestone's `Status:` line as `plan list` does. review-request chose in-progress milestones by that field, which never existed, so an overlapping in-progress milestone was never reported. It is now listed under 진행 중 영역 with the existing efficiency hint (15 of the 20 short requests). In-progress milestones are picked before the first three are taken, so done milestones listed first no longer hide one.
|
|
146
|
+
- The verdict is unchanged, as the owner chose on 2026-09-30: failure lessons stay past context, and the `planConflicts` condition, which had never been met, is removed from `proceed`, whose reason now reads `안전 — 충돌 신호 < 3`. Counting every failure lesson would have turned all 20 short requests into "확인 필요" (11 today). The previous and fixed CLI gave the same `proceed` and conflict count for all 158 inputs (20 short requests and 138 real user requests). In-progress tasks are still counted only among the first three task matches, because that count decides `proceed`. The 138 user requests (median 16 words) match no failure lesson, task-log failure, in-progress task or milestone at all, because brainstorm requires every word of the request to match within one entry.
|
|
147
|
+
- review-request reads brainstorm output up to 16 MiB. With the default 1 MiB spawn buffer a larger output was cut, parsing failed without notice and every signal was lost, so `proceed` read true. The new milestone `status` field could push an output just under that limit over it: a second-model review reproduced 983,635 → 1,160,435 bytes turning `proceed` from false to true. Outputs that fit the old buffer keep their verdict; the largest on this workspace was 422 KB.
|
|
148
|
+
- The reuse-map scan no longer returns a table header row as a candidate. It matched request words anywhere in a row, so a word such as `use` (in `Reuse Method`) made the header `Capability` a reuse candidate. A header is now recognised from the table structure: outside a table, a line with a pipe whose next line is a delimiter row (with or without outer pipes). The table then runs to a blank line or another block (heading, quote, fence, list item, rule), so a body row without pipes or shaped like `| - | - |` stays data, and a pipe in the line above a table does not hide its header. A hand-written table with a Korean header is skipped too.
|
|
149
|
+
- The feature-graph overlap check read `.leerness/feature_graph.md` split on `### ` headings, while `feature add` writes `.leerness/feature-graph.md` with `## F-XXXX` headings, so no feature overlap was ever reported. It now uses the same node ranges as `feature list` and reports overlaps under 진행 중 영역 with the existing hint; like milestones, they do not affect `proceed`. Runs of spaces are collapsed first, because the shared heading pattern takes quadratic time on a long run of spaces followed by text (1.5 s at 40,000 spaces), so titles show single spaces. The shared function is unchanged; it also serves handoff and `feature list`.
|
|
150
|
+
- `scripts/review-request-signals-probe.js` (`npm run test:review-request`, also in `test:commands` after the labels probe): conflict and past-context lines in text and `--json`, including an evidence block with an empty heading; three conflicts still stop `proceed`; four failure lessons do not; an in-progress milestone is reported without stopping `proceed`, a done one is not, and done milestones listed first do not hide it; brainstorm output of about 1.4 MB still gives three conflicts; a feature-graph heading with 300,000 spaces is parsed within 40 seconds; a feature-graph node that shares a request word is reported; English and Korean header rows are not candidates, including delimiter rows without outer pipes and a pipe in the line above; a body row without pipes or shaped like `| - | - |` does not hide the row above it. On the previous code all eight tests fail. Reverting one piece at a time in an isolated copy (the milestone status field, the lesson title, the task request, the task-log line, the header skip, recognising headers by the English name only, dropping the table state, judging a table start by a pipe in the line above, requiring both outer pipes, the milestone condition in `proceed`, slicing milestones before filtering, counting lessons as conflicts, the conflict line format, the empty-title fallback, the reason text, the feature-graph file name, the feature heading level, the default 1 MiB buffer, parsing without collapsing spaces) failed the expected test in 19 of 19 cases, and the unmodified copy passed. Three read-only review rounds by a second model (gpt-6.1-sol) found the milestone order, the buffer flip, four table-boundary cases, the empty heading, the quadratic heading pattern and three probe gaps; each was reproduced before it was fixed. Left open: a table ended by an empty list item or an HTML block, a heading with two spaces after `##`, and brainstorm's tracker scan, which is quadratic and can exceed review-request's 12-second limit (about 25 s at 40,000 rows).
|
|
151
|
+
- Values from hand-edited skill.json and platform-constraints.json are shown by one rule everywhere, not only in review-request (T-0325). Where these files hold an object, an array or nothing in place of text, skill info, search, match and lint, brainstorm (also with `--include`), handoff, retro, insights, roadmap and constraints list/check printed `[object Object]`, a comma-joined array or `undefined`, and the files they write kept it: SKILL.md from `skill export`, `export-all` and `publish`, the publish manifest and README, the skill README mirrors, `.leerness/skill-index.md`, roadmap.html, the leerness.html graph and `.leerness/skill-suggestions.md`. Counts read the letters of a string (`cap 12` for `"capabilities": "zebra export"`) or joined an object into the total of skill uses (`1[object Object]회`). The graph page keyed skill nodes by an `id` that could be an object, so two such skills became one node, `skill:[object Object]`, and one of them vanished. Text output and generated files now show text values only, with terminal and Markdown text on one line, and count only lists and numbers (0 otherwise; a numeric string such as `"3"` is not a number). The graph and roadmap pages keep a skill's text `id` and `name` as written, since they identify nodes; the pages escape them as HTML. `--json` still reports stored fields as stored: retro and insights keep each skill's `count` as written and add up only numbers. The rule is `lib/store-display.js`, which review-request now uses too. skill match and skill impact read a name that is not text as missing and fall back to the directory id, so such a skill is matched and counted under its id. skill lint reads a skill.json name or description that is not text as missing: an object description now fails with `description_missing` instead of passing as the 15-character text `[object Object]`. Text is still checked as written.
|
|
152
|
+
- Commands no longer crash on these shapes. List methods were called on whatever a field held: `capabilities` as a string or an object crashed skill search, info, consolidate, export, export-all and publish, the README mirror that skill learn, use and optimize rewrite, `skill add` from such a skill pack, and `init` with that pack, which writes the catalog into skill-index.md; a `lastUsed` that is not text crashed retro; a null `sources` entry crashed skill info and learn; `skill info --json` crashed on a null `verification`, a null source or `sources` written as one string, and now reports them as stored. A source whose `url` is empty printed `[object Object]` and is now left out. skill learn crashed on every skill.json without `sources` or `patterns`, the shape of the built-in skills (its success line read their lengths after the file was written), and now starts those lists. skill use saved `NaN` (written as null) when `usage` had no count, and now counts from 0. Adding to a field of another shape (`skill learn --capability` when `capabilities` is not a list, `skill use` when the count is not a number, `skill optimize` when `optimizations` is not a list) is refused in the project language and the file is left as it was; the value is not rewritten for the user. The same holds for a skill.json that is not a JSON object: with an array root, learn, use and optimize reported success while the save kept only `[]`, and text that does not parse was overwritten.
|
|
153
|
+
- platform-constraints.json entries are checked like the file itself. The loader checked only the top level, so a null platform, `aliases` that is not a list of text or `constraints` that is not a list of objects crashed constraints list and check and review-request. Such a file is now reported as damaged (`platform-constraints.json 손상`, `corruptStore` in `--json`), the defaults are used, and `constraints add` refuses to overwrite it, as for a file that does not parse. `docs`, `kind` and `detail` that are not text are values rather than structure and are left out of the text. `constraints add` on a hand-written platform without a `constraints` list starts the list instead of crashing. More inputs now reach the damaged-store notes, so the `constraints add` refusal and the `--json` note follow the project language, as the list and check warnings already did.
|
|
154
|
+
- review-request prints store text on one line. Control characters in a skill name, a reuse-map row, a constraint's docs or detail, a decision heading, a hand-edited task request, a milestone or a feature-graph title were printed as they were, terminal escapes included, while `constraints check` already turned them into spaces; they are spaces now, as are the same values in the Korean `skill list` table (the English one was already safe), skill lint messages (skill.json and SKILL.md names), skill match and its history file, handoff's skill lines and skill impact. `--json` is unchanged.
|
|
155
|
+
- `scripts/store-values-probe.js` (`npm run test:store-values`, also in `test:commands` after the review-request probes), 13 tests: every text command above with skill.json values that are an object, an array, missing, a string where a list belongs, or a list of other items, listing each skill by id so that silence is not a pass; valid sources still shown, as text and as `{ url }`; the refusals in both languages with the file unchanged, including a skill.json that is not a JSON object; counts, including retro's order, suggestion and workspace view; skill lint and impact; the generated files, with the export description still preferring `description`; `--json` keeping stored values, including retro and insights counts; non-text constraint values; five malformed constraint shapes reported as damaged with `constraints add` refused, in Korean and English; the graph page, including ids that differ only by a control character; control characters across the review-request and skill surfaces; and a skill pack with non-text values through `skill add` and `init`. The probe pins the skill catalog to the built-in skills: a leerness-skillpack beside the CLI or in the global npm root would otherwise add skills to its output. With every piece reverted in an isolated copy, all 13 tests fail. Reverting one piece at a time (80 pieces: each skill-display site, each count, total and sort, the learn, use and optimize field and file checks, the constraints entry check, constraint lines and docs, `constraints add`, the English notes, each review-request line, skill list, lint, the graph fields and `skill info --json`) failed a test in 80 of 80 cases, and the unmodified copy passed; five more changes that put back mistakes made during the review rounds, or drop every source, failed too. The first run left one piece uncaught, the review-request conflict line: `task add` already writes control characters as spaces, so that test now edits the tracker row by hand. A reproduction matrix of 147 runs (12 malformed fixtures across the skill and constraint commands) went from 52 bad results, 35 of them non-zero exits, to none.
|
|
156
|
+
- A read-only review by a second model (gpt-6.1-sol) found seven gaps in the first version, each reproduced before it was fixed: `skill info --json` crashes, retro and insights `--json` replacing a stored count with 0, graph nodes keyed by an object id, sources with an empty url, SKILL.md names in lint messages, Korean-only damaged-store notes, and the ambient skill catalog in the probe. A second round found four more, also reproduced and fixed: lint folding a stored name before checking it (`"kite<ESC>"` passed), learn, use and optimize on an array root, graph ids folded so that ids differing only by a control character became one node, and probe checks that a suppressed source list would have passed. A third round, limited to P1 findings by a rule set before the second, found none. Left open from it: a graph link written in a description (`[[skill:a<newline>b]]`) is still folded to one line and can point at the `a b` node, and lint's trigger-clause hint, as before this change, needs a space after "Use", so a description wrapped there gets the hint.
|
|
157
|
+
|
|
158
|
+
## 1.36.293 - 2026-09-30
|
|
159
|
+
|
|
160
|
+
- decisions.md and lessons.md headers follow the harness language. `decision add`, `lesson save` and the other memory writers re-render these files behind a generated header, which was Korean in every project, so an English project's decisions.md began with `## Template (예시 — …)` after its first decision. The header now follows the harness authoring language: an explicit `--authoring-language`, else the stored project language (manifest, then `.leerness/LANGUAGE`); a command's `--language` or `LEERNESS_LANG` does not change the file, and projects without a stored language keep the Korean header.
|
|
161
|
+
- Existing files keep working. The generated prefix is still checked (`projection_diverged` guards hand edits), and it now accepts either the English or the Korean header, so a file written by an earlier version or before a language change is not refused; the next write replaces only that header, while records and appended text must match exactly. The write preflight and admission budget accept either header and size the one that will be written. Korean projects are written byte for byte as before: the same writes with the previous and the current library left 8 of 8 decisions and lessons files identical, and the English control differed. `memory-migration` bundles still render the Korean header, because their verification re-renders recorded bytes; the next ordinary write replaces it.
|
|
162
|
+
- `scripts/memory-language-probe.js` (`npm run test:memory-language`) covers English and Korean projects for both files, a header of the other language accepted and replaced with the appended note kept, hand edits refused under either header with no file changed, the preflight's acceptance and exact projection size for each language pair, and the language source.
|
|
163
|
+
- Two existing probes expected the old behavior: `memory-legacy-retention-probe.js` and `memory-projection-retention-probe.js` seed an English project and expected rewritten files to keep the Korean header. Their fixtures now write the Korean header explicitly, as earlier versions did, and expect the English header after a write, so they also check through the real add, drop, restore and backfill commands that a legacy Korean header is accepted and replaced with the appended bytes kept exactly once (48/48 and 18/18). Their refusal cases pass unchanged.
|
|
164
|
+
|
|
165
|
+
## 1.36.292 - 2026-09-30
|
|
166
|
+
|
|
167
|
+
- English handoff no longer prints Korean-only tool text. An English project on Korean Windows saw the terminal-encoding notice, skill suggestions, the official-skill cache note, the next-step suggestions and the compact `다음:` line in Korean. Every string the tool writes on the handoff text, `--compact`, `--pulse`, `--json` and workspace (`--include`, `--all-apps`) paths, in the SessionStart hook context and in the pre-handoff drift and not-initialized banners now follows the project language; 168 string literals were wrapped in a language helper whose first argument is the unchanged Korean text. Helper text these paths print follows it too: next-step titles, abnormal-shutdown details and resume guide, session blind spots and short session flags, the version-skew warning, shell-script risk text, and built-in skill descriptions, for which English shows the description's English sentence or the skill's English name. Document bodies and user data are printed as stored.
|
|
168
|
+
- Korean output is unchanged: 24 Korean scenarios (fresh standard and minimal projects and a fixture raising 20 conditional sections, each as handoff, compact, pulse, JSON, hook and compact with a session flag; plus workspace, not-initialized, missing-path and version-skew runs) matched the previous CLI byte for byte, and the same comparison in English differed in all 24.
|
|
169
|
+
- `scripts/handoff-i18n-probe.js` (`npm run test:handoff-i18n`, also in `test:i18n`, `test`, `test:core` and `test:fast`) checks fresh English projects (handoff, compact, pulse, JSON, hook, short session flags), a fixture raising 20 conditional sections (24 checks) in English and in Korean, the terminal-encoding notice (Windows code page 949, or a POSIX locale without UTF-8), workspace, not-initialized, missing-path and version-skew output, and a static guard that fails when a Korean string literal on these paths is not the Korean argument of a language helper. Breaking each of 16 localizations in an isolated copy made its targeted check fail (16 of 16), after a control run in which every targeted check passed; one of them, an unwrapped string in a section no fixture raises, is caught only by the static guard.
|
|
170
|
+
- English handoff output is longer than the Korean it replaces: a fresh English project's `context budget` rises by 40 tokens in standard mode (10,889 of 12,000) and 33 in minimal mode (1,858 of 2,200) on this machine. Korean totals are unchanged.
|
|
171
|
+
- The English-leakage ratchet (e2e block O) drops from 27 to 25 lines, because `pulse` shares the handoff `--pulse` renderer. The e2e session-signal checks accept the English short flags as well.
|
|
172
|
+
- Not changed here: after `decision add`, decisions.md in an English project still starts with the Korean template heading, because that projection is checked against its rendered header (fixed in 1.36.293). Pre-wake-audit reports keep the language they were written in. The handoff API-skill section never matches the current task, because progress rows carry no title or notes (fixed in 1.36.294).
|
|
173
|
+
|
|
174
|
+
## 1.36.291 - 2026-09-30
|
|
175
|
+
|
|
176
|
+
- Staged reviewers: `review-feedback start` accepts a v2 contract (`leerness.review-feedback-contract/v2`) with 1 to 5 ordered `stages`, for example a first and a final reviewer, each with its reviewer and `maxRounds`. The stages review the shared frozen scope and criteria in order, and each applies the single-reviewer rules to its own rounds and budget. A NO GO is re-reviewed by the stage that gave it; the next stage starts once it passes, and the review is GO when the last stage passes. The same model may serve several stages, but a v2 round names its `reviewerSession`, which cannot be a session another stage used (`feedback_session_reused`) or the session that recorded the reviewed implementation attempt (`feedback_session_not_independent`). Sessions are declared strings, not authenticated. `agents record reviewed --feedback-round` binds the latest round of that round's stage. Single-reviewer contracts and their history are unchanged; the 46 existing review-feedback probe cases pass unmodified.
|
|
177
|
+
- Route to GO: human output of `review-feedback start|submit|show` is written in the project language (`--language ko|en`, then `LEERNESS_LANG`, the project manifest, Korean); it was English only. Section markers, status values and JSON text are the same in every language, and the English report outside the new block is byte-identical to 1.36.290 for six single-reviewer states. The report begins with a `[GO_ROUTE]` checklist. It lists the stage and reviewer, the rounds used and reviews left, each open blocker's required outcome with every acceptance check marked passed or open with its latest status and evidence, the fixed criteria and the regression check, the owner decisions when the review stopped, and otherwise numbered next steps with the `agents record` commands. JSON adds `goRoute` and `nextRoundTemplate`, a skeleton of the next round. Its placeholders and empty evidence lists are invalid on purpose: each of its 12 placeholders (13 in a staged review) is rejected on its own, and the checks of already resolved issues come prefilled as passed.
|
|
178
|
+
- Reviewer guidance (AGENTS.md, the review checklist, reviewer role and dispatch prompts) asks for TO_GO as a numbered checklist in fix order: location, evidence and how to reproduce, the required behaviour, each check with how it will be verified and the evidence needed, then the pending criteria and regression check, the reviews left and the next steps. It describes staged reviewers and their session rule. A fresh English project's `context budget` grows by 219 tokens in standard mode (10,849 of 12,000) and by 218 in minimal mode (1,825 of 2,200). Both totals include the Korean-Windows code-page notice that handoff prints on this machine, about 70 tokens that the 1.36.290 figures did not include.
|
|
179
|
+
- Ten new review-feedback probe cases (56 in total) cover stage order, re-review by the stage that gave NO GO, sessions, per-stage budgets, the route, the skeleton, the language order, the Korean report and the staged record binding. Breaking each of 24 guards in an isolated copy made its targeted case fail (24 of 24), after a control run in which all targeted cases passed.
|
|
180
|
+
|
|
181
|
+
## 1.36.290 - 2026-09-29
|
|
182
|
+
|
|
183
|
+
- Generated instructions keep one full copy of the reviewer protocol and the context-reading paragraph, in AGENTS.md, because Leerness serves several agents. This holds in standard and minimal mode. CLAUDE.md imports AGENTS.md with an `@AGENTS.md` line, which Claude Code loads at launch, and keeps the three core rules. The Cursor rule, the Copilot instructions and the session workflow point to AGENTS.md. The protocol had been appended to four files and the paragraph to five, so a session start counted each three times: a fresh English project with one task, decision and plan measured 12,076 of its 12,000-token `context budget` (exit 1), and now measures 10,560. Minimal mode's paragraph no longer names context-routing.md, because minimal follows the paragraph directly and the budget loaded that document. The minimal budget is 2,200 tokens instead of 1,200, since minimal now carries the full protocol: a fresh English minimal project measured 4,148 and now 1,537.
|
|
184
|
+
- e2e: 18 checks that pass on 1.36.188 were failing, unnoticed because the 2.9-hour suite had not been run in full. Each was bisected over 185 commits to its first failing commit. Thirteen followed intended changes and now assert the current behaviour: icon removal (1.36.237), rule observations (1.36.238), compact rules and delegation brief (1.36.255), legacy prose retention (1.36.262), `setup-agents` removal (1.36.280), and the checked-projection and lossless-archive refusals (1.36.191, 1.36.190): the migrate fixture is now a renderer-written projection, and the concurrent-drop fixture is created with `decision add` instead of hand-written JSON, which both refusals rejected before any race.
|
|
185
|
+
- Test harness: the lock probe and the race harness now observe checked memory-output publication (a hard link, or PowerShell `File.Replace` on Windows) introduced in 1.36.190. Before, 8 of 11 lost-update races were never created and the lock invariant saw 16 of 41 state writes. Now all 11 pairs race and keep both records, and all 41 writes are observed under their locks.
|
|
186
|
+
- Orphan-guard self-check: a probe that validated npm script entry points by iterating script names was read as a run-all enumerator, which had disabled the detector on this repository since 1.36.190. The probe now iterates values. The detector then found one real dormant script, the Playwright dashboard benchmark, renamed from `test:ui-boundary-dashboard` to `bench:ui-boundary-dashboard`.
|
|
187
|
+
- `context-reading-probe` checks that fresh standard and minimal English projects stay within their own context budget, so guidance growth is caught by a fast suite.
|
|
188
|
+
- e2e runs from a hermetic, initialized project instead of the package root. CLI calls that passed neither a cwd nor a project path had used this repository as their project. Each full run added three test `dispatch.prepared` events to its execution ledger, which session close listed as agent provenance, bumped its usage counter and wrote an agent-run record. A final check compares a snapshot of the package's `.leerness`, gitignored state included, and fails on any change; `scripts/e2e-repo-guard.js` checks itself in `npm test`. On a copy of the tree, the old dispatch and lsp blocks passed while changing three files there, and the guard reported them; from the hermetic home the same blocks pass and change nothing. The guard's first full run then found two blocks that named the repository explicitly and still bumped its usage counter. The `whats-new` header-parsing check now passes a directory without a CHANGELOG, so the command falls back to the package's real CHANGELOG. The `selftest --json` stdout check now runs in a copy of this repository's harness, with a 900 s limit, because selftest takes 274 to 285 s there.
|
|
189
|
+
|
|
190
|
+
## 1.36.289 - 2026-09-29
|
|
191
|
+
|
|
192
|
+
- UI review questions: each of the five questions in a review packet now asks the reviewer to read every visible string and accessible name, not only scanner candidates, and to decide whether it speaks to the user or to the builder. Each gives concrete cues (requirement sentences, build or fallback narration, preview framing, criteria such as "within 3 seconds", raw values) and names the case that is not a finding. On the 324-surface held-out corpus a Codex reviewer separated leakage from clean copy perfectly with both the previous and the new questions (180/180, 0/144 false alerts), so no detection gain was measurable there.
|
|
193
|
+
- Browser collector: the placeholder of a visible text field is collected as its own `dom-placeholder` surface and scanned as the `placeholder` attribute. Chromium drops it from the accessible name once `aria-label` or a label names the field, so `<input aria-label="Email" placeholder="TODO: …">` was never scanned. The field's value is still never read, a placeholder already used as the accessible name is not collected twice, and hidden, transparent, zero-size and non-text controls contribute none.
|
|
194
|
+
- `ui-boundary-browser-probe.js --cdp` (`npm run test:ui-boundary-cdp`) runs the real-browser controls over plain CDP against an installed Chrome or Edge (Node 22+), without Playwright. In headless Chrome 154 and Edge 154 all 91 checks pass, including the 22 existing real-browser controls, which had never run on this machine, and 5 new placeholder controls.
|
|
195
|
+
|
|
196
|
+
## 1.36.288 - 2026-09-29
|
|
197
|
+
|
|
198
|
+
- Add UI copy guidance for the agent that builds screens. `init` installs `.leerness/ui-copy-boundary.md` and a `ui-copy-boundary` skill for Claude Code (`.claude/skills/`) and Codex (`.agents/skills/`) in the project language: for each visible string, ask whether it speaks to the user or to the builder, and keep specifications, criteria, implementation narration, notes, placeholder copy and raw values off the screen. The files are managed (re-install refreshes them and keeps a section the team appended); `init --minimal` leaves them out. In a blind A/B (four screens, one generation each, labelled by a separate Codex run), 33 of 366 strings were builder-facing without the guide, 0 of 272 with its draft wording and 0 of 263 with the final wording; about half of the 33 were preview framing invited by the experiment's own instruction. In a project installed this way, Codex opened the skill for a UI task and not for a backend task (one run each); Claude Code was not observed.
|
|
199
|
+
- UI boundary scanner v2 (`leerness.ui-boundary-scanner/v2`): rules match through full-width characters, non-breaking or wide spaces and zero-width characters while findings keep the supplied bytes; new signals for bilingual developer-note labels, placeholder and maintenance copy, Korean debug labels, exception text after a label, camelCase metadata keys, `[object Object]`, unresolved `{{x}}`/`${x}`/`%s`, missing values, raw i18n keys and JSON dumps. On an independent 324-surface corpus detection rose from 5/180 to 25/180 and false alerts from 6/144 to 32/144, most of them in template editors and other tooling text the corpus includes on purpose; requirement, criteria and narration wording stays unmatched. Evidence digests include the scanner version, so v1-bound reviews are stale for v2 results.
|
|
200
|
+
- An independent Codex review found six defects, all reproduced and fixed: invalid YAML in the English skill description, `is`/`는` connectives excusing `[object Object]`, any "variable"/"template" word excusing an unresolved placeholder, JSON parsed from the normalised view or refused after a line break, a shorter domain list than documented, and a 129 ms note-label backtrack (now 2.5 ms).
|
|
201
|
+
- `ui scan` summaries name render artifacts, developer notes and debug text separately; findings stay advisory.
|
|
202
|
+
- The state-lock heartbeat re-checks the admission of the operation that holds the lock instead of making a new admission on every touch, so it starts no Git process. It used to run `git rev-parse` in the project once per lock and once per second while a lock was held: five short locked appends started 10 Git processes (now 5, the operations' own), a lock held 3.2 s started 4 more (now 0), and deleting a project right after two locked appends failed 4/10 times in a plain project and 10/10 in a Git project (now 0/10 each). The heartbeat still stops on an incompatible layout descriptor, and now also when a repository is created around the held operation, whose own writes are blocked from then on.
|
|
203
|
+
- Test cleanup no longer relies on `fs.rmSync` `maxRetries`, which Node 26.3 ignores for `EPERM` on Windows (a held directory or an unshared file fails after 0-1 ms). `scripts/temp-cleanup.js` waits explicitly and boundedly, and 57 probe cleanups use it. The `test-run node` selector-fixture cleanup now waits the same way; before, one `EPERM` there made the command report `runtime-selector-unavailable` and refuse to run the requested test.
|
|
204
|
+
|
|
205
|
+
## 1.36.287 - 2026-09-28
|
|
206
|
+
|
|
207
|
+
- Load the skill catalog on first use and reuse the `npm root -g` result from a machine cache keyed by node, npm and npm configuration, so commands that never read skills start no npm process (Windows, 5-run interleaved medians: `--version` 329→137 ms, `task list --json` 527→338 ms).
|
|
208
|
+
- Collect the runtime environment once per process and probe tool versions only for `env summary`. Default handoff reuses the 18-tool inventory per project until PATH, the executable names in a PATH directory, a probed executable, the project's version-manager files or related environment variables change, or 24 hours pass; `--writeback` and `env detect` always probe (`handoff --json` 3259→1370 ms; text handoff 10254→2483 ms with a warm cache, 7808 ms cold). Machine caches live in the per-user state directory (`LEERNESS_CACHE_DIR` overrides it), keep the 32 most recent entries and are never written under `--dry-run`.
|
|
209
|
+
- Default text handoff no longer writes the tracked `active-wakeups.json` or `next-action-queue.json`, restoring the zero tracked-write contract. It still shows the missed wakeup and the suggestions; `handoff --writeback` records them.
|
|
210
|
+
- Secret scan follows Git's repository view: nested repositories and worktrees are not scanned as this repository, `.git/info/exclude` counts as ignored, `.leerness/archive` and `.leerness-backup` are skipped, and one handoff scans once (this repository: 253 false unacknowledged findings to 0, 9.3 to 1.4 s). Encoding check and code walks share the nested-repository boundary.
|
|
211
|
+
- Session close keeps user-written text inside the generated handoff region by position: a note under the title or a section the generator never writes moves verbatim after the region. Drift and audit read the current region, so legacy text kept below it no longer reports a stale or never-generated handoff.
|
|
212
|
+
- `npm test` no longer runs 17 probes twice (187 invocations of 170 distinct steps; now 173 distinct steps, each once, including the three new probes), and lint fails when `npm test` repeats a step.
|
|
213
|
+
|
|
214
|
+
## 1.36.286 - 2026-09-27
|
|
215
|
+
|
|
216
|
+
- Prevent an unclaimed generated `.leerness/cache/` file from causing a strict false failure for an already committed claim in projects without the ignore rule.
|
|
217
|
+
- Keep strict comparison for actual source changes and explicitly claimed cache files; cover single-task and read-only all-claim checks with a regression fixture.
|
|
218
|
+
|
|
219
|
+
## 1.36.285 - 2026-09-27
|
|
220
|
+
|
|
221
|
+
- Check Git working-tree status once for a read-only `verify-claim --all` sweep, while keeping individual claim verdicts and baseline policy unchanged. An empty sweep makes no status request.
|
|
222
|
+
- Keep per-claim Git checks when `--run-tests` or `--referee` executes project code, so a file changed during the sweep can affect later claims. A focused regression probe counts the real Git requests and checks verdict parity.
|
|
223
|
+
|
|
224
|
+
## 1.36.284 - 2026-09-26
|
|
225
|
+
|
|
226
|
+
- Optionally compare the local Firestore response with the Firebase Emulator Hub's advertised Firestore host and port. The old response format remains unchanged when no hub port is supplied.
|
|
227
|
+
- Preserve the distinction between a matching, unauthenticated hub advertisement and verified project identity or test readiness. An isolated live emulator reported the same mapping for a different requested project ID.
|
|
228
|
+
- On supported Node runtimes, run one directly selected test without an extra Node test worker so Windows timeouts can stop it promptly. Give the Windows process-tree termination command more time for named npm scripts; its own detached descendants remain a best-effort limit.
|
|
229
|
+
|
|
230
|
+
## 1.36.283 - 2026-09-25
|
|
231
|
+
|
|
232
|
+
- Add a bounded, read-only `test-plan firestore-probe` for the local Firestore emulator rule-coverage response shape. It distinguishes connection, HTTP, content-type and JSON-shape failures without returning response bodies or running tests.
|
|
233
|
+
- Keep project identity, service readiness and test-pass claims false. A live isolated emulator returned the same shape for the configured and a different project ID, so this observation alone cannot authenticate the service.
|
|
234
|
+
|
|
235
|
+
## 1.36.282 - 2026-09-25
|
|
236
|
+
|
|
237
|
+
- Add an explicit `test-run suite-list` observation for trusted Node wrappers that emit a bounded `--list` JSON manifest. It distinguishes a selected, skipped or absent target from mere script-name presence, and accepts a focused list only when the target is the sole selected entry.
|
|
238
|
+
- Keep list mode separate from execution-mode selector proof and test-pass evidence. The reference Functions wrapper listed 103 selected and 3 skipped tests, including a retired named script; no test or project migration was run there.
|
|
239
|
+
|
|
240
|
+
## 1.36.281 - 2026-09-25
|
|
241
|
+
|
|
242
|
+
- Add an opt-in `test-run npm-script` path for TEST-01. It executes one exact named npm script only when the earlier script probe's command, package and script digests still match; direct npm pre/post hooks are rejected, and a post-run package change invalidates the observed exit.
|
|
243
|
+
- Report the process exit without claiming an individual test was selected or passed. Test output is not returned; timeouts attempt to terminate the child process tree. Service identity, reusable evidence and full CI remain separate.
|
|
244
|
+
|
|
245
|
+
## 1.36.280 - 2026-09-25
|
|
246
|
+
|
|
247
|
+
- Remove the CLI-agent activation question and the `setup-agents` command. `init`, `migrate` and updates no longer create or reset external-agent enable flags; existing project values remain intact. The old `--no-setup-agents` flag is accepted as a no-op for existing scripts.
|
|
248
|
+
- Codex, Claude Code and other programs still consume the generated harness instructions and adapters without this activation step. Existing explicit Leerness agent-dispatch settings remain available for projects that already use them.
|
|
249
|
+
|
|
250
|
+
## 1.36.279 - 2026-09-25
|
|
251
|
+
|
|
252
|
+
- Add an explicit direct Node test runner for TEST-01. It checks the current Node selector with a controlled zero/one/multiple fixture, then runs one declared in-project test file with an exact escaped name and event-only output.
|
|
253
|
+
- Reject zero or multiple matches, skipped or failed tests, timeout and reporter overflow as focused passes. The read-only test-plan commands remain separate; npm wrapper selection, source/environment-bound receipts and final CI remain unverified.
|
|
254
|
+
|
|
255
|
+
## 1.36.278 - 2026-09-25
|
|
256
|
+
|
|
257
|
+
- Add a read-only named npm script probe for TEST-01. It checks an exact `test:<failedTestId>` script in a project or nested package, rejects unverified forwarded filter arguments, and keeps every test unrun and runner-selection/coverage flags unverified.
|
|
258
|
+
- Validate package paths, size, UTF-8 and duplicate JSON keys before reporting digests. A real read-only Functions project inspection confirmed an individual script and rejected a filter appended to its whole-suite wrapper; no project files or tests were changed.
|
|
259
|
+
|
|
260
|
+
## 1.36.277 - 2026-09-25
|
|
261
|
+
|
|
262
|
+
- Add a bounded read-only loopback HTTP response probe for the approved TEST-01 work. It checks a declared status and optional body marker, separates mismatches from connection/timeout errors, and never promotes a matching response to test, service-identity or final-CI evidence.
|
|
263
|
+
- Keep project runner selection, service-specific protocol checks, revision-bound receipts, cross-process sharing and final gates as separate follow-ups.
|
|
264
|
+
|
|
265
|
+
## 1.36.276 - 2026-09-25
|
|
266
|
+
|
|
267
|
+
- Reuse a native Git location on Windows only while the caller environment, resolved working directory and inspected PATH candidate files remain unchanged. A changed or unreadable path falls back to the original system `where.exe` lookup; shell-free execution and cwd-shadow rejection remain in place.
|
|
268
|
+
- Add a Windows regression check for unchanged, inserted, replaced and removed Git candidates, environment changes, cwd shadows, junction retargeting and caller mutation to the runtime tier. A measured publication case fell from 225 to 117 seconds with the same 1,579 Git commands; full-suite results are tracked separately.
|
|
269
|
+
|
|
270
|
+
## 1.36.275 - 2026-09-24
|
|
271
|
+
|
|
272
|
+
- Fix an intermittent Windows runtime-layout test failure: while an exclusive writer holds a lock, its heartbeat legitimately updates the lock owner's modification time. The read-only fixture now ignores only that declared timestamp, while continuing to reject changes to owner bytes and other paths. This also prevents the fixture's own assertion from interrupting the hard-link cleanup recovery test.
|
|
273
|
+
- Keep fast smoke focused: the platform check runs its one Windows path selftest case instead of all 355, and the generic smoke check no longer repeats the full selftest. `test:core` and `npm test` still run the complete selftest explicitly.
|
|
274
|
+
- Read the current generated handoff section in `lazy detect` when older authored content is preserved after it. A retained init placeholder no longer makes a successful session close and verification look incomplete; malformed generated markers still block.
|
|
275
|
+
- Align two existing integration fixtures with current contracts: an intentionally unsupported benchmark provider leaves the child with exit 1, and mode changes read the manifest through a checked descriptor while holding its lock.
|
|
276
|
+
|
|
277
|
+
## 1.36.274 - 2026-09-24
|
|
278
|
+
|
|
279
|
+
- Add the next approved TEST-01 stage: a bounded, read-only loopback TCP probe. It distinguishes reachable ports, connection refusals, timeouts and other connection errors without running tests or claiming service health. The probe rejects external hosts and is included in the existing focused test-plan check.
|
|
280
|
+
|
|
281
|
+
## 1.36.273 - 2026-09-24
|
|
282
|
+
|
|
283
|
+
- Add the first approved TEST-01 stage: a read-only plan for declared failed, related and final checks. Reject unmapped or ambiguous failures, surface missing final coverage and declared service blockers, and keep every selected check marked unrun. Wire the focused probe into the local test tiers. Actual test execution, readiness observation, result reuse and CI skipping remain separate work.
|
|
284
|
+
|
|
285
|
+
## 1.36.272 - 2026-09-23
|
|
286
|
+
|
|
287
|
+
- Add opt-in, evidence-backed plain-language reporting with one shared policy, two agent skill pointers, a default-off project toggle and scoped handoff status. Add an advisory UI information check that distinguishes repeated-fact candidates, semantic review, unknown evidence and purposeful repetition without removing UI or granting approval. Remove one repeated gate explanation from the Leerness dashboard. Keep `hive-analytics` migration owner-managed and use it only as read-only usage evidence for Leerness development.
|
|
288
|
+
|
|
289
|
+
## 1.36.271 - 2026-09-23
|
|
290
|
+
|
|
291
|
+
- Name the main session owner in generated start, shared-writeback and close requirements so delegated workers and reviewers do not inherit conflicting session-wide commands. Retire only the exact older Korean lines from a managed migration when the original is backed up byte-for-byte; preserve edited and custom instructions. A copied-project rehearsal preserves task/rule state, while the live project update remains pending concurrent work.
|
|
292
|
+
|
|
293
|
+
## 1.36.270 - 2026-09-23
|
|
294
|
+
|
|
295
|
+
- Keep session-close handoffs aligned with the owner's current task priority: explicit task selection, then numbered owner priorities, then the most recently updated actionable task. Report the selected task and its source; reject invalid selections and ambiguous priority markers before changing documents. Recheck the plan before publication and preserve authored rules.
|
|
296
|
+
|
|
297
|
+
## 1.36.269 - 2026-09-23
|
|
298
|
+
|
|
299
|
+
- Keep old generated start, close and review-wide instructions from returning during managed Claude, Cursor and Copilot migrations when an exact original backup exists. Preserve edited and project-specific text. Honor `migrate --no-env` when skipping environment file generation and show the correct migration command in its dry-run preview. A full managed-file rehearsal used a copy of `hive-analytics`; the live project was not updated.
|
|
300
|
+
|
|
301
|
+
## 1.36.268 - 2026-09-23
|
|
302
|
+
|
|
303
|
+
- Retire the exact old Korean AGENTS.md bootstrap and mandatory 11-document reading block during a managed migration only when an identical original is present in the migration backup. Preserve modified or user-authored instructions. Keep scoped owner/worker/reviewer guidance, task state and active rules; no live project update or automatic history retention is enabled.
|
|
304
|
+
|
|
305
|
+
## 1.36.267 - 2026-09-23
|
|
306
|
+
|
|
307
|
+
- Treat a completed retention journal as incomplete when its archive manifest, completion receipt or expected index is missing or changed, so archived IDs cannot silently appear unused. Refuse a task list assembled across a concurrent restore. Rehearse exact retention, task lookup and restoration on a bounded copy of a real project; no automatic retention or source-project change is enabled.
|
|
308
|
+
|
|
309
|
+
## 1.36.266 - 2026-09-23
|
|
310
|
+
|
|
311
|
+
- Add explicit task-history previews, retained originals, exact restoration and source-bound recovery. Pending operation records stop incomplete-history reads and task-ID allocation; changed inputs or ambiguous task tables refuse publication. Keep existing owner-lock protection after a process crash and report the required manual lock recovery. No automatic retention, deletion or project rollout is enabled.
|
|
312
|
+
|
|
313
|
+
## 1.36.265 - 2026-09-22
|
|
314
|
+
|
|
315
|
+
- Reject unsafe or exhausted retained task IDs before allocation and require typed index identifiers/digests. Check the combined active/retained range for sequential and batch task creation before writing. Verify retained evidence using the existing claim response contract, including missing implementation failures. Refresh legacy self-checks to exercise current status normalization, invalid-date handling and corrupted team storage; preserve minimal-mode review requirements without an obsolete length ratio.
|
|
316
|
+
|
|
317
|
+
## 1.36.264 — 2026-09-22
|
|
318
|
+
|
|
319
|
+
- Add fail-closed indexed retained task history for CTX-02B: preserve task totals and historical ID reservation, resolve exact retained tasks for verification/current context, include retained task rows in full listing/search/archive views, and validate source/row SHA-256 before reading retained evidence. No archive move, restore, deletion or automatic retention is enabled.
|
|
320
|
+
|
|
321
|
+
## 1.36.263 — 2026-09-22
|
|
322
|
+
|
|
323
|
+
- Require the reviewer's final NO GO response to explain the needed changes and fixed GO checks, including reviews outside the feedback CLI. Group actionable blockers, missing verification, owner decisions and optional suggestions; expose derived GO requirements without changing review history, criteria, stop limits or approval authority.
|
|
324
|
+
|
|
325
|
+
## 1.36.262 — 2026-09-22
|
|
326
|
+
|
|
327
|
+
- Add read-only current task/rule navigation and metadata-only context size diagnosis. Session close limits terminal history to recent references, reports full totals, and refreshes only its marked handoff summary while retaining legacy prose and canonical records.
|
|
328
|
+
|
|
329
|
+
## 1.36.261 — 2026-09-22
|
|
330
|
+
|
|
331
|
+
- Preserve environment snapshot annotations and Unicode during checked saves; report conflicts and partial-save failures across explicit detection and handoff writeback.
|
|
332
|
+
|
|
333
|
+
## 1.36.260 — 2026-09-22
|
|
334
|
+
|
|
335
|
+
- Preserve legacy handoff history and metadata with checked UTF-8 capture, rolling retention and explicit publication failure reporting.
|
|
336
|
+
|
|
337
|
+
## 1.36.259 — 2026-09-22
|
|
338
|
+
|
|
339
|
+
- Preserve authored handoff reminders during refresh and cleanup; check UTF-8 and captured identity, retain newline style, and report storage failures without false success.
|
|
340
|
+
|
|
341
|
+
## 1.36.258 — 2026-09-22
|
|
342
|
+
|
|
343
|
+
- Check team source and generated view before saving; preserve Unicode and metadata, reject authored or stale projections, and report partial publication without replaying an uncertain two-file save.
|
|
344
|
+
|
|
345
|
+
## 1.36.257 — 2026-09-22
|
|
346
|
+
|
|
347
|
+
- Preserve environment example text during sync; check private-source and target integrity, append missing names with empty values under the shared lock, and report publication failures with recovery evidence.
|
|
348
|
+
|
|
349
|
+
## 1.36.256 — 2026-09-22
|
|
350
|
+
|
|
351
|
+
- Preserve feature graph prose and multilingual text through checked add/link edits; reject malformed or stale source, keep existing creation and no-op behavior, and publish new graphs only after candidate validation.
|
|
352
|
+
|
|
353
|
+
## 1.36.255 — 2026-09-21
|
|
354
|
+
|
|
355
|
+
- Scope generated onboarding and delegation to the assigned role and current rules; retain independent evidence checks, remove invented compact rules, and preserve custom context-routing instructions during updates. Guidance only; existing projects require an explicit harness update.
|
|
356
|
+
|
|
357
|
+
## 1.36.254 — 2026-09-21
|
|
358
|
+
|
|
359
|
+
- Preserve audit ignore and environment example text; check private key sources without copying values and report partial save failures
|
|
360
|
+
|
|
361
|
+
## 1.36.253 — 2026-09-21
|
|
362
|
+
|
|
363
|
+
- Preserve README and package source integrity during audit version fixes; count confirmed saves and report partial failures instead of swallowing them.
|
|
364
|
+
|
|
365
|
+
## 1.36.252 — 2026-09-21
|
|
366
|
+
|
|
367
|
+
- Guard audit timestamp edits with checked UTF-8 source capture and publication; preserve missing/resolved documents, count confirmed saves and report partial failure.
|
|
368
|
+
|
|
369
|
+
## 1.36.251 — 2026-09-21
|
|
370
|
+
|
|
371
|
+
- Protect explicit handoff date saves with checked UTF-8 and captured source validation; preserve Unicode, BOM and unchanged files, and avoid unconditional state-update claims.
|
|
372
|
+
|
|
373
|
+
## 1.36.250 — 2026-09-21
|
|
374
|
+
|
|
375
|
+
- Mode changes now preflight strict manifest and instruction snapshots, preserve authored text and metadata, and report partial save failures without false success. Shared text storage supports smaller captured byte limits; isolated CLI and compatibility regressions added.
|
|
376
|
+
|
|
377
|
+
## 1.36.249 — 2026-09-21
|
|
378
|
+
|
|
379
|
+
- Rule mutations now preserve valid multilingual text and reject malformed or stale captured input; checked archive IDs, stable lock order and archive-first removal report partial saves. Focused CLI regression and supported runtime checks added.
|
|
380
|
+
|
|
381
|
+
## 1.36.248 — 2026-09-21
|
|
382
|
+
|
|
383
|
+
- Optional harness authoring language independent of user-facing explanations; retain saved selection, preserve source text, expose policy in handoff and delegation, and keep legacy installs unchanged.
|
|
384
|
+
|
|
385
|
+
## 1.36.247 — 2026-09-21
|
|
386
|
+
|
|
387
|
+
- Protect installer text and environment migration with strict UTF-8 snapshots, preserved signatures and values, checked publication and explicit partial-failure reporting
|
|
388
|
+
|
|
389
|
+
## 1.36.246 — 2026-09-21
|
|
390
|
+
|
|
391
|
+
- Require actionable reviewer feedback, freeze acceptance criteria and stop unproductive review loops without automatic approval.
|
|
392
|
+
|
|
393
|
+
## 1.36.245 — 2026-09-21
|
|
394
|
+
|
|
395
|
+
- Protect generated instruction merge and creation with strict text snapshots, preserve user files across races, and report partial installation progress.
|
|
396
|
+
|
|
397
|
+
## 1.36.244 — 2026-09-21
|
|
398
|
+
|
|
399
|
+
- Protect brief and README text publication, preserve authored sections and CRLF fields, preflight paired writes, and check exports and anchor brief saves.
|
|
400
|
+
|
|
401
|
+
## 1.36.243 — 2026-09-21
|
|
402
|
+
|
|
403
|
+
- Protect session-close documents and direct text sources against malformed Unicode, stale changes and unsafe publication; retain LF/CRLF frontmatter and report partial document saves.
|
|
404
|
+
|
|
405
|
+
## 1.36.242 — 2026-09-21
|
|
406
|
+
|
|
407
|
+
- Plan and archive commands now reject malformed text, preflight paired candidates and preserve captured originals through checked publication. Partial publication errors name the saved side; scope exclusions support CRLF and reject malformed tables. Private development candidate; remaining generation and session-close boundaries plus optional English stay planned.
|
|
408
|
+
|
|
409
|
+
## 1.36.241 — 2026-09-21
|
|
410
|
+
|
|
411
|
+
- Task table saves now reject malformed UTF-8 and invalid Unicode, preserve captured input through checked publication, and preflight imported task text. Windows temporary cleanup removes only empty reservations; Node 24 Korean-path crash regression covered. Private development candidate; other prose stores and optional English remain follow-up.
|
|
412
|
+
|
|
413
|
+
## 1.36.240 — 2026-09-21
|
|
414
|
+
|
|
415
|
+
- Encoding diagnostics now separate byte validity, unchecked scope, and advisory prose damage signals; read-only scans preserve originals, with bounded reads and Windows Node24 compatibility.
|
|
416
|
+
|
|
417
|
+
## 1.36.239 — 2026-09-20
|
|
418
|
+
|
|
419
|
+
- Preserve split UTF-8 and final JSON frames in interactive CLI responses; share bounded process collection with benchmark, reject invalid/partial output and stdin failures, and record one terminal outcome. Offline stream probe 31 groups; ENC-01 diagnostics/storage/language work remains open.
|
|
420
|
+
|
|
421
|
+
## 1.36.238 — 2026-09-20
|
|
422
|
+
|
|
423
|
+
- Rule verification: distinguish historical active records and keyword observations from compliance; retain unverified obligations and preserve authored rules.
|
|
424
|
+
|
|
425
|
+
## 1.36.237 — 2026-09-16
|
|
426
|
+
|
|
427
|
+
- Remove decorative icons from managed harness instructions and handoff labels while preserving user Unicode; clarify UTF-8 and PowerShell guidance in both languages. Token savings are not inferred from byte counts.
|
|
428
|
+
|
|
429
|
+
## 1.36.236 — 2026-09-16
|
|
430
|
+
|
|
431
|
+
- Preserve split UTF-8 benchmark output, report full response size, and fail bounded collection on invalid bytes, output overflow or timeout; failed providers now give exit code 1. See docs/agent-bench-output.md.
|
|
432
|
+
|
|
433
|
+
## 1.36.235 — 2026-09-16
|
|
434
|
+
|
|
435
|
+
- 별도 로그인 없는 UI scan 및 review packet/assess CLI: 기존 검사·coverage·stale 판정 재사용, 기본 요약/JSON, 프로젝트 무변경. 실제 독립 의미 검수와 승인은 별도.
|
|
436
|
+
|
|
437
|
+
## 1.36.234 — 2026-09-16
|
|
438
|
+
|
|
439
|
+
- GitHub OAuth 로그인 연결: state/PKCE와 인증 계정 ID 허용 목록, 일회 callback 및 짧은 메모리 세션. 대상 승인과 운영 로그인 검증은 별도.
|
|
440
|
+
|
|
441
|
+
## 1.36.233 — 2026-09-16
|
|
442
|
+
|
|
443
|
+
- 검증 확인서의 일회 사용을 대상/control/정책 Git ref 동시 대조로 저장하고 재시작·응답 유실 후 과거 사용 기록을 조회. 실제 GitHub 로그인 및 최종 승인은 후속.
|
|
444
|
+
|
|
445
|
+
## 1.36.232 — 2026-09-15
|
|
446
|
+
|
|
447
|
+
- 승인 정책의 관측 하한을 기존 Git CAS에 보존: 재시작 후 후퇴/철회 보존, 동시 갱신 및 불명확한 저장 복구, 선택 호스트 연결. 실제 승인자 인증과 승인 기록 저장은 후속.
|
|
448
|
+
|
|
449
|
+
## 1.36.231 — 2026-09-15
|
|
450
|
+
|
|
451
|
+
- 호스트 고정 키로 서명된 승인 정책을 검증하고 철회·revision 후퇴·정책 교체를 거부. 정책 인증서와 호스트 기준을 확인서에 결박하며 기존 직접 검증 v1과 승인 미부여 상태 유지.
|
|
452
|
+
|
|
453
|
+
## 1.36.230 — 2026-09-15
|
|
454
|
+
|
|
455
|
+
- 승인 확인서의 서명·정확한 대상·현재 담당 세션·유효기간을 읽기 전용으로 검증하는 구성요소 추가. 정책 출처 인증과 실제 승인 쓰기는 후속이며 승인 권한은 미검증으로 유지.
|
|
456
|
+
|
|
457
|
+
## 1.36.229 — 2026-09-15
|
|
458
|
+
|
|
459
|
+
- Compare a retained UI review and its result journal with an explicit Git target, record digest and current review requirements. Reuse the original binary material and record validators.
|
|
460
|
+
- Preserve changed criteria, coverage gaps, incomplete execution, findings and self-review as separate evidence. Recheck target/run/attempt/result refs without creating records, running a provider or granting approval.
|
|
461
|
+
- Share the validated retention reader and add focused real-Git target and mutation probes.
|
|
462
|
+
|
|
463
|
+
## 1.36.228 — 2026-09-15
|
|
464
|
+
|
|
465
|
+
- Explicitly connect a saved provider observation to one reviewer terminal event and the existing result journal. Bind the original observation, contributor, materials and ledger prefix; require approval of the exact local publication preview.
|
|
466
|
+
- Reconcile uncertain writes without repeating HTTP or terminal events. Keep result bytes stable after unrelated ledger appends, resynchronize existing events, and expose existing RunRecord recovery with separate explicit retention.
|
|
467
|
+
- Reject conflicting history and incomplete executions, preserve findings without granting approval, and fence result publication against changed control or observation refs. Add real Git, TLS, process interruption and contention probes.
|
|
468
|
+
|
|
469
|
+
## 1.36.227 — 2026-09-15
|
|
470
|
+
|
|
471
|
+
- Share the CLI state lock with library ledger writes. Distinguish true nested work from unrelated asynchronous callers and reject same-process contention without blocking the event loop.
|
|
472
|
+
- Take the real shared lock for ledger appends by default and expose a checked ledger transaction boundary. Preserve owner tokens, release behavior, dry-run/runtime checks and uncertain history without automatic takeover or repair.
|
|
473
|
+
- Cover CLI/library async ownership and real multi-process appends. Bound retries when cleaning this test run's temporary fixtures after Windows file I/O; keep assertion failures visible.
|
|
474
|
+
|
|
475
|
+
## 1.36.226 — 2026-09-15
|
|
476
|
+
|
|
477
|
+
- Synchronize the execution ledger's written file descriptor before reporting append success or publishing a newly created ledger. Surface synchronization failure without retrying or removing uncertain appended bytes.
|
|
478
|
+
- Add storage-fault, short-write and fresh-process termination regressions to the local suites. File synchronization does not guarantee directory metadata durability or replace shared locking and recovery.
|
|
479
|
+
|
|
480
|
+
## 1.36.225 — 2026-09-15
|
|
481
|
+
|
|
482
|
+
- Fix SessionStart hook installation to emit nested typed handlers, recognize existing nested settings, and repair legacy flat hooks without dropping custom handlers/options. Read-only status no longer marks flat hooks as fully installed.
|
|
483
|
+
- Add real CLI hook regressions and Codex/Claude configuration diagnostics. A valid JSON hook and terminal success do not certify host trust or runtime execution.
|
|
484
|
+
- Add staged test guidance to Korean/English project templates: failed test, related checks, one final required CI; bounded readiness checks, safe generated-artifact handling, and revision-specific evidence. Correct stale test-tier duration claims; automatic selection and CI skipping remain unimplemented.
|
|
485
|
+
|
|
486
|
+
## 1.36.224 — 2026-09-15
|
|
487
|
+
|
|
488
|
+
- Validate the complete journal envelope before Git object writes, including depth/node limits added by wrapping an HTTP-valid response.
|
|
489
|
+
- Explicitly retain validated bound GET observations in a canonical Git journal with stable IDs, create-only publication and fresh-process recovery. Preserve original and observed ledger prefixes; keep review-event and RunRecord publication separate. Private development candidate.
|
|
490
|
+
|
|
491
|
+
## 1.36.223 — 2026-09-15
|
|
492
|
+
|
|
493
|
+
- Explicitly request a bound UI receipt and validate actual stored-response GET output against the original attempt, packet, declared model, material digests and ledger prefix. Preserve legacy v1/v2 behavior and distinguish incomplete reviews. No reviewer-event writes, RunRecord publication or approval; private development candidate.
|
|
494
|
+
|
|
495
|
+
## 1.36.222 — 2026-09-15
|
|
496
|
+
|
|
497
|
+
- Explicitly opt into pre-dispatch material retention and original ledger-prefix evidence; recover inputs read-only across process interruption using bounded Git ancestry. Existing v1 defaults stay unchanged. No automatic receipt, RunRecord or final approval; private development candidate.
|
|
498
|
+
|
|
499
|
+
## 1.36.221 — 2026-09-14
|
|
500
|
+
|
|
501
|
+
- RB-03B2b: explicit UI review request preview, one-shot OpenAI dispatch fenced by original run, durable response locator and read-only bound lookup; offline Git/TLS interruption tests; private development only
|
|
502
|
+
|
|
503
|
+
## 1.36.220 — 2026-09-14
|
|
504
|
+
|
|
505
|
+
- RB-03B2a: add bounded read-only stored OpenAI response retrieval; explicit credential/project, single fixed-host GET, TLS/deadline/JSON validation; no dispatch binding or automatic review recovery. Private development candidate.
|
|
506
|
+
|
|
507
|
+
## 1.36.219 — 2026-09-14
|
|
508
|
+
|
|
509
|
+
- RB-03B1: journal completed UI observations and recover retained outcomes without re-executing the reviewer; private development candidate only.
|
|
510
|
+
|
|
511
|
+
## 1.36.218 — 2026-09-14
|
|
512
|
+
|
|
513
|
+
- RB-03A: reserve UI review attempts durably and fence callback start with Git CAS; preserve execution-unknown after interruption and recover retained results without re-execution. Private development candidate; no provider authorization or public release.
|
|
514
|
+
|
|
515
|
+
## 1.36.217 — 2026-09-14 (private development, unreleased)
|
|
516
|
+
|
|
517
|
+
- Run the public CI jobs only in the public repository, keeping the Linux/Windows release matrix. No product, npm or site changes.
|
|
518
|
+
|
|
519
|
+
## 1.36.216 — 2026-09-14
|
|
520
|
+
|
|
521
|
+
- RB-02E: 실제 UI 관측과 실행원장 참조를 불변 Git RunRecord에 보존하고 지정 리비전의 기록 및 자료 digest를 무쓰기 검증. 저장 재시도는 검토를 재실행하지 않음. 독립 검토와 accepted 권한 및 cleanup은 미승인 유지.
|
|
522
|
+
|
|
523
|
+
## 1.36.215 — 2026-09-14
|
|
524
|
+
|
|
525
|
+
- RB-02D: 검수 batch의 Git ref 저장, 소유권 세대와 CAS, 멱등 재시도·중단 복구 및 스냅샷 이력 보존 추가. 로컬 library 범위이며 자동 dispatch/독립 승인/RunRecord finalize는 미활성.
|
|
526
|
+
|
|
527
|
+
## 1.36.214 — 2026-09-14
|
|
528
|
+
|
|
529
|
+
- 실제 dashboard UI 수집에 명시 표면 예산을 적용하고 고정 대조군의 오탐·의미 누락·후보 제거율·수정 자동화 비용을 측정. partial/stale 자료는 품질 비율에서 제외. 기본 scanner 정책과 UI 문구는 유지. 로컬 미배포.
|
|
530
|
+
|
|
531
|
+
## 1.36.213 — 2026-09-14
|
|
532
|
+
|
|
533
|
+
- Chromium DOM layout 및 native accessibility copy를 기존 UI boundary scanner에 연결. 인라인/생성 문구, 입력 내용 제외, 관측 변경과 수집 누락, 원문 없는 batch metadata를 검증. 로컬 미배포 후보.
|
|
534
|
+
|
|
535
|
+
## 1.36.212 — 2026-09-14
|
|
536
|
+
|
|
537
|
+
- UIB-04C: 단일 task UI 증거와 기존 실행 원장 parent/attempt/actor 선언·검수 receipt를 대조하고 재사용·원장 교체를 거부. 원장의 선언을 인증된 공급자/독립 승인으로 승격하지 않음.
|
|
538
|
+
|
|
539
|
+
## 1.36.211 — 2026-09-14
|
|
540
|
+
|
|
541
|
+
- UIB-04B: 명시 UI 증거 bytes/digest 대조 및 bounded checked read, 일회성 host callback 관측·원본 재확인·동일 task finding 결박. 독립 actor/semantic 인증과 공개출하는 미실행.
|
|
542
|
+
|
|
543
|
+
## 1.36.210 — 2026-09-14
|
|
544
|
+
|
|
545
|
+
- UIB-04A: bounded UI review material and receipt contracts with snapshot reuse, typed coverage, stale detection and conservative identity declarations; local unreleased candidate.
|
|
546
|
+
|
|
547
|
+
## 1.36.209 — 2026-09-14
|
|
548
|
+
|
|
549
|
+
- UIB-03: bounded UI surface scanner with shared secret patterns, aggregate security findings, digest-only review projection and syntax controls; local unreleased candidate.
|
|
550
|
+
|
|
551
|
+
## 1.36.208 — 2026-09-14
|
|
552
|
+
|
|
553
|
+
- UIB-02: integrate optional versioned UI Boundary role, review-task and ledger contracts; preserve legacy behavior, scoped coverage and sanitized finding provenance without granting approval or enabling dispatch.
|
|
554
|
+
|
|
555
|
+
## 1.36.207 — 2026-09-14
|
|
556
|
+
|
|
557
|
+
- UIB-01: add versioned pure UI Boundary metadata assessment and five leakage subtypes with positive/negative controls. No UI enforcement, scanner, automatic deletion or independent semantic approval.
|
|
558
|
+
|
|
559
|
+
## 1.36.206 — 2026-09-13
|
|
560
|
+
|
|
561
|
+
- Windows Node24 저장소 진단의 정상 파일 dev0 오거부 수정. 읽기 후 handle·경로·부모를 재확인하고 close 실패를 원문 없는 진단으로 반환; 1MiB 한도와 읽기 전용 계약 유지. 로컬 미배포 후보.
|
|
562
|
+
|
|
563
|
+
## 1.36.205 — 2026-09-13
|
|
564
|
+
|
|
565
|
+
- Windows Node24 역할 설정 읽기·저장과 실행원장 읽기·추가의 dev0 오거부 수정. 읽기 후와 원장 쓰기 전후 확인 handle·부모검사 및 기존 보존·오류 거부 유지. 로컬 미배포 후보.
|
|
566
|
+
|
|
567
|
+
## 1.36.204 — 2026-09-13
|
|
568
|
+
|
|
569
|
+
- Windows Node24의 pathname dev0로 정상 runtime descriptor를 거부하던 오류 수정. 두 번째 handle로 장치·파일·metadata를 재확인하며 링크·경합·16KiB 제한과 실패 거부 유지. 로컬 미배포 후보.
|
|
570
|
+
|
|
571
|
+
## 1.36.203 — 2026-09-13
|
|
572
|
+
|
|
573
|
+
- 명시 memory 정책의 복구를 최대64KiB chunk로 전송하고 실패별 읽기·쓰기 비용과 불완전 원본을 기록. 외부 fallback 사전권한·128파일/128MiB 경계를 유지하며 실패 artifact 보존. 로컬 미배포 후보.
|
|
574
|
+
|
|
575
|
+
## 1.36.202 — 2026-09-13
|
|
576
|
+
|
|
577
|
+
- 명시 memory 정책의 publication 검증 재읽기에 상한을 전달하고 cleanup 잔존 파일을 CLI·MCP·부분 실패 receipt로 보고한다. 복구 원문 복사 예산과 물리적 예약은 미보장으로 유지한다.
|
|
578
|
+
|
|
579
|
+
## 1.36.201 (Unreleased)
|
|
580
|
+
|
|
581
|
+
- Connect optional complete memory write policies to decision/lesson add, save, drop and restore in CLI and MCP. Bound initial memory reads and check candidates before serialization; retain locks, duplicate/force semantics, lossless archives, source rechecks and existing default behavior. No operating limits are selected automatically.
|
|
582
|
+
|
|
583
|
+
## 1.36.200 (Unreleased)
|
|
584
|
+
|
|
585
|
+
- Add explicit internal memory write admission with bounded initial reads, JSON depth checks and output cost checks before preparation. Separate hard processing limits from target sizes so explicitly requested reductions can recover oversized stores without bypassing processing limits. Default CLI/MCP writer limits remain unchanged.
|
|
586
|
+
- Restore the dry-run refusal code for memory mutations by checking write permission before publication starts; retain zero writes and duplicate no-op behavior.
|
|
587
|
+
|
|
588
|
+
## 1.36.199 (Unreleased)
|
|
589
|
+
|
|
590
|
+
- Bind decisions/lessons writes to a single-use prepared candidate and checked source. Reuse the same immutable output bytes for publication and optional cost assessment; preserve existing command selection and recovery stages without activating default size limits.
|
|
591
|
+
- Align the UTF-8 regression fixtures with the existing lossless legacy preservation contract, testing both admitted generated-format Markdown and rejected lossy rewrites.
|
|
592
|
+
|
|
593
|
+
## 1.36.198 (Unreleased)
|
|
594
|
+
|
|
595
|
+
- Add an explicit read-only memory write cost preflight that combines bounded source and recovery capture with candidate, retained suffix, archive and backend-specific normal publication costs. Recheck the original inputs before returning metadata; no writer policy or write authorization is activated.
|
|
596
|
+
|
|
597
|
+
## 1.36.197 (Unreleased)
|
|
598
|
+
|
|
599
|
+
- Add an explicit-budget, read-only memory footprint API for checked canonical/projection/archive bytes and a bounded, rechecked recovery metadata inventory, including files without receipts. Writer defaults remain unchanged.
|
|
600
|
+
|
|
601
|
+
## 1.36.196 (Unreleased)
|
|
602
|
+
|
|
603
|
+
- Add a pure memory candidate budget diagnostic with explicit caller limits, iterative JSON byte counting and pre-parse input/depth checks. Ordinary writer defaults remain unchanged.
|
|
604
|
+
|
|
605
|
+
## 1.36.195 (Unreleased)
|
|
606
|
+
|
|
607
|
+
- Reject unsupported decision/lesson item shapes and non-string rendered fields before duplicate, selection or write paths; preserve missing/null fields and unknown JSON extensions.
|
|
608
|
+
- Return a stable CLI error code with surface, item index and field metadata while preserving canonical, projection and archive files on rejection.
|
|
609
|
+
- Preserve existing CLI whitespace, duplicate and force behavior; retain ordinary writer size/count defaults pending measured admission policy.
|
|
610
|
+
|
|
611
|
+
## 1.36.194 (Unreleased)
|
|
612
|
+
|
|
613
|
+
- Add explicit CLI preparation, application and rollback of legacy decision/lesson memory, retaining and verifying original Markdown before active publication.
|
|
614
|
+
- Reuse canonical locks, runtime admission, checked input/output and partial recovery records; refuse changed or unattributed files and preserve withdrawn canonical data in the archive.
|
|
615
|
+
- Add failure injection, path/runtime boundary and actual competing-process regressions; keep the MCP migration inspection tool read-only.
|
|
616
|
+
- Fix Windows output observation on Node builds that report an unknown path device: confirm identity through descriptors while still rejecting unknown descriptor identity and mismatched metadata.
|
|
617
|
+
|
|
618
|
+
## 1.36.193 (Unreleased)
|
|
619
|
+
|
|
620
|
+
- Add read-only CLI/MCP observation of legacy memory migration candidates with bounded checked input and final source/runtime rechecks.
|
|
621
|
+
- Share lexical-parent resolution checks across memory input and publication; preserve existing writer size behavior.
|
|
622
|
+
- Add file-change, runtime-change, whole-command no-write and private metadata regressions.
|
|
623
|
+
|
|
624
|
+
## 1.36.192 — Unreleased (2026-09-12)
|
|
625
|
+
|
|
626
|
+
- feat(memory): add an internal pure legacy migration assessor for caller-supplied decision/lesson observations; return bounded metadata about retained-raw requirements without reading files, exporting memory contents, authorizing writes or applying a migration
|
|
627
|
+
- safety(memory): bound raw input, combined candidate output sizes and the existing decision parser's repeated-fence scan estimate; preserve uncertainty and refuse oversized work before parsing or whole-output rendering
|
|
628
|
+
- test: cover input and format contracts, exact byte boundaries, current writer-format agreement, and isolated execution without I/O or canonical payload construction
|
|
629
|
+
|
|
630
|
+
## 1.36.191 — Unreleased (2026-09-12)
|
|
631
|
+
|
|
632
|
+
- fix(memory): apply checked projection preservation to legacy-only decision/lesson add, save, drop, restore and migration backfill; retain exact appended text and refuse record rewrites that would discard original Markdown
|
|
633
|
+
- fix(memory): retain record-free init templates and manual notes as opaque appended text, and include UTF-8 BOMs in preservation checks instead of silently stripping them
|
|
634
|
+
- test: exercise legacy preservation, refusal without domain file changes, forced mutations, dry runs, fresh initialization and subsequent canonical writes through the actual CLI
|
|
635
|
+
|
|
636
|
+
## 1.36.190 — 2026-09-08
|
|
637
|
+
|
|
638
|
+
- fix(memory): reject existing non-array decision/lesson JSON before writes or duplicate success; retain syntax-error codes, absent-file backfill and read-only fallback
|
|
639
|
+
- fix(memory): prepare JSON and Markdown before add/save/drop writes, including drop archives; preserve existing locks and I/O order without claiming multi-file transactions or lossless restore
|
|
640
|
+
- test: cover memory input rejection and output preparation in source and installed consumers with normal CRUD, legacy and migration controls
|
|
641
|
+
- test: carry bounded installed-handoff child lifecycle, completion diagnostics and watchdog coverage into the next release candidate
|
|
642
|
+
|
|
643
|
+
## 1.36.189 — 2026-09-08
|
|
644
|
+
|
|
645
|
+
- ci: add Linux and Windows installed-package gates so tarball contents and consumer execution are tested separately from source checkout
|
|
646
|
+
|
|
647
|
+
- test: validate installed store diagnostics, state inspection, MCP presence and memory guard ordering in isolated consumer projects; retain nonempty result and timeout diagnostics
|
|
648
|
+
|
|
649
|
+
- fix(memory): reject malformed decision and lesson JSON before duplicate selection, archive writes or restore projection changes; preserve existing read fallback and plan behavior
|
|
650
|
+
|
|
3
651
|
## 1.36.188 — 2026-09-08
|
|
4
652
|
|
|
5
653
|
- Add read-only state stores diagnostics for decision, lesson and role status, bounded reads and explicit fallback provenance; preserve metadata-only state inspect and existing mutation behavior.
|