instar 1.3.11 → 1.3.13
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/dist/feedback-factory/processor/transitions.d.ts +44 -0
- package/dist/feedback-factory/processor/transitions.d.ts.map +1 -0
- package/dist/feedback-factory/processor/transitions.js +102 -0
- package/dist/feedback-factory/processor/transitions.js.map +1 -0
- package/dist/scheduler/MentorOnboardingRunner.d.ts +19 -0
- package/dist/scheduler/MentorOnboardingRunner.d.ts.map +1 -1
- package/dist/scheduler/MentorOnboardingRunner.js +44 -1
- package/dist/scheduler/MentorOnboardingRunner.js.map +1 -1
- package/dist/scheduler/MentorOnboardingTick.d.ts +10 -0
- package/dist/scheduler/MentorOnboardingTick.d.ts.map +1 -1
- package/dist/scheduler/MentorOnboardingTick.js +8 -0
- package/dist/scheduler/MentorOnboardingTick.js.map +1 -1
- package/dist/server/AgentServer.d.ts.map +1 -1
- package/dist/server/AgentServer.js +32 -3
- package/dist/server/AgentServer.js.map +1 -1
- package/dist/server/routes.d.ts.map +1 -1
- package/dist/server/routes.js +10 -10
- package/dist/server/routes.js.map +1 -1
- package/package.json +1 -1
- package/scripts/feedback-factory/_py_transitions_ref.py +49 -0
- package/scripts/feedback-factory/transitions-corpus.json +40 -0
- package/scripts/feedback-factory/transitions-parity.mjs +71 -0
- package/src/data/builtin-manifest.json +47 -47
- package/upgrades/1.3.12.md +26 -0
- package/upgrades/1.3.13.md +37 -0
- package/upgrades/side-effects/feedback-factory-transitions.md +34 -0
- package/upgrades/side-effects/mentor-live-readiness.md +63 -0
|
@@ -0,0 +1,34 @@
|
|
|
1
|
+
# Side-Effects Review — feedback-factory lifecycle state machine (Phase 1, increment 3)
|
|
2
|
+
|
|
3
|
+
**Slug:** `feedback-factory-transitions`
|
|
4
|
+
**Date:** `2026-05-26`
|
|
5
|
+
**Author:** Echo
|
|
6
|
+
**Spec:** `docs/specs/feedback-factory-migration.md` (converged v2, approved by Justin 2026-05-26)
|
|
7
|
+
**Scope:** The pure lifecycle decision logic — `V2_STATES`/`V2_TRANSITIONS`/`TRANSITION_GATES` constants, `can_transition` (:1045, scar a's evidence gate + the state machine + chronic circuit-breaker), and `detect_cycling` (:1139). The DB-coupled drivers (`cmd_transition`, the version-anchored half of `can_transition_to_verified`) are later increments.
|
|
8
|
+
|
|
9
|
+
## Summary of the change
|
|
10
|
+
|
|
11
|
+
Byte-exact port of the above from `the-portal/.claude/scripts/feedback-processor.py` to `src/feedback-factory/processor/transitions.ts`. Pure functions, no I/O. **Not wired into any route/job yet** — no behavioral change. Adds the transitions parity harness + Tier-1 unit tests.
|
|
12
|
+
|
|
13
|
+
This is the heart of scar (a): the evidence gate (terminal transitions to `wontfix`/`closed`/`chronic_escalated` require ≥20-char justification — unified with the `clusters.ts` API hard gate) and the chronic circuit-breaker (auto-block `chronic` at `recurrenceCount ≥ 3`, forcing `chronic_escalated`).
|
|
14
|
+
|
|
15
|
+
## Equivalence verification
|
|
16
|
+
|
|
17
|
+
- **33/33 cases match the reference Python** — both the `allowed` decision AND the exact `reason` string (the reasons interpolate Python's `sorted(set)` list-repr; the port reproduces it via `pyListRepr` so even the diagnostic text is byte-identical), plus all `detect_cycling` results.
|
|
18
|
+
- The check ORDER is preserved exactly (invalid target → unknown current → illegal transition → evidence gate → hard gate → chronic breaker), so the first-failing reason matches the reference for every case.
|
|
19
|
+
|
|
20
|
+
## Seven-dimension review
|
|
21
|
+
|
|
22
|
+
1. **Over/under-reach** — Pure deterministic functions, no I/O, no global state, not imported by any runtime path. Cannot affect existing behavior. The constants are exported read-only.
|
|
23
|
+
2. **Level-of-abstraction fit** — Processor-logic layer, alongside the fingerprint + similarity ports. Correct home. The state machine is data (constants) + a pure validator — no DB coupling, which is why it ports cleanly now (the DB-coupled verification driver waits for the data layer).
|
|
24
|
+
3. **Signal vs Authority** — `can_transition` is the structural evidence gate (scar a): it *enforces* that terminal transitions carry evidence, mirroring the `clusters.ts` API hard gate. This is legitimate authority that already exists in the reference (not new authority introduced by the port). The processor still never force-closes; it validates.
|
|
25
|
+
4. **Interactions** — None. New isolated module; nothing imports it yet. Parity scripts are LOCAL-only (external reference path via `PORTAL_PROCESSOR`).
|
|
26
|
+
5. **Rollback cost** — Trivial: delete the module + tests + scripts.
|
|
27
|
+
6. **Migration parity** — N/A. New internal library code; touches no agent-installed file.
|
|
28
|
+
7. **Failure modes** — (a) Port diverges from reference → caught by the parity harness (33/33, decisions+reasons+cycling) + unit assertions in CI. (b) A new lifecycle state added to the reference but not the port → the "every transition target is a known state" unit test + future parity runs catch drift; Dawn's review is the human backstop. (c) Reason-string repr divergence → parity asserts reasons byte-for-byte.
|
|
29
|
+
|
|
30
|
+
## Tests
|
|
31
|
+
|
|
32
|
+
- Tier-1 unit (CI): `tests/unit/feedback-factory/transitions.test.ts` — state legality, terminal states, evidence gate (both sides of 20 chars), dispatch hard gate, chronic circuit-breaker (recurrence 2 vs 3), cycling detection, constants integrity. 12 tests.
|
|
33
|
+
- Parity (local gate, evidence): `scripts/feedback-factory/transitions-parity.mjs` → **33/33** decisions + reasons + cycling identical to the reference Python.
|
|
34
|
+
- No integration/E2E this increment: not yet wired to a route/job; those tiers attach with the clustering/transition driver. Reasoned decision, documented.
|
|
@@ -0,0 +1,63 @@
|
|
|
1
|
+
# Side-Effects Review — Mentor live-readiness (§19.4 follow-on)
|
|
2
|
+
|
|
3
|
+
**Spec:** `docs/specs/FRAMEWORK-ONBOARDING-MENTOR-SPEC.md` (converged 5 iters, approved by Justin)
|
|
4
|
+
**Change:** Closes the three live-promotion blockers the §19.4 Phase-5 reviewer flagged, so the
|
|
5
|
+
mentor can be promoted toward `live` safely: (1) **async tick** — `POST /mentor/tick` is now
|
|
6
|
+
fire-and-forget (202) with the result in `GET /mentor/status`.lastResult, so a slow Stage-A spawn
|
|
7
|
+
can't hang the request; (2) **spawn-kill-on-timeout** — `spawnStageA` kills the session and throws
|
|
8
|
+
on poll exhaustion (no orphaned tmux pane, no partial transcript); (3) **persist-only delivery** —
|
|
9
|
+
`live` mode delivers the Stage-A message by appending to a durable per-mentee outbox, never via
|
|
10
|
+
`threadline_send`/spawn (the structural fix for the cross-agent spawn loop).
|
|
11
|
+
**Files:** `src/scheduler/MentorOnboardingTick.ts`, `src/scheduler/MentorOnboardingRunner.ts`,
|
|
12
|
+
`src/server/routes.ts`, `src/server/AgentServer.ts`, the three mentor test files, `upgrades/NEXT.md`.
|
|
13
|
+
|
|
14
|
+
## Principle check (Phase 1)
|
|
15
|
+
|
|
16
|
+
Decision point? Same as §19.4 — signal-only loop. The new delivery path is the only outbound
|
|
17
|
+
action, and it is **persist-only** (queue append), gated to `live` mode, and structurally cannot
|
|
18
|
+
spawn a counterpart session. Still ships dormant (`mentor.enabled=false`).
|
|
19
|
+
|
|
20
|
+
## The seven questions
|
|
21
|
+
|
|
22
|
+
1. **Over-block.** Async tick returns 202 even if a tick is in-flight (`accepted:false, reason:
|
|
23
|
+
in-flight`) — correct (no overlapping ticks). No legitimate action blocked.
|
|
24
|
+
2. **Under-block.** Spawn-kill-on-timeout closes the orphan/partial-transcript gap. Delivery is
|
|
25
|
+
persist-only — it queues; whether the mentee's session ingests the outbox is the mentee's side,
|
|
26
|
+
validated at the live step. The outbox write is best-effort (never throws) so a delivery failure
|
|
27
|
+
can't crash a tick — a dropped message is preferable to a crashed loop while dormant/dry-run.
|
|
28
|
+
3. **Level-of-abstraction fit.** Async state lives on the runner (`inFlight` + `lastResult`); the
|
|
29
|
+
route is a thin 202 trigger. Delivery is an injected service (pure tick stays I/O-free; the
|
|
30
|
+
AgentServer impl is the only thing that touches disk). Correct layering.
|
|
31
|
+
4. **Signal vs authority.** Compliant. Delivery is the loop's only outbound effect, persist-only,
|
|
32
|
+
live-gated. No component is gated/killed/blocked. The tick still has no authority over the user.
|
|
33
|
+
5. **Interactions.** `killSession` on timeout reuses the existing SessionManager kill path. The
|
|
34
|
+
outbox is a new dedicated dir (`server-data/mentor-outbox/`), isolated from the ledger and other
|
|
35
|
+
stores. The in-flight guard prevents the heartbeat job from stacking ticks.
|
|
36
|
+
6. **External surfaces.** `POST /mentor/tick` now returns 202 (was 200 with the result) for the
|
|
37
|
+
enabled case; disabled still returns 200 `{ran:false,reason:disabled}`. `GET /mentor/status` gains
|
|
38
|
+
`inFlight` + `lastResult`. The outbox is a local file, not an external call. Still Bearer-gated.
|
|
39
|
+
7. **Rollback cost.** Low. Dormant; revert restores the synchronous tick. The outbox dir is harmless
|
|
40
|
+
queued data.
|
|
41
|
+
|
|
42
|
+
## Phase 5 — second-pass
|
|
43
|
+
|
|
44
|
+
The §19.4 live loop already carried a dedicated second-pass (concur, 0 blocking). This PR
|
|
45
|
+
*implements that reviewer's three flagged fixes verbatim* (async tick, kill-on-timeout, persist-only
|
|
46
|
+
delivery), so it closes their concerns rather than introducing new decision surface. Self-reviewed
|
|
47
|
+
against their notes; no new spawning/gating logic beyond the persist-only outbox (which is the
|
|
48
|
+
spawn-loop-safe shape they recommended).
|
|
49
|
+
|
|
50
|
+
## Remaining before `live`
|
|
51
|
+
|
|
52
|
+
`dailySpendCapUsd` is still a run-count cap (`maxRoundsPerDay`, a real hard spend bound) rather than
|
|
53
|
+
dollar accounting — tracked (<!-- tracked: topic-13435 -->). Deep Stage-B forensics + surface
|
|
54
|
+
assembly land in the next PR. End-to-end mentee ingestion of the outbox is validated at the live
|
|
55
|
+
step (test-as-self), which remains Justin's sign-off per the off→dry-run→live track.
|
|
56
|
+
|
|
57
|
+
## Testing
|
|
58
|
+
|
|
59
|
+
- Tier 1 (unit, +3 tick): delivery in live-only / not dry-run / safe-when-unwired; (+2 runner):
|
|
60
|
+
startTick fire-and-forget 202 + result lands in status; disabled short-circuit.
|
|
61
|
+
- Tier 2 (integration): `/mentor/tick` 202-when-enabled + status.lastResult; disabled 200.
|
|
62
|
+
- Tier 3 (e2e): unchanged — dormant on the production path.
|
|
63
|
+
- route-completeness + discoverability gates pass; affected push-config suite green (745) vs main.
|