3 Commits

Author SHA1 Message Date
Michał Pierzchała d4cf02a889 chore(gates): classify #2278 daemon-platform-runtime edges and ratchet handler session authority (#2354)
* chore(gates): classify #2278 daemon-platform-runtime edges (R74) and ratchet handler session authority (R75)

* chore(gates): discover the R75 shape target from the SessionState declaration

* chore(gates): capture dynamic-import bindings in R74 so symbol drift cannot hide

* chore(gates): reject dynamic-import destructure residue in R74

* chore(gates): R74 rejects open-ended dynamic imports beside named bindings

* chore(gates): renumber daemon-platform-runtime-inventory to R76 (R74 taken on main)
2026-09-08 13:21:29 +02:00
Michał Pierzchała dcd8b65d4c refactor(daemon): split src/daemon/types.ts into request types and session state (#2346)
* refactor(daemon): split daemon/types.ts into request and session-state modules

`src/daemon/types.ts` served two audiences from one file: the dispatch request
shape and the daemon's live session record. It also sat in the only daemon type
cycle — it imported `RefFrame` from `ref-frame.ts`, which imported `SessionState`
back — so neither file could be read in isolation.

Three modules replace it, each importing only downward:

- `daemon-request-wire.ts` declares `DaemonWireRequest`: a dispatched request
  with no `internal` key and no property path to `SessionState` or `DeviceLease`,
  so a consumer can read a request's command, flags and public metadata without
  depending on the session record.
- `daemon-request.ts` adds the daemon-only half (`DaemonRequestInternal`, which
  stays unexported) plus the response vocabulary.
- `session-state.ts` owns `SessionState` and the shapes only it holds.

The cycle is cut by `ref-frame-slot.ts`, declared below both `ref-frame.ts` and
`session-state.ts`: it owns the frame VALUE (the class stays unexported, so the
type remains nominal and unconstructible from outside), while `ref-frame.ts`
keeps every lifetime transition and every `session.refFrame` write.

No behavior change: every importer moves to the module owning the symbol it
uses, with no re-export shim at the old path. `client-normalizers.ts` takes
`SessionRuntimeHints` from `@agent-device/kernel/contracts`, which declares it.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01Ujrc8LYmvM249WY8921J1Y

* test(daemon): assert the wire request shape cannot reach session state

A type-level walk over `DaemonWireRequest` fails `tsc` if the shape regains an
`internal` key or grows a property path back to `SessionState` or `DeviceLease`.
Positive controls over `DaemonRequest` prove the walk finds both when they are
there, so a walk that never matches anything cannot pass by accident.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01Ujrc8LYmvM249WY8921J1Y

* test(daemon): keep the three over-budget test files at their base length

Splitting `daemon/types.ts` turns one combined import into two in every file
that used both halves. Three of those test files are already over the 1,000-line
tripwire, where the size ratchet allows no growth, so each sheds one line that
was carrying nothing:

- `snapshot-handler.test.ts` and `find.test.ts` each drop a `toHaveLength`
  assertion an adjacent `toEqual` on an explicit array literal already makes.
- `session-replay-repair-transaction.test.ts` names the filtered close actions
  instead of wrapping the expression across three lines inside `expect`.

No assertion is weakened and no test content is removed. Splitting these files
along the modules they mirror is the standing remedy, but none of those modules
split here, so it stays out of this change and is tracked in #2353.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01Ujrc8LYmvM249WY8921J1Y

* chore(gates): point the daemon modularity and wire-compat gates at the split modules

R7 now locates the `SessionState` declaration by the declaration itself rather
than by a recorded path: `sessionStateWritePressure` measures the merge-base
tree too, and that tree still declares it in `daemon/types.ts` — a path constant
would measure it as zero pressure and bank the headroom.

R10's external-importer ratchet covers all three modules that replaced
`daemon/types.ts`, so moving a symbol between them cannot reopen the boundary to
a new outside zone. The recorded membership is unchanged: `client-normalizers.ts`
and `remote/daemon-artifacts.ts` both import `daemon-request.ts` only.

The daemon RPC closure gate waives `DaemonRequest`, `DaemonResponse` and
`DaemonArtifact` by path, so those three keys follow the declarations to
`daemon-request.ts`. `DaemonRequest`'s rationale now says what it is — the
server-side narrowing of the kernel declaration that fixes the wire shape —
rather than calling it a re-export alias.

The `live-state-shape` and session-resource declaration sites move with
`SessionState`; the depgraph lookalike fixture takes a new plausible path now
that `daemon/session-state.ts` is the real root.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01Ujrc8LYmvM249WY8921J1Y

---------

Co-authored-by: Claude <noreply@anthropic.com>
2026-09-06 12:36:54 +02:00
Michał Pierzchała 006f2d9f60 chore(gates): layering baselines ratchet against merge-base (#2299)
* refactor(layering): ratchet R6, R9 and R10 against the merge-base tree

R6 type-spine inversions, R9's largest type cycle and R10's R7 ownership
pressure now compare the working tree with the same measurement taken over
the merge-base with origin/main, read through the shared committed-tree
reader (one git ls-tree, one git cat-file --batch, no second checkout).
Growth still fails with the same message shape, a shrink needs no edit, and
no change can bank headroom by leaving a number above the tree.

R9's per-zone check gains membership from the reference, so the overflow
message names the file that joined instead of listing the whole zone.

* chore(gates): delete the R6, R9 and R10 pins the merge-base now supplies

TYPE_INVERSION_BASELINE, LARGEST_TYPE_CYCLE_ZONE_CEILINGS, TYPE_CYCLE_BASELINE
and DAEMON_MODULARITY_BASELINE.sessionState were the hand-edited references
these three ratchets compared against. The merge-base measurement replaces
them, so there is no number left to leave above the tree and no entry to raise.
externalDaemonTypesImporters stays: it names files, not a count.
2026-09-05 20:48:46 +02:00