instar 1.3.1002 → 1.3.1004

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,77 @@
1
+ # Side-effects review — WhatsApp + iMessage join the channel registry
2
+
3
+ **Change:** `buildUserChannelDefinitions` gains `user-whatsapp` and `user-imessage` rows, with
4
+ exported `whatsappStateFrom` / `imessageStateFrom` mappers and route wiring from
5
+ `ctx.whatsapp.getStatus().state` and `ctx.imessage.getConnectionInfo().state`.
6
+
7
+ **Decision point touched?** No new gate. This is additive read-only observability on an existing
8
+ `advisory: true` route. It does change what a caller CONCLUDES about reachability, which is why the
9
+ verdict mapping is the whole of this review.
10
+
11
+ ---
12
+
13
+ ## 1. Over-block
14
+
15
+ Nothing is blocked or rejected — the route is advisory and gates nothing. The over-claim risk runs the
16
+ other way and is handled: `qr-pending` is reported as `reachable-no-credential` rather than `broken`,
17
+ because the link is alive and needs a HUMAN to scan a code. Reporting it as broken would send an
18
+ operator to debug a connection behaving exactly as designed.
19
+
20
+ ## 2. Under-block
21
+
22
+ The honest limit, stated in both rows' own text rather than left to assumption: `working` means the
23
+ link was up when probed. It does NOT prove a send to a particular chat or contact would land. Same
24
+ caveat the Telegram and mutual-ssh rows already carry.
25
+
26
+ Unrecognised states from either adapter map to `unknown`, never to `working`. That is the failure
27
+ direction that matters — a state this module has not seen must not read as healthy — and it is
28
+ pinned by a test.
29
+
30
+ Not addressed: neither row probes a round-trip. A true reachability proof would require sending, which
31
+ a status read must not do.
32
+
33
+ ## 3. Level-of-abstraction fit
34
+
35
+ Correct, and it follows the pattern already established for Telegram and Slack: the STATE→VERDICT
36
+ mapping is an exported pure function testable without constructing an adapter, and the route supplies
37
+ live state through a narrow context. The mapping is where a wrong verdict would come from, so it is
38
+ the part that is pinned.
39
+
40
+ ## 4. Signal vs authority compliance
41
+
42
+ Compliant. Pure signal on an advisory route with no blocking power. Adding rows strengthens the
43
+ registry's "absence is impossible" property — the invariant that a channel with no row cannot report
44
+ that it is missing.
45
+
46
+ ## 5. Interactions
47
+
48
+ `UserChannelProbeContext` gains two required fields, so any other constructor of it must supply them
49
+ — there is exactly one (the `/channels` route), updated here. The `/channels` payload grows from 6
50
+ rows to 8; the integration test that pins the exact set and the audience partition was updated in
51
+ this change rather than left for CI to catch.
52
+
53
+ `WhatsAppLiveState` mirrors the adapter's own union. If the adapter adds a state, the mapper reports
54
+ `unknown` rather than mis-classifying — a deliberate fail-safe, not an oversight.
55
+
56
+ ## 6. External surfaces
57
+
58
+ `GET /channels` returns two additional rows. Additive; existing consumers reading known ids are
59
+ unaffected. No endpoint added, no config key, no behaviour change to messaging itself.
60
+
61
+ ## 7. Multi-machine posture
62
+
63
+ **Machine-local by design for iMessage**, and this is a real property rather than a shortcut: the
64
+ backend it talks to runs on this host, so the channel genuinely exists only where that backend is.
65
+ That is recorded in the row's own `cost` text so a caller choosing it knows the work will not survive
66
+ this machine going away.
67
+
68
+ WhatsApp is pairing-bound to the operator's phone through whichever host holds the session — the same
69
+ locality. Neither introduces replicated state; both are per-host reads of a per-host adapter, and a
70
+ cross-machine merged view would be actively misleading since another machine's link says nothing
71
+ about this one's.
72
+
73
+ ## 8. Rollback cost
74
+
75
+ Trivial: remove the two rows, the two mappers, the two context fields and the route wiring, and
76
+ restore the integration test's expected set. No persisted state, no schema, no migration. Rolling back
77
+ re-opens the stated gap, so it should carry a reason.
@@ -0,0 +1,74 @@
1
+ # Side-effects review — spec-converge terminates on design-class findings
2
+
3
+ **Change:** `/spec-converge`'s first convergence criterion changes from "no MATERIAL new issues"
4
+ (material = anything requiring a spec change) to "no DESIGN-class findings for TWO consecutive
5
+ rounds", with an explicit design/precision taxonomy that reviewers DECLARE per finding. The report
6
+ template records both counts per round.
7
+
8
+ **Decision point touched?** Yes, and it is the whole review: this is the stop criterion of the gate
9
+ that decides whether a spec may claim convergence — the tag `/instar-dev` requires before touching
10
+ instar source.
11
+
12
+ ---
13
+
14
+ ## 1. Over-block
15
+
16
+ Reduced, deliberately, and that is the point. The prior criterion over-blocked absolutely: on a spec
17
+ that appends its own review history the surface grows each round, a reviewer always finds precision
18
+ to add, and every such finding counted as material — so the loop could not terminate BY CONSTRUCTION.
19
+ Two specs hit the 10-round cap for reasons unrelated to design soundness.
20
+
21
+ ## 2. Under-block
22
+
23
+ The real risk, stated plainly: **loosening what counts as terminating could let a spec converge with
24
+ an unaddressed design defect misfiled as precision.**
25
+
26
+ Three things bound it, none of which is "the reviewer will be careful":
27
+ - The taxonomy names the dangerous case EXPLICITLY — a statement that is factually WRONG about the
28
+ system is design-class, never precision. That case is not hypothetical: round 10 of
29
+ `standards-registry-ships-with-code` caught a false rollback claim, and under a careless taxonomy
30
+ that would have been filed as wording.
31
+ - TWO consecutive quiet rounds, not one. A single quiet round is weak evidence on a growing surface.
32
+ - The class is DECLARED by the reviewer that raised the finding and the comparator consumes the
33
+ declaration rather than re-deriving it from wording — so a misclassification is an explicit act
34
+ recorded in the report, not an inference nobody can see.
35
+
36
+ Residual and unfixed: a reviewer that systematically under-classifies still ends the loop early. This
37
+ trades one judgment for a better-specified one; it does not eliminate judgment. Per-round counts in
38
+ the report are the detection surface, not a guarantee.
39
+
40
+ ## 3. Level-of-abstraction fit
41
+
42
+ Correct. The defect is in the stop criterion's DEFINITION, which lives in the skill's prose and is
43
+ applied by the comparator, so the fix belongs in the prose plus the report template that makes it
44
+ auditable. No code enforces the classification today and none is added — an important honesty: this
45
+ is an instruction change, so it binds only as well as the reviewers follow it.
46
+
47
+ ## 4. Signal vs authority compliance
48
+
49
+ The comparator retains exactly the authority it had (emit `converged: true|false`). What changes is
50
+ the definition it applies and the requirement that it consume a DECLARED class rather than infer one
51
+ — moving a judgment from implicit to explicit. No new blocking power anywhere.
52
+
53
+ ## 5. Interactions
54
+
55
+ `write-convergence-tag.mjs` is untouched: criterion 2 (zero unresolved `## Open questions`) is still
56
+ enforced structurally there, so the STRUCTURAL half of convergence is unchanged and this change
57
+ cannot weaken it. The report template's Iteration Summary gains a column (design/precision split);
58
+ existing reports remain readable, and future ones carry the counts the new criterion depends on.
59
+
60
+ ## 6. External surfaces
61
+
62
+ None. `/spec-converge` is an instar-development skill, not user-facing, not an endpoint, no config
63
+ key. The observable effect is that specs which would previously have hit the cap can now converge on
64
+ their merits — and that convergence reports show two counts where they showed one.
65
+
66
+ ## 7. Multi-machine posture
67
+
68
+ Not applicable. This is repo-level skill prose plus a report template, identical on every checkout,
69
+ with no runtime state, no persistence, and nothing to replicate, proxy, or reconcile.
70
+
71
+ ## 8. Rollback cost
72
+
73
+ Trivial: restore the previous criterion paragraph and the template's original column. No state, no
74
+ migration, no code. A rollback re-creates the unterminating loop, so it should carry a reason.
@@ -0,0 +1,72 @@
1
+ # Side-effects review — tier classifier no longer treats a .config FILENAME as a config surface
2
+
3
+ **Change:** removes the `\.config\b` alternative from `CONFIG_SURFACE_HINT` in
4
+ `scripts/lib/classify-tier.mjs`. That alternative matched a filename REFERENCE, so a diff that merely
5
+ read `*.config.ts` satisfied the config-surface gate and, combined with any object literal, raised the
6
+ risk floor for "new config key added".
7
+
8
+ **Decision point touched?** Yes — the risk floor of the instar-dev tier gate. This LOWERS the floor in
9
+ one specific false-positive case, so it is a loosening and reviewed as such.
10
+
11
+ ---
12
+
13
+ ## 1. Over-block
14
+
15
+ This change exists to remove one. The over-block was concrete: a read-only developer script that adds
16
+ no config key had its floor raised to 2 purely for naming `vitest.push.config.ts`.
17
+
18
+ ## 2. Under-block
19
+
20
+ The real risk of the change, stated plainly: narrowing a heuristic can blind it. If a genuine
21
+ config-key addition mentions ONLY a `*.config.ts` filename and none of the remaining anchors
22
+ (`ConfigDefaults`, `config.json`, `defaultConfig`, `InstarConfig`, `configSchema`), its floor will no
23
+ longer rise.
24
+
25
+ Bounded two ways. The remaining anchors cover the actual config surfaces in this repo — a diff adding
26
+ a real key names the module, the file, or the type. And a test now iterates EVERY remaining anchor and
27
+ asserts the floor still rises, so a future narrowing that blinds the check fails.
28
+
29
+ Residual: this is a heuristic over diff text and always was. It deters accidental omission; it is not
30
+ a boundary against a determined author. Unchanged by this.
31
+
32
+ ## 3. Level-of-abstraction fit
33
+
34
+ Correct — the defect is in the hint regex and the fix is in the hint regex. A broader alternative
35
+ (requiring the anchor on the SAME line as the key) was considered and rejected as a larger behavioural
36
+ change than the evidence supports: one bad alternative was identified precisely, so one alternative is
37
+ removed.
38
+
39
+ ## 4. Signal vs authority compliance
40
+
41
+ The classifier is a SIGNAL that informs a declared tier; the agent holds the authority and the
42
+ declaration is audited. This change makes the signal more accurate without altering who decides. Per
43
+ `docs/signal-vs-authority.md` that is the intended direction.
44
+
45
+ ## 5. Interactions
46
+
47
+ `CONFIG_SURFACE_HINT` is used only to gate the `key: value` pattern inside the new-capability check.
48
+ No other risk signal is affected; the `export class` and router patterns are untouched. All 47
49
+ pre-existing classifier tests pass unchanged, plus 2 new ones.
50
+
51
+ Changes to this file alter tier decisions for FUTURE commits only. Nothing recorded in past decision
52
+ audits is rewritten.
53
+
54
+ ## 6. External surfaces
55
+
56
+ None. Development-time classifier; no endpoint, no config key, no runtime behaviour, not user-facing.
57
+
58
+ ## 7. Multi-machine posture
59
+
60
+ Not applicable: a pure function over diff text, identical on every checkout, with no state, no
61
+ persistence, and nothing to replicate or reconcile.
62
+
63
+ ## 8. Rollback cost
64
+
65
+ Trivial — restore the alternative. The regression test would then fail, which is the correct signal
66
+ that the rollback reintroduces the false positive rather than a silent revert.
67
+
68
+ ## Disclosure
69
+
70
+ I hit this false positive myself and declared Tier 1 under the raised floor without reading it first.
71
+ That declaration and its deliberate re-declaration are both in the decision audit. This change fixes
72
+ the classifier; it does not excuse the declaration.