From de7f5cde8bc8a9ee8952d50d09b985f7b84ad52c Mon Sep 17 00:00:00 2001 From: githubscum <65476409+githubscum@users.noreply.github.com> Date: Wed, 4 Nov 2026 00:37:25 -0600 Subject: [PATCH] KNOWN-LIMITS: amend 29, 65, 66, 70, 77 to match the code; add 87 Five entries still described fixes as missing after they landed. Each gets a dated status or amendment, with the old text kept. New limit 87: the shipped matcher returns no rule for tool-form scheduling (probe in the entry). Pin re-stamped; the stamp covers these entries, not a re-read of all 87. Co-Authored-By: Claude Opus 5.5 --- KNOWN-LIMITS.md | 82 +++++++++++++++++++++++++++++++++++++++++++++++-- 1 file changed, 80 insertions(+), 2 deletions(-) diff --git a/KNOWN-LIMITS.md b/KNOWN-LIMITS.md index 9129759..c3da904 100644 --- a/KNOWN-LIMITS.md +++ b/KNOWN-LIMITS.md @@ -1,8 +1,8 @@ @@ -967,6 +967,15 @@ for *truth* against `dc1910b`. Stamping on the strength of a numbering check would be a smaller lie than stamping on nothing, and it would still be one. The stamp remains owed by whoever verifies. +**Amended 2026-11-04: the automation exists.** "That CI wiring is still not built" is out of +date. CI has run `--check` since 2026-10-26 (`3f0f763`), and +`test/known-limits-committed-pin.test.js` reads the committed pin. **What this did not fix is +the entry's real subject, and this amendment is the proof.** On 2026-11-03 a read of the log +against the code found limits 29, 65, 66, 70 and 77 still describing fixes as missing after +they had landed, some for over a week, with CI green throughout. The pin check proves the +log is the one that was stamped. It does not prove the log is true, and it cannot notice a +closure that happened in the code and never reached the record. + ## 30. Edit tokens are fungible per file, so signing twice builds a grant by hand Found 2026-07-26, live, from a double-signing that was an accident. @@ -2594,10 +2603,19 @@ carries no digest; re-stamping is a separate act on `main`, as limit 29 intended, and nothing in `npm test` runs `--check` yet (the "nothing runs the check" paragraph above stays true). +**Amended 2026-11-04: that paragraph is no longer true.** CI landed on 2026-10-26 (`3f0f763`) +and runs `npm run limits-pin -- --check` on every pull request, on Ubuntu and on Windows, +next to `npm test` (`.github/workflows/ci.yml`). "Nothing runs the check" and "this +repository has no CI at all" are history. The pin at the top of this file carries a digest +now. The residual stands: a digest binds the text, not its truth. + --- ## 66. Subagent tool use is outside the witness entirely +**Status, amended 2026-11-04: the headline below is no longer true on the current +harness. Partly closed.** See the amendment at the end of this entry before quoting it. + **Found 2026-09-02**, on a real dispatch: one parent session, three concurrent children, chain rows counted across the window. @@ -2635,6 +2653,19 @@ can be bypassed": **the bypass does not require intent, and it is the normal case.** 519 is a floor rather than a point estimate, and the same-command asymmetry it exposes is filed separately as limit 70. +**Amended 2026-11-04: the harness changed, the hooks caught up, and the sentence "the gate +cannot see, record, or stop anything a subagent does" is now false here.** The harness fires +the same hooks for a tool call made inside a subagent, carrying the parent's `session_id` +plus `agent_id` and `agent_type`. Both hooks read those fields since the 2026-10-26 signing +sitting (`1c3e9f2`), and write them onto the row. A count on 2026-11-03 found 6,614 rows on +this machine's chain with a non-empty `agentId`, and a probe on 2026-10-22 stopped a +subagent's read of the chain at the self-mod gate (request `db8790d9`). The 2026-09-02 +measurement and the 519 replayed calls above were true of the harness of that date, and they +stand as history. **What remains open:** Lotor cannot tell which harness version it runs +under, so on a harness that does not route subagent tool events through hooks this entry +still holds in full, and nothing on the chain says which case a reader is in. A missing +`agentId` means a parent call or an older harness, and the row alone cannot separate them. + **Related.** Limit 67 is the same dispatch reporting numbers that do not match its own transcripts. Limit 44 is the other enforcement gap found by probing rather than by reading. @@ -2744,6 +2775,10 @@ stamp. ## 70. The protected-path rules are enforced against the parent and structurally unenforced against a child +**Status, amended 2026-11-04: narrowed, not closed.** On the current harness the same +command is gated whether the parent or a child runs it. See the amendment at the end of +this entry and the one on limit 66. + **Found 2026-09-02**, by replaying six weeks of real dispatches through the matcher rather than by staging a probe. @@ -2780,6 +2815,11 @@ configuration these 519 are an enforcement hole; today they are 519 missing rows The replay tool lives outside this repository, so a reader of this log cannot re-run it from here. +**Amended 2026-11-04.** "A subagent's calls never reach it" is false on the current harness: +they reach the hook and are attributed (limit 66's amendment). The asymmetry measured on +2026-09-02 survives only on a harness version that does not route subagent tool events +through hooks. Lotor cannot tell which version it runs under, so the entry stays, narrowed. + **Related.** Limit 66 is the same blindness stated as a recording gap rather than an enforcement one. Limit 62 is the other way a protected path escapes the self-mod rule: by spelling rather than by caller. @@ -3119,6 +3159,9 @@ core and is not touched here. ## 77. `matcherHash` depends on the checkout's line endings, so one commit has two stamps +**Status: CLOSED 2026-10-26 at the signing sitting (`1c3e9f2`), schema `matcher/3`.** The +queued patch below landed. See the closing note at the end of this entry. + `matcherVersionHash()` digests `Function.prototype.toString()` of the rule functions, and `toString()` returns the source text as loaded, line endings included. A Windows clone with `core.autocrlf=true` checks out CRLF, so the @@ -3158,6 +3201,14 @@ temp copies: patched LF equals patched CRLF, the patched LF stamp equals the unpatched LF stamp, and the unpatched control still differs. Until it lands, the limit stands as written above. +**CLOSED 2026-10-26.** The fold is in `matcherHashInputs()`, the schema is `matcher/3`, +`test/policy-matcher-stamp-eol.test.js` guards it, and the patch rehearsals now skip with a +message saying the patch landed. This entry kept reading "not landed" for nine days after +it did, which is limit 29's failure again. **Still open, and the entry already said so:** +how the receipts written before the change are read. Every CRLF-era stamp on this machine's +chain still differs from the LF stamp of the same commit, and `src/views/matcher-history.js` +is what tells them apart. + ## 78. The R2 tool I/O digest covers only the calls the post-tool-use hook already writes, and a guessable response can be recovered from it **Status: OPEN, recorded 2026-10-22 with v3 work order V3-03** (branch @@ -3352,3 +3403,30 @@ so a chain with an inserted garbage line can pass `store.verify()` and still refuse to seal; and re-sealing from scratch yields byte-identical notes (Ed25519 is deterministic and the note text is fixed by size and root), so losing the sidecar loses nothing a stranger kept. + +## 87. The scheduling rules read commands, and a harness can schedule through a tool + +**Found 2026-10-22 by reading the policy source; probed 2026-11-04 by running it.** Limit 44 +closed the shell forms of scheduling. A harness can also schedule through a tool call with +no shell in it. With all nine rules set to `gate`, the shipped `evaluate()` returned no rule +for each of these, each given a prompt that would run a remote script: + +| call | rule | +|---|---| +| `Bash`, `schtasks /create ...` (control) | scope-escalation | +| `Bash`, `crontab -e` (control) | scope-escalation | +| `CronCreate` | none | +| `ScheduleWakeup` | none | +| `RemoteTrigger` | none | +| `mcp__scheduled-tasks__create_scheduled_task` | none | +| `mcp__scheduled-tasks__update_scheduled_task` | none | + +The act is the same as the controls and the door is different: every command rule asks +whether the input has a `command` string, these have none, and the artifact half of limit 44 +looks only at `Write`, `Edit` and `NotebookEdit`. This is the same family as limit 31, which +says the rule set has no concept of actions scheduled for later. It is not a statement about +what a harness does with such a call, or whether a row is recorded for it; that depends on +how the hooks are registered, and it was not measured here. The input shapes in the probe +are this author's, and a list of tool names would only move the hole, so the fix is a +question for the policy's design rather than a rule to add. Any fix is a change to +`src/policy` (non-delegable core), and it waits for a signing sitting.