instar 0.28.106 → 0.28.107

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.
@@ -0,0 +1,46 @@
1
+ /**
2
+ * AttributionResolver — read-side resolver for the burn-detection system.
3
+ *
4
+ * Phase 2 of docs/specs/token-burn-detection-and-self-heal.md.
5
+ *
6
+ * Pure function: given the shape of a TokenLedger event (sessionId, cwd,
7
+ * prompt text, model) returns an attribution_key suitable for grouping
8
+ * "calls of the same structural origin." Used by the Phase 3 BurnDetector
9
+ * to populate attribution_key for events the Phase 1 chokepoint did NOT
10
+ * write directly — chiefly the dominant Claude-CLI path where the JSONL
11
+ * trail carries the prompt and cwd but no source-side label.
12
+ *
13
+ * Authority shape: this is signal-only. It does not gate, throttle, or
14
+ * decide anything. It maps event → key. The detector emits, the
15
+ * Remediator decides. See umbrella spec §"Signal-vs-Authority Decomposition".
16
+ *
17
+ * No I/O, no time-dependent behavior — deterministic for tests + reasoning.
18
+ */
19
+ export interface AttributionEvent {
20
+ sessionId: string;
21
+ /** cwd / projectPath field from the JSONL line. */
22
+ projectPath?: string | null;
23
+ /** The user prompt that triggered the assistant response. Optional — when missing, resolver falls back to cwd / unknown. */
24
+ prompt?: string | null;
25
+ /** Model string from the JSONL line (`message.model`). */
26
+ model?: string | null;
27
+ }
28
+ /**
29
+ * Resolve an attribution_key for an event.
30
+ *
31
+ * Resolution order:
32
+ * 1. Manifest entry that matches the prompt (with optional cwd / model
33
+ * narrowing) → `<component>::<promptFingerprint>`.
34
+ * 2. cwd-based scheduled-job inference — if the cwd contains a path
35
+ * segment like `.instar/jobs/<name>`, return `user-job:<name>`.
36
+ * 3. cwd-based user-extension inference — if the cwd contains
37
+ * `.claude/hooks/` or `.instar/hooks/`, return the hook filename.
38
+ * 4. Fallback: `unknown::<sessionId-prefix>`.
39
+ *
40
+ * The prompt-based check is intentionally first: it's the most informative
41
+ * signal for the bleed-detection use case (one prompt shape running tens
42
+ * of thousands of times). cwd-based inference is the secondary signal for
43
+ * cases where the prompt is variable but the source is recognisable.
44
+ */
45
+ export declare function resolveAttribution(event: AttributionEvent): string;
46
+ //# sourceMappingURL=AttributionResolver.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"AttributionResolver.d.ts","sourceRoot":"","sources":["../../src/monitoring/AttributionResolver.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;GAiBG;AAKH,MAAM,WAAW,gBAAgB;IAC/B,SAAS,EAAE,MAAM,CAAC;IAClB,mDAAmD;IACnD,WAAW,CAAC,EAAE,MAAM,GAAG,IAAI,CAAC;IAC5B,4HAA4H;IAC5H,MAAM,CAAC,EAAE,MAAM,GAAG,IAAI,CAAC;IACvB,0DAA0D;IAC1D,KAAK,CAAC,EAAE,MAAM,GAAG,IAAI,CAAC;CACvB;AAED;;;;;;;;;;;;;;;;GAgBG;AACH,wBAAgB,kBAAkB,CAAC,KAAK,EAAE,gBAAgB,GAAG,MAAM,CAgClE"}
@@ -0,0 +1,107 @@
1
+ /**
2
+ * AttributionResolver — read-side resolver for the burn-detection system.
3
+ *
4
+ * Phase 2 of docs/specs/token-burn-detection-and-self-heal.md.
5
+ *
6
+ * Pure function: given the shape of a TokenLedger event (sessionId, cwd,
7
+ * prompt text, model) returns an attribution_key suitable for grouping
8
+ * "calls of the same structural origin." Used by the Phase 3 BurnDetector
9
+ * to populate attribution_key for events the Phase 1 chokepoint did NOT
10
+ * write directly — chiefly the dominant Claude-CLI path where the JSONL
11
+ * trail carries the prompt and cwd but no source-side label.
12
+ *
13
+ * Authority shape: this is signal-only. It does not gate, throttle, or
14
+ * decide anything. It maps event → key. The detector emits, the
15
+ * Remediator decides. See umbrella spec §"Signal-vs-Authority Decomposition".
16
+ *
17
+ * No I/O, no time-dependent behavior — deterministic for tests + reasoning.
18
+ */
19
+ import { buildAttributionKey } from './attributionKey.js';
20
+ import { ATTRIBUTION_MANIFEST } from './attribution-manifest.js';
21
+ /**
22
+ * Resolve an attribution_key for an event.
23
+ *
24
+ * Resolution order:
25
+ * 1. Manifest entry that matches the prompt (with optional cwd / model
26
+ * narrowing) → `<component>::<promptFingerprint>`.
27
+ * 2. cwd-based scheduled-job inference — if the cwd contains a path
28
+ * segment like `.instar/jobs/<name>`, return `user-job:<name>`.
29
+ * 3. cwd-based user-extension inference — if the cwd contains
30
+ * `.claude/hooks/` or `.instar/hooks/`, return the hook filename.
31
+ * 4. Fallback: `unknown::<sessionId-prefix>`.
32
+ *
33
+ * The prompt-based check is intentionally first: it's the most informative
34
+ * signal for the bleed-detection use case (one prompt shape running tens
35
+ * of thousands of times). cwd-based inference is the secondary signal for
36
+ * cases where the prompt is variable but the source is recognisable.
37
+ */
38
+ export function resolveAttribution(event) {
39
+ // 1. Manifest-based prompt match (with optional cwd/model narrowing).
40
+ if (event.prompt && event.prompt.length > 0) {
41
+ for (const entry of ATTRIBUTION_MANIFEST) {
42
+ if (matchesEntry(entry, event)) {
43
+ return buildAttributionKey(entry.component, event.prompt);
44
+ }
45
+ }
46
+ }
47
+ // 2. Scheduled-job inference: a path segment of the cwd is the job name.
48
+ // e.g. /Users/x/.instar/jobs/daily-summary → user-job:daily-summary
49
+ if (event.projectPath) {
50
+ const jobMatch = event.projectPath.match(/[/\\]\.instar[/\\]jobs[/\\]([^/\\]+)/);
51
+ if (jobMatch && jobMatch[1]) {
52
+ return `user-job:${jobMatch[1]}::${shortPromptFp(event.prompt)}`;
53
+ }
54
+ // 3. Hook / extension inference.
55
+ const hookMatch = event.projectPath.match(/[/\\](?:\.claude|\.instar)[/\\]hooks[/\\]([^/\\]+)/);
56
+ if (hookMatch && hookMatch[1]) {
57
+ return `user-hook:${hookMatch[1]}::${shortPromptFp(event.prompt)}`;
58
+ }
59
+ }
60
+ // 4. Fallback. Use a stable session-id prefix so a single misbehaving
61
+ // session shows as one key (and not exploded by per-prompt fingerprint).
62
+ if (!event.sessionId || event.sessionId.length === 0) {
63
+ return 'unknown::no-session';
64
+ }
65
+ const sidPrefix = event.sessionId.slice(0, 8);
66
+ return `unknown::${sidPrefix}`;
67
+ }
68
+ function matchesEntry(entry, event) {
69
+ // Prompt must match if patterns are defined (Phase 2 always defines them).
70
+ if (entry.promptPatterns && entry.promptPatterns.length > 0) {
71
+ if (!event.prompt)
72
+ return false;
73
+ const hit = entry.promptPatterns.some((re) => re.test(event.prompt));
74
+ if (!hit)
75
+ return false;
76
+ }
77
+ // Optional cwd narrowing.
78
+ if (entry.cwdPatterns && entry.cwdPatterns.length > 0) {
79
+ if (!event.projectPath)
80
+ return false;
81
+ const hit = entry.cwdPatterns.some((re) => re.test(event.projectPath));
82
+ if (!hit)
83
+ return false;
84
+ }
85
+ // Optional model narrowing.
86
+ if (entry.modelHints && entry.modelHints.length > 0) {
87
+ if (!event.model)
88
+ return false;
89
+ const hit = entry.modelHints.some((m) => event.model.includes(m));
90
+ if (!hit)
91
+ return false;
92
+ }
93
+ return true;
94
+ }
95
+ function shortPromptFp(prompt) {
96
+ if (!prompt || prompt.length === 0)
97
+ return 'nonprompt';
98
+ // Cheap deterministic fingerprint without importing crypto on every call.
99
+ // Phase 1's buildAttributionKey covers the cryptographic case; here we
100
+ // only need to disambiguate prompts at the user-job / user-hook level.
101
+ let h = 0;
102
+ const slice = prompt.slice(0, 128);
103
+ for (let i = 0; i < slice.length; i++)
104
+ h = ((h << 5) - h + slice.charCodeAt(i)) | 0;
105
+ return (h >>> 0).toString(16).padStart(8, '0').slice(0, 8);
106
+ }
107
+ //# sourceMappingURL=AttributionResolver.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"AttributionResolver.js","sourceRoot":"","sources":["../../src/monitoring/AttributionResolver.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,39 @@
1
+ /**
2
+ * Static attribution manifest for the burn-detection-and-self-heal system.
3
+ *
4
+ * Phase 2 of docs/specs/token-burn-detection-and-self-heal.md. Maps known
5
+ * instar-internal LLM call patterns to stable component names so the
6
+ * BurnDetector (Phase 3) can group calls of the same shape.
7
+ *
8
+ * Adding entries does not require a spec change — they are inference rules
9
+ * for an observation system, not authority. The manifest is a hint store,
10
+ * not a gate.
11
+ *
12
+ * Pattern semantics (per docs/specs/token-burn-detection-and-self-heal.md
13
+ * §"Attribution key", §"Capture surface"):
14
+ * - `promptPatterns`: regex on the user prompt that prompted the
15
+ * assistant response. First-match wins. Order matters — list more
16
+ * specific patterns first.
17
+ * - `cwdPatterns`: optional regex on the `cwd` field of the JSONL line.
18
+ * Useful when a component is recognisable by its working directory
19
+ * but its prompt varies.
20
+ * - `modelHints`: optional list of model substrings; narrows the match
21
+ * when the same prompt could come from multiple components but only
22
+ * one of them uses a specific model.
23
+ */
24
+ export interface AttributionPattern {
25
+ /** Stable component name written into attribution_key. */
26
+ component: string;
27
+ /** Regex matched against the user prompt. */
28
+ promptPatterns?: RegExp[];
29
+ /** Regex matched against the cwd / projectPath field. */
30
+ cwdPatterns?: RegExp[];
31
+ /** Substrings narrowing the match to specific models. */
32
+ modelHints?: string[];
33
+ }
34
+ /**
35
+ * The manifest. Order is significant — first-match wins. Add more specific
36
+ * entries before broader ones.
37
+ */
38
+ export declare const ATTRIBUTION_MANIFEST: AttributionPattern[];
39
+ //# sourceMappingURL=attribution-manifest.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"attribution-manifest.d.ts","sourceRoot":"","sources":["../../src/monitoring/attribution-manifest.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;;;GAsBG;AAEH,MAAM,WAAW,kBAAkB;IACjC,0DAA0D;IAC1D,SAAS,EAAE,MAAM,CAAC;IAClB,6CAA6C;IAC7C,cAAc,CAAC,EAAE,MAAM,EAAE,CAAC;IAC1B,yDAAyD;IACzD,WAAW,CAAC,EAAE,MAAM,EAAE,CAAC;IACvB,yDAAyD;IACzD,UAAU,CAAC,EAAE,MAAM,EAAE,CAAC;CACvB;AAED;;;GAGG;AACH,eAAO,MAAM,oBAAoB,EAAE,kBAAkB,EAsDpD,CAAC"}
@@ -0,0 +1,83 @@
1
+ /**
2
+ * Static attribution manifest for the burn-detection-and-self-heal system.
3
+ *
4
+ * Phase 2 of docs/specs/token-burn-detection-and-self-heal.md. Maps known
5
+ * instar-internal LLM call patterns to stable component names so the
6
+ * BurnDetector (Phase 3) can group calls of the same shape.
7
+ *
8
+ * Adding entries does not require a spec change — they are inference rules
9
+ * for an observation system, not authority. The manifest is a hint store,
10
+ * not a gate.
11
+ *
12
+ * Pattern semantics (per docs/specs/token-burn-detection-and-self-heal.md
13
+ * §"Attribution key", §"Capture surface"):
14
+ * - `promptPatterns`: regex on the user prompt that prompted the
15
+ * assistant response. First-match wins. Order matters — list more
16
+ * specific patterns first.
17
+ * - `cwdPatterns`: optional regex on the `cwd` field of the JSONL line.
18
+ * Useful when a component is recognisable by its working directory
19
+ * but its prompt varies.
20
+ * - `modelHints`: optional list of model substrings; narrows the match
21
+ * when the same prompt could come from multiple components but only
22
+ * one of them uses a specific model.
23
+ */
24
+ /**
25
+ * The manifest. Order is significant — first-match wins. Add more specific
26
+ * entries before broader ones.
27
+ */
28
+ export const ATTRIBUTION_MANIFEST = [
29
+ // The 2026-05-15 bleed: the InputDetector's NO_PROMPT classifier asked
30
+ // the LLM "is this stuck?" every 5s on every idle session, burning
31
+ // ~3B tokens/day. This pattern catches that exact prompt shape.
32
+ {
33
+ component: 'InputDetector',
34
+ promptPatterns: [/analyzing terminal output/i, /is this stuck/i, /stalled session detection/i],
35
+ },
36
+ // MessagingToneGate evaluates outbound user-facing messages for tone +
37
+ // banned-content compliance (ELI16, no inline code, etc).
38
+ {
39
+ component: 'MessagingToneGate',
40
+ promptPatterns: [/evaluate this outbound message/i, /tone gate/i, /eli16/i],
41
+ },
42
+ // CommitmentSentinel watches for commitments the agent made that lack
43
+ // follow-through.
44
+ {
45
+ component: 'CommitmentSentinel',
46
+ promptPatterns: [/commitment.*follow.through/i, /unfulfilled commitment/i],
47
+ },
48
+ // MessageSentinel classifies inbound messages (emergency stop, etc).
49
+ {
50
+ component: 'MessageSentinel',
51
+ promptPatterns: [/classify.*inbound message/i, /emergency stop classifier/i],
52
+ },
53
+ // StallTriageNurse — the LLM-powered session-recovery classifier.
54
+ {
55
+ component: 'StallTriageNurse',
56
+ promptPatterns: [/triage.*stalled session/i, /session.*stall.*classifier/i],
57
+ },
58
+ // CoherenceReviewer — the deeper "is this agent acting coherently"
59
+ // check, invoked by the coherence-gate path.
60
+ {
61
+ component: 'CoherenceReviewer',
62
+ promptPatterns: [/coherence review/i, /agent coherence/i],
63
+ },
64
+ // ProjectDriftChecker — round-start signal that the project context
65
+ // has drifted from what was loaded.
66
+ {
67
+ component: 'ProjectDriftChecker',
68
+ promptPatterns: [/project drift/i, /context drift detection/i],
69
+ },
70
+ // ResumeValidator — verifies a Claude Code resume payload before
71
+ // letting a session pick back up.
72
+ {
73
+ component: 'ResumeValidator',
74
+ promptPatterns: [/validate.*resume payload/i, /resume validation/i],
75
+ },
76
+ // TopicLinkageHandler — figures out which existing thread a new
77
+ // Telegram message belongs to.
78
+ {
79
+ component: 'TopicLinkageHandler',
80
+ promptPatterns: [/topic linkage/i, /thread linking/i],
81
+ },
82
+ ];
83
+ //# sourceMappingURL=attribution-manifest.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"attribution-manifest.js","sourceRoot":"","sources":["../../src/monitoring/attribution-manifest.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;;;GAsBG;AAaH;;;GAGG;AACH,MAAM,CAAC,MAAM,oBAAoB,GAAyB;IACxD,uEAAuE;IACvE,mEAAmE;IACnE,gEAAgE;IAChE;QACE,SAAS,EAAE,eAAe;QAC1B,cAAc,EAAE,CAAC,4BAA4B,EAAE,gBAAgB,EAAE,4BAA4B,CAAC;KAC/F;IACD,uEAAuE;IACvE,0DAA0D;IAC1D;QACE,SAAS,EAAE,mBAAmB;QAC9B,cAAc,EAAE,CAAC,iCAAiC,EAAE,YAAY,EAAE,QAAQ,CAAC;KAC5E;IACD,sEAAsE;IACtE,kBAAkB;IAClB;QACE,SAAS,EAAE,oBAAoB;QAC/B,cAAc,EAAE,CAAC,6BAA6B,EAAE,yBAAyB,CAAC;KAC3E;IACD,qEAAqE;IACrE;QACE,SAAS,EAAE,iBAAiB;QAC5B,cAAc,EAAE,CAAC,4BAA4B,EAAE,4BAA4B,CAAC;KAC7E;IACD,kEAAkE;IAClE;QACE,SAAS,EAAE,kBAAkB;QAC7B,cAAc,EAAE,CAAC,0BAA0B,EAAE,6BAA6B,CAAC;KAC5E;IACD,mEAAmE;IACnE,6CAA6C;IAC7C;QACE,SAAS,EAAE,mBAAmB;QAC9B,cAAc,EAAE,CAAC,mBAAmB,EAAE,kBAAkB,CAAC;KAC1D;IACD,oEAAoE;IACpE,oCAAoC;IACpC;QACE,SAAS,EAAE,qBAAqB;QAChC,cAAc,EAAE,CAAC,gBAAgB,EAAE,0BAA0B,CAAC;KAC/D;IACD,iEAAiE;IACjE,kCAAkC;IAClC;QACE,SAAS,EAAE,iBAAiB;QAC5B,cAAc,EAAE,CAAC,2BAA2B,EAAE,oBAAoB,CAAC;KACpE;IACD,gEAAgE;IAChE,+BAA+B;IAC/B;QACE,SAAS,EAAE,qBAAqB;QAChC,cAAc,EAAE,CAAC,gBAAgB,EAAE,iBAAiB,CAAC;KACtD;CACF,CAAC"}
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "instar",
3
- "version": "0.28.106",
3
+ "version": "0.28.107",
4
4
  "description": "Persistent autonomy infrastructure for AI agents",
5
5
  "type": "module",
6
6
  "main": "dist/index.js",
@@ -1,8 +1,8 @@
1
1
  {
2
2
  "$schema": "./builtin-manifest.schema.json",
3
3
  "schemaVersion": 1,
4
- "generatedAt": "2026-05-15T21:25:05.645Z",
5
- "instarVersion": "0.28.106",
4
+ "generatedAt": "2026-05-15T21:38:45.342Z",
5
+ "instarVersion": "0.28.107",
6
6
  "entryCount": 188,
7
7
  "entries": {
8
8
  "hook:session-start": {
@@ -0,0 +1,35 @@
1
+ # Upgrade Guide — vNEXT
2
+
3
+ <!-- bump: patch -->
4
+
5
+ ## What Changed
6
+
7
+ Phase two of the token-burn-detection-and-self-heal system. Still observation-only — no alerts, no auto-throttling, no new dashboard. This phase adds the piece that figures out which component made each LLM call after the fact.
8
+
9
+ What lands today:
10
+
11
+ - A short list of patterns that match the prompt shapes the agent's internal components produce.
12
+ - A pure function that takes a token-ledger event and returns a stable attribution identifier.
13
+
14
+ The detector in phase three will use this function to group calls by where they came from. Nothing in production calls the new function yet.
15
+
16
+ ## What to Tell Your User
17
+
18
+ Your agent picked up the second of six pieces of the new self-watch system. Like the first piece, nothing changes about how your agent behaves today. The watcher you approved is being built in stages so each piece can be reviewed on its own.
19
+
20
+ For now, no action needed. The third piece is the one that will start actually noticing things.
21
+
22
+ ## Summary of New Capabilities
23
+
24
+ | Capability | How to Use |
25
+ |-----------|-----------|
26
+ | Read-side attribution resolver | Internal — no surface yet. |
27
+ | Static attribution manifest | Internal — covers nine known components. |
28
+
29
+ ## Evidence
30
+
31
+ Twenty-two new tests in `tests/unit/burn-detection-phase-2.test.ts` all pass. The resolver is a pure function with no I/O and no dependency on time, so the test suite is deterministic. Manifest integrity tests cover uniqueness of component names, non-empty entries, and at-least-one-matcher per entry.
32
+
33
+ The existing token-ledger and selectIntelligenceProvider unit suites still pass — no regression on the parts not touched by this phase.
34
+
35
+ Side-effects review for this phase is in `upgrades/side-effects/token-burn-detection-phase-2.md`. The reviewer identified zero blocking concerns; phase two ships pure inference with no runtime decision authority, so second-pass review is not required per the instar-dev skill criteria.
@@ -0,0 +1,44 @@
1
+ # Side-Effects Review — Token-Burn Detection Phase 2
2
+
3
+ **Spec**: `docs/specs/token-burn-detection-phase-2.md` (parent: `docs/specs/token-burn-detection-and-self-heal.md`, approved by Justin 2026-05-15).
4
+
5
+ ## 1. Over-block
6
+
7
+ Phase 2 cannot block anything — it's a pure function with no caller in production yet. Worst case "over-block" is a wrong attribution: a prompt that should have been labeled `InputDetector` ends up under `unknown::<sessionPrefix>`. Phase 3's detector treats unknown-keyed spend as alert-only-on-unknown (per umbrella §"Auto-throttle mechanism"), so even a wrong attribution still produces a usable alert — just less informative.
8
+
9
+ ## 2. Under-block
10
+
11
+ The pattern manifest covers nine known instar-internal components. New components added in unrelated PRs do not appear in the manifest until someone adds them. They fall through to `unknown::<sessionPrefix>` and are still observable — just not labeled by name. Adding manifest entries is the right discipline going forward; the lint from Phase 1 catches new direct-LLM-HTTP callers, but it does not catch new components calling through the chokepoint without a manifest entry. This is a known and accepted gap.
12
+
13
+ ## 3. Level-of-abstraction fit
14
+
15
+ `AttributionResolver` and the manifest sit in `src/monitoring/`, next to `TokenLedger` and `LlmRateGate`. Correct layer: it's part of the observability surface, not a piece of the core LLM-call path or a decision-maker.
16
+
17
+ The resolver is a pure function — no I/O, no time-dependent behavior. That's the right abstraction; Phase 3's read path can call it in a tight loop without worrying about side effects.
18
+
19
+ ## 4. Signal-vs-authority compliance
20
+
21
+ The resolver is signal-only. It produces an attribution key; it does not decide whether anything happens. The umbrella spec's §"Signal-vs-Authority Decomposition" places AttributionResolver in the "no authority" row, and Phase 2 matches that placement.
22
+
23
+ **Compliant.**
24
+
25
+ ## 5. Interactions
26
+
27
+ - **TokenLedger.** No interaction in Phase 2 — the resolver does not read or write the ledger. Phase 3 will pair them.
28
+ - **LlmRateGate.** No interaction. The gate enforces decisions; the resolver produces keys those decisions reference.
29
+ - **AnthropicIntelligenceProvider chokepoint path.** No interaction — when the chokepoint writes attribution_key, Phase 3's read path passes it through unchanged and skips the resolver call.
30
+ - **Other manifests.** No other manifest in the tree has overlapping responsibility; this is a new file.
31
+
32
+ No shadowing, no double-fire, no race.
33
+
34
+ ## 6. External surfaces
35
+
36
+ No external surface change. Phase 2 is internal pure code with no callers in production.
37
+
38
+ ## 7. Rollback cost
39
+
40
+ Three new files (`AttributionResolver.ts`, `attribution-manifest.ts`, test). Backout = delete the three files. No persistent state, no schema change, no caller dependency until Phase 3.
41
+
42
+ ## Second-pass review
43
+
44
+ Phase 2 ships pure observability inference with no runtime decision authority. It does NOT touch any of the high-risk surfaces listed in `/instar-dev` Phase 5 (no block/allow, no session lifecycle, no coherence gate, no sentinel/guard/gate/watchdog with authority). Second-pass review is **not required** per the skill's criteria.