@bompus/house-rules 0.0.0-stage → 0.11.0
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/CONTRIBUTING.md +54 -0
- package/LICENSE +21 -0
- package/README.md +347 -2
- package/THIRD_PARTY_NOTICES.md +188 -0
- package/compose.mjs +119 -0
- package/composition.mjs +353 -0
- package/config-view.mjs +194 -0
- package/config.mjs +320 -0
- package/docs/assets/banner-dark.png +0 -0
- package/docs/assets/banner-light.png +0 -0
- package/docs/assets/overview.png +0 -0
- package/docs/configuration.md +193 -0
- package/docs/npm-release.md +45 -0
- package/docs/skill-names.md +50 -0
- package/examples/person/house-rules.json +15 -0
- package/examples/person/rules/10-tooling.md +8 -0
- package/examples/person/rules/20-reporting.md +9 -0
- package/examples/project/AGENTS.md +18 -0
- package/package.json +40 -4
- package/rule-references.mjs +91 -0
- package/rules/core.md +431 -0
- package/rules/modifiers/coded-offers.md +40 -0
- package/rules/modifiers/effort-estimates.md +41 -0
- package/rules/modifiers/land-when-done.md +12 -0
- package/rules/modifiers/low-quota-handoff.md +19 -0
- package/rules/modifiers/multi-agent.md +34 -0
- package/rules/modifiers/no-attribution.md +10 -0
- package/rules/modifiers/plan-files.md +50 -0
- package/rules/modifiers/question-cards.md +48 -0
- package/rules/modifiers/release-batching.md +13 -0
- package/rules/modifiers/scratch-on-disk.md +15 -0
- package/rules/modifiers/shared-host-load.md +48 -0
- package/rules/modifiers/solo-operator.md +13 -0
- package/rules/modifiers/squash-landing.md +22 -0
- package/rules/modifiers/swarmail.md +12 -0
- package/rules/references/github-actions.md +45 -0
- package/rules/references/landing.md +39 -0
- package/rules/references/multi-agent.md +47 -0
- package/rules/references/release-batching.md +43 -0
- package/rules/references/squash-landing.md +44 -0
- package/setup.mjs +375 -0
- package/skills/hr-agent-guidance-audit/LICENSE +21 -0
- package/skills/hr-agent-guidance-audit/SKILL.md +86 -0
- package/skills/hr-agent-guidance-audit/agents/openai.yaml +2 -0
- package/skills/hr-agent-guidance-audit/references/records-and-lessons.md +60 -0
- package/skills/hr-agent-guidance-refresh/LICENSE +21 -0
- package/skills/hr-agent-guidance-refresh/SKILL.md +68 -0
- package/skills/hr-agent-guidance-refresh/agents/openai.yaml +2 -0
- package/skills/hr-agent-guidance-refresh/references/verification.md +47 -0
- package/skills/hr-api-exposure-check/SKILL.md +159 -0
- package/skills/hr-api-exposure-check/agents/openai.yaml +3 -0
- package/skills/hr-audit-choices/SKILL.md +67 -0
- package/skills/hr-audit-choices/agents/openai.yaml +2 -0
- package/skills/hr-benchmarking/NOTICE.md +36 -0
- package/skills/hr-benchmarking/SKILL.md +316 -0
- package/skills/hr-benchmarking/agents/openai.yaml +2 -0
- package/skills/hr-benchmarking/references/javascript.md +17 -0
- package/skills/hr-benchmarking/references/priority-findings-20261006.md +115 -0
- package/skills/hr-benchmarking/references/tools.md +160 -0
- package/skills/hr-benchmarking/scripts/process-attribution.ps1 +20 -0
- package/skills/hr-benchmarking/scripts/process-attribution.py +107 -0
- package/skills/hr-better-accessibility/LICENSE +22 -0
- package/skills/hr-better-accessibility/NOTICE.md +46 -0
- package/skills/hr-better-accessibility/SKILL.md +119 -0
- package/skills/hr-better-accessibility/agents/openai.yaml +3 -0
- package/skills/hr-better-accessibility/focus-and-keyboard.md +130 -0
- package/skills/hr-better-accessibility/forms.md +82 -0
- package/skills/hr-better-accessibility/hit-areas.md +98 -0
- package/skills/hr-better-accessibility/motion-and-zoom.md +81 -0
- package/skills/hr-better-accessibility/screen-readers.md +101 -0
- package/skills/hr-better-accessibility/semantics-and-aria.md +84 -0
- package/skills/hr-better-colors/LICENSE +21 -0
- package/skills/hr-better-colors/NOTICE.md +37 -0
- package/skills/hr-better-colors/SKILL.md +114 -0
- package/skills/hr-better-colors/agents/openai.yaml +3 -0
- package/skills/hr-better-colors/color-formats.md +90 -0
- package/skills/hr-better-colors/color-usage.md +140 -0
- package/skills/hr-better-colors/contrast.md +80 -0
- package/skills/hr-better-colors/palette-generation.md +104 -0
- package/skills/hr-better-colors/palette-structure.md +76 -0
- package/skills/hr-better-colors/token-naming.md +97 -0
- package/skills/hr-better-layout/LICENSE +22 -0
- package/skills/hr-better-layout/NOTICE.md +48 -0
- package/skills/hr-better-layout/SKILL.md +92 -0
- package/skills/hr-better-layout/agents/openai.yaml +3 -0
- package/skills/hr-better-layout/grouping-and-alignment.md +144 -0
- package/skills/hr-better-layout/spacing-and-adaptivity.md +215 -0
- package/skills/hr-better-typography/LICENSE +22 -0
- package/skills/hr-better-typography/NOTICE.md +46 -0
- package/skills/hr-better-typography/SKILL.md +172 -0
- package/skills/hr-better-typography/agents/openai.yaml +3 -0
- package/skills/hr-better-typography/choosing-fonts.md +69 -0
- package/skills/hr-better-typography/css-cheat-sheet.md +65 -0
- package/skills/hr-better-typography/details-and-accessibility.md +119 -0
- package/skills/hr-better-typography/spacing-and-sizing.md +131 -0
- package/skills/hr-better-typography/variable-fonts-and-opentype.md +105 -0
- package/skills/hr-better-typography/wrapping-and-punctuation.md +57 -0
- package/skills/hr-better-writing/LICENSE +22 -0
- package/skills/hr-better-writing/NOTICE.md +46 -0
- package/skills/hr-better-writing/SKILL.md +122 -0
- package/skills/hr-better-writing/agents/openai.yaml +3 -0
- package/skills/hr-change-impact/SKILL.md +113 -0
- package/skills/hr-change-impact/agents/openai.yaml +5 -0
- package/skills/hr-code-review/LICENSE +21 -0
- package/skills/hr-code-review/NOTICE.md +26 -0
- package/skills/hr-code-review/SKILL.md +147 -0
- package/skills/hr-code-review/agents/openai.yaml +3 -0
- package/skills/hr-code-review/references/evidence.md +57 -0
- package/skills/hr-design-exploration/SKILL.md +82 -0
- package/skills/hr-design-exploration/agents/openai.yaml +4 -0
- package/skills/hr-diagnosing-bugs/NOTICE.md +45 -0
- package/skills/hr-diagnosing-bugs/SKILL.md +108 -0
- package/skills/hr-diagnosing-bugs/agents/openai.yaml +3 -0
- package/skills/hr-diagnosing-bugs/references/reporting.md +72 -0
- package/skills/hr-explain-code/NOTICE.md +37 -0
- package/skills/hr-explain-code/SKILL.md +110 -0
- package/skills/hr-explain-code/agents/openai.yaml +5 -0
- package/skills/hr-explain-code/references/helper-brief.md +39 -0
- package/skills/hr-extract-shared-steps/SKILL.md +134 -0
- package/skills/hr-extract-shared-steps/agents/openai.yaml +3 -0
- package/skills/hr-handoff/SKILL.md +91 -0
- package/skills/hr-handoff/agents/openai.yaml +5 -0
- package/skills/hr-handoff/assets/ledger.example.json +10 -0
- package/skills/hr-handoff/assets/receipt.example.json +76 -0
- package/skills/hr-handoff/assets/source.example.json +20 -0
- package/skills/hr-handoff/references/reconciliation.md +105 -0
- package/skills/hr-handoff/scripts/check-reconciliation.mjs +282 -0
- package/skills/hr-house-rules-setup/SKILL.md +100 -0
- package/skills/hr-house-rules-setup/agents/openai.yaml +5 -0
- package/skills/hr-issue-tracker-setup/SKILL.md +49 -0
- package/skills/hr-issue-tracker-setup/agents/openai.yaml +5 -0
- package/skills/hr-lean-plan/SKILL.md +142 -0
- package/skills/hr-lean-plan/agents/openai.yaml +5 -0
- package/skills/hr-maintainability-review/SKILL.md +176 -0
- package/skills/hr-maintainability-review/agents/openai.yaml +5 -0
- package/skills/hr-manual-qa/NOTICE.md +36 -0
- package/skills/hr-manual-qa/SKILL.md +37 -0
- package/skills/hr-manual-qa/agents/openai.yaml +3 -0
- package/skills/hr-navigation-retro/LICENSE +21 -0
- package/skills/hr-navigation-retro/NOTICE.md +5 -0
- package/skills/hr-navigation-retro/SKILL.md +86 -0
- package/skills/hr-navigation-retro/agents/openai.yaml +4 -0
- package/skills/hr-navigation-retro/references/inputs.md +67 -0
- package/skills/hr-navigation-retro/scripts/retro.py +552 -0
- package/skills/hr-navigation-retro/scripts/transcripts.py +205 -0
- package/skills/hr-ordering-tests/SKILL.md +51 -0
- package/skills/hr-ordering-tests/agents/openai.yaml +2 -0
- package/skills/hr-plain-prose/SKILL.md +261 -0
- package/skills/hr-plain-prose/agents/openai.yaml +3 -0
- package/skills/hr-plain-prose/scripts/check.mjs +331 -0
- package/skills/hr-pr-followup/LICENSE +21 -0
- package/skills/hr-pr-followup/NOTICE.md +9 -0
- package/skills/hr-pr-followup/SKILL.md +71 -0
- package/skills/hr-pr-followup/agents/openai.yaml +2 -0
- package/skills/hr-pr-followup/references/review-helpers.md +90 -0
- package/skills/hr-pr-followup/scripts/check-pr-review.ts +510 -0
- package/skills/hr-pr-followup/scripts/resolve-pr-thread.ts +219 -0
- package/skills/hr-progress-report/SKILL.md +49 -0
- package/skills/hr-progress-report/agents/openai.yaml +5 -0
- package/skills/hr-read-reddit/SKILL.md +44 -0
- package/skills/hr-read-reddit/agents/openai.yaml +2 -0
- package/skills/hr-read-reddit/scripts/reddit.ts +252 -0
- package/skills/hr-read-x-links/SKILL.md +42 -0
- package/skills/hr-read-x-links/agents/openai.yaml +2 -0
- package/skills/hr-read-x-links/scripts/x-post.ts +264 -0
- package/skills/hr-split-to-prs/LICENSE +21 -0
- package/skills/hr-split-to-prs/NOTICE.md +9 -0
- package/skills/hr-split-to-prs/SKILL.md +61 -0
- package/skills/hr-split-to-prs/agents/openai.yaml +2 -0
- package/skills/hr-stock-ui-audit/SKILL.md +132 -0
- package/skills/hr-stock-ui-audit/agents/openai.yaml +3 -0
- package/skills/hr-stock-ui-audit/scripts/scan.mjs +619 -0
- package/skills/hr-tdd/LICENSE +21 -0
- package/skills/hr-tdd/NOTICE.md +10 -0
- package/skills/hr-tdd/SKILL.md +40 -0
- package/skills/hr-tdd/agents/openai.yaml +3 -0
- package/skills/hr-tdd/mocking.md +39 -0
- package/skills/hr-tdd/tests.md +77 -0
- package/skills/hr-test-audit/SKILL.md +146 -0
- package/skills/hr-test-audit/agents/openai.yaml +3 -0
- package/skills/hr-test-audit/scripts/floor-guard.ts +137 -0
- package/skills/hr-what-next/SKILL.md +61 -0
- package/skills/hr-what-next/agents/openai.yaml +4 -0
- package/skills/hr-what-next/references/reporting.md +68 -0
- package/skills/hr-writing-for-agents/NOTICE.md +46 -0
- package/skills/hr-writing-for-agents/SKILL-MECHANICS.md +83 -0
- package/skills/hr-writing-for-agents/SKILL.md +108 -0
- package/skills/hr-writing-for-agents/agents/openai.yaml +3 -0
- package/skills/hr-writing-pr/NOTICE.md +48 -0
- package/skills/hr-writing-pr/SKILL.md +104 -0
- package/skills/hr-writing-pr/agents/openai.yaml +2 -0
|
@@ -0,0 +1,39 @@
|
|
|
1
|
+
# When to mock
|
|
2
|
+
|
|
3
|
+
Mock at **system boundaries** only:
|
|
4
|
+
|
|
5
|
+
- External APIs (payment, email, etc.)
|
|
6
|
+
- Databases (sometimes; prefer a test DB)
|
|
7
|
+
- Time/randomness
|
|
8
|
+
- File system (sometimes)
|
|
9
|
+
|
|
10
|
+
Don't mock:
|
|
11
|
+
|
|
12
|
+
- Your own classes/modules
|
|
13
|
+
- Internal collaborators
|
|
14
|
+
- Anything you control
|
|
15
|
+
|
|
16
|
+
## Designing for mockability
|
|
17
|
+
|
|
18
|
+
At system boundaries, design interfaces that are easy to mock:
|
|
19
|
+
|
|
20
|
+
**1. Use dependency injection**
|
|
21
|
+
|
|
22
|
+
Pass external dependencies in rather than creating them internally:
|
|
23
|
+
|
|
24
|
+
```typescript
|
|
25
|
+
// Easy to mock
|
|
26
|
+
function processPayment(order, paymentClient) {
|
|
27
|
+
return paymentClient.charge(order.total);
|
|
28
|
+
}
|
|
29
|
+
|
|
30
|
+
// Hard to mock
|
|
31
|
+
function processPayment(order) {
|
|
32
|
+
const client = new StripeClient(process.env.STRIPE_KEY);
|
|
33
|
+
return client.charge(order.total);
|
|
34
|
+
}
|
|
35
|
+
```
|
|
36
|
+
|
|
37
|
+
**2. Reuse production interfaces**
|
|
38
|
+
|
|
39
|
+
Prefer existing operation-specific APIs when they serve production callers. Otherwise mock the transport boundary; request routing in a fake is acceptable. Do not add wrappers solely to simplify mocks. Assert observable results rather than calls to repo-owned helpers.
|
|
@@ -0,0 +1,77 @@
|
|
|
1
|
+
# Good and bad tests
|
|
2
|
+
|
|
3
|
+
## Good tests
|
|
4
|
+
|
|
5
|
+
**Integration-style**: Test through real interfaces, not mocks of internal parts.
|
|
6
|
+
|
|
7
|
+
```typescript
|
|
8
|
+
// GOOD: Tests observable behavior
|
|
9
|
+
test("user can checkout with valid cart", async () => {
|
|
10
|
+
const cart = createCart();
|
|
11
|
+
cart.add(product);
|
|
12
|
+
const result = await checkout(cart, paymentMethod);
|
|
13
|
+
expect(result.status).toBe("confirmed");
|
|
14
|
+
});
|
|
15
|
+
```
|
|
16
|
+
|
|
17
|
+
Characteristics:
|
|
18
|
+
|
|
19
|
+
- Tests behavior users/callers care about
|
|
20
|
+
- Uses public API only
|
|
21
|
+
- Survives internal refactors
|
|
22
|
+
- Describes WHAT, not HOW
|
|
23
|
+
- Assertions establish one observable behavior; use several when the contract needs them
|
|
24
|
+
|
|
25
|
+
## Bad tests
|
|
26
|
+
|
|
27
|
+
**Implementation-detail tests**: Coupled to internal structure.
|
|
28
|
+
|
|
29
|
+
```typescript
|
|
30
|
+
// BAD: Tests implementation details
|
|
31
|
+
test("checkout calls paymentService.process", async () => {
|
|
32
|
+
const mockPayment = { process: jest.fn() };
|
|
33
|
+
await checkout(cart, mockPayment);
|
|
34
|
+
expect(mockPayment.process).toHaveBeenCalledWith(cart.total);
|
|
35
|
+
});
|
|
36
|
+
```
|
|
37
|
+
|
|
38
|
+
Red flags:
|
|
39
|
+
|
|
40
|
+
- Mocking internal collaborators
|
|
41
|
+
- Testing private methods
|
|
42
|
+
- Asserting internal collaborator calls/counts/order instead of observable behavior. External-boundary count or order contracts are valid assertions.
|
|
43
|
+
- Test breaks when refactoring without behavior change
|
|
44
|
+
- Test name describes HOW not WHAT
|
|
45
|
+
- Bypassing the tested public interface to inspect private implementation state. Observable storage, wire, and DOM outcomes remain valid; prefer fake state over call logs when state expresses the contract.
|
|
46
|
+
|
|
47
|
+
```typescript
|
|
48
|
+
// BAD: Checks private storage when storage is not the public contract
|
|
49
|
+
test("createUser saves to database", async () => {
|
|
50
|
+
await createUser({ name: "Alice" });
|
|
51
|
+
const row = await db.query("SELECT * FROM users WHERE name = ?", ["Alice"]);
|
|
52
|
+
expect(row).toBeDefined();
|
|
53
|
+
});
|
|
54
|
+
|
|
55
|
+
// GOOD: Verifies through interface
|
|
56
|
+
test("createUser makes user retrievable", async () => {
|
|
57
|
+
const user = await createUser({ name: "Alice" });
|
|
58
|
+
const retrieved = await getUser(user.id);
|
|
59
|
+
expect(retrieved.name).toBe("Alice");
|
|
60
|
+
});
|
|
61
|
+
```
|
|
62
|
+
|
|
63
|
+
**Tautological tests**: Expected value restates the implementation, so the test passes by construction.
|
|
64
|
+
|
|
65
|
+
```typescript
|
|
66
|
+
// BAD: Expected value is recomputed the way the code computes it
|
|
67
|
+
test("calculateTotal sums line items", () => {
|
|
68
|
+
const items = [{ price: 10 }, { price: 5 }];
|
|
69
|
+
const expected = items.reduce((sum, i) => sum + i.price, 0);
|
|
70
|
+
expect(calculateTotal(items)).toBe(expected);
|
|
71
|
+
});
|
|
72
|
+
|
|
73
|
+
// GOOD: Expected value is an independent, known literal
|
|
74
|
+
test("calculateTotal sums line items", () => {
|
|
75
|
+
expect(calculateTotal([{ price: 10 }, { price: 5 }])).toBe(15);
|
|
76
|
+
});
|
|
77
|
+
```
|
|
@@ -0,0 +1,146 @@
|
|
|
1
|
+
---
|
|
2
|
+
name: hr-test-audit
|
|
3
|
+
description: Gate new or changed tests on the value they add, and sweep an existing suite for low-value, implementation-coupled or duplicate tests to delete. Use when adding or reviewing tests, or when asked to prune, audit or clean up a test suite.
|
|
4
|
+
---
|
|
5
|
+
|
|
6
|
+
# Test audit
|
|
7
|
+
|
|
8
|
+
Two modes share one value bar: a test earns its upkeep by protecting observable
|
|
9
|
+
behavior, a credible regression, or an independent contract. **Authoring mode**
|
|
10
|
+
gates each new or changed test before it lands. **Audit mode** finds existing
|
|
11
|
+
tests that fail the bar and removes them in small, evidenced batches. For the
|
|
12
|
+
red-green loop itself, use a TDD skill where one is installed; this skill decides which tests are worth
|
|
13
|
+
keeping.
|
|
14
|
+
|
|
15
|
+
## Authoring gate
|
|
16
|
+
|
|
17
|
+
Before adding a test, answer all four. A missing answer means don't add it yet.
|
|
18
|
+
|
|
19
|
+
1. What observable behavior, invariant or contract does it protect?
|
|
20
|
+
2. What credible regression makes it fail? Name the production change that
|
|
21
|
+
turns it red: a wrong constant or argument, a wrong branch, a missing side
|
|
22
|
+
effect, an empty or default return, or a missing check for empty, nil,
|
|
23
|
+
unauthorized or malformed input. If none would, it is a change detector or
|
|
24
|
+
cannot fail.
|
|
25
|
+
3. Why doesn't existing coverage already catch that? Each contract has one
|
|
26
|
+
owning test at its strongest boundary. Another layer needs its own risk the
|
|
27
|
+
owner cannot reach. Prefer a new case in an existing table or fixture over a
|
|
28
|
+
near-duplicate test.
|
|
29
|
+
4. Does it need a production seam (export, flag, wrapper, injection hook) that
|
|
30
|
+
no production caller uses? Then test at the real boundary instead.
|
|
31
|
+
|
|
32
|
+
When a unit must be tested in isolation, write down the ways it can fail before
|
|
33
|
+
writing the code, and test those failures. A test written after the code tends
|
|
34
|
+
to restate the code.
|
|
35
|
+
|
|
36
|
+
A bug regression test must fail on the pre-fix code for the intended reason,
|
|
37
|
+
then pass after the fix. One that never demonstrably failed proves the mock, not
|
|
38
|
+
the fix. One regression at the owning boundary covers the bug; don't replay it
|
|
39
|
+
at every layer it crosses. For a sequence `hr-ordering-tests` found, that
|
|
40
|
+
regression is the named test beside its enumeration.
|
|
41
|
+
|
|
42
|
+
Changing an existing test so it checks less counts as removing it: deleting or
|
|
43
|
+
skipping it, loosening an assertion, or rewriting an expected value to match new
|
|
44
|
+
output. It needs the audit-mode evidence from step 2, not only these answers.
|
|
45
|
+
To catch these moves in a diff, run
|
|
46
|
+
`bun <this skill's directory>/scripts/floor-guard.ts [--base <ref>]` from
|
|
47
|
+
the repository. It reports new suppression comments, added skips or
|
|
48
|
+
`.only`, deleted test files and assertions removed from surviving tests, and
|
|
49
|
+
exits 0 clean, 1 with findings, 2 when it could not run. Each finding still
|
|
50
|
+
needs a reason; a 2 is never a pass.
|
|
51
|
+
|
|
52
|
+
For retry and concurrency failures, exercise the implementation at the boundary
|
|
53
|
+
where order matters. Cover the credible lost-response, interrupted-write or
|
|
54
|
+
restart sequence with controlled barriers and assert durable state or externally
|
|
55
|
+
visible behavior. Do not replace that coverage with a separate model of the code.
|
|
56
|
+
Code that merges events from more than one actor also needs an enumeration test
|
|
57
|
+
from `hr-ordering-tests`, and a change that adds a kind of event adds it to that
|
|
58
|
+
test's event list.
|
|
59
|
+
|
|
60
|
+
When behavior depends on three or more independent settings, cover every pair
|
|
61
|
+
of their values rather than every combination: list each setting's value
|
|
62
|
+
classes and edge values, drop combinations the code rejects, and build the
|
|
63
|
+
smallest table where each pair appears at least once (Microsoft PICT generates
|
|
64
|
+
one). Most interaction bugs need only two settings to line up. Add an explicit
|
|
65
|
+
case for each combination of three or more settings already known to interact,
|
|
66
|
+
such as one behind a past bug or a documented constraint.
|
|
67
|
+
|
|
68
|
+
Then check the test against the junk patterns below. A match fails the gate
|
|
69
|
+
unless the retention bar names the contract it independently guards.
|
|
70
|
+
|
|
71
|
+
## Junk patterns
|
|
72
|
+
|
|
73
|
+
Authoring rejects new tests that match; audits hunt for existing ones that do.
|
|
74
|
+
|
|
75
|
+
- no assertion, or an assertion that cannot fail
|
|
76
|
+
- expected values produced by the code under test, or copied from it
|
|
77
|
+
(fixtures, inventories, export lists, snapshots taken from current output)
|
|
78
|
+
- exact source, import or string greps standing in for behavior
|
|
79
|
+
- private helpers or call shapes tested again where a real boundary already
|
|
80
|
+
covers them
|
|
81
|
+
- the same contract asserted several times, or one shared helper re-tested in
|
|
82
|
+
every caller
|
|
83
|
+
- tests that exist only to keep test-only exports, globals or wrappers alive,
|
|
84
|
+
and production code whose only callers are tests
|
|
85
|
+
- mocks that implement the asserted behavior, or one mock standing in for
|
|
86
|
+
different APIs
|
|
87
|
+
- negative tests that pass for an unrelated reason (a different guard rejects
|
|
88
|
+
the input, or the production path never reaches the check)
|
|
89
|
+
- names or fixtures that promise more than the test exercises
|
|
90
|
+
- tests that break under a behavior-preserving refactor
|
|
91
|
+
|
|
92
|
+
## Retention bar
|
|
93
|
+
|
|
94
|
+
Keep a test that independently enforces a public API, protocol, config,
|
|
95
|
+
migration, storage, security, platform, default or release contract. Also keep
|
|
96
|
+
call-order tests when order is observable, regressions with a credible failure
|
|
97
|
+
mode, and a source check when it is the cheapest guard that fails on a
|
|
98
|
+
user-facing change and survives a rename. Slow or static is not a reason to
|
|
99
|
+
delete. A kept test that fails on the unchanged baseline may be a real bug:
|
|
100
|
+
reproduce and fix it rather than deleting the test.
|
|
101
|
+
|
|
102
|
+
## Audit mode
|
|
103
|
+
|
|
104
|
+
1. **Discover, read-only.** Read the repository's testing guidance first. For a
|
|
105
|
+
large suite, split discovery by area and run the slices in parallel if the
|
|
106
|
+
host allows. Prefer a few high-confidence candidates over a long speculative
|
|
107
|
+
list. Before judging one, read the whole test, the production code it covers,
|
|
108
|
+
that code's callers, and any overlapping tests.
|
|
109
|
+
2. **Record evidence per candidate** before editing: test name and location;
|
|
110
|
+
the failure it can actually detect; non-test callers of what it covers; the
|
|
111
|
+
stronger test that remains, or why none is needed; why it exists (history);
|
|
112
|
+
what production or test-support code its removal frees; the focused
|
|
113
|
+
validation command. A missing field means the candidate is not ready.
|
|
114
|
+
3. **Edit one coherent batch.** Remove the tests along with the test-only
|
|
115
|
+
exports, wrappers and dead paths they kept alive; don't leave aliases. Move a
|
|
116
|
+
retained regression to its owning boundary. Don't add replacement tests that
|
|
117
|
+
restate the implementation, and don't count uncertain deletions as progress.
|
|
118
|
+
4. **Validate.** Run the owning and sibling tests, then the repository's
|
|
119
|
+
required checks. Where a removed test grepped source or a plan, run the
|
|
120
|
+
script or dry run that owns the real contract instead.
|
|
121
|
+
5. **Report**: categories removed, kept false positives and why, checks run,
|
|
122
|
+
and production versus test lines changed (`git diff --numstat`). Land one
|
|
123
|
+
batch at a time through the repository's normal flow, then rerun discovery on
|
|
124
|
+
the updated base for the next batch.
|
|
125
|
+
|
|
126
|
+
## Sources
|
|
127
|
+
|
|
128
|
+
Original synthesis, adapting:
|
|
129
|
+
|
|
130
|
+
- OpenClaw's
|
|
131
|
+
[`test-audit`](https://github.com/openclaw/openclaw/blob/65f1e4d2279eecd6e40d55d82027d5c97b4b272b/.agents/skills/test-audit/SKILL.md):
|
|
132
|
+
the authoring gate, junk patterns, retention bar and evidence fields.
|
|
133
|
+
- [Ansh Nanda via Ray Fernando](https://x.com/RayFernando1337/status/2102927565778522610):
|
|
134
|
+
the failure-list-first rule. Their "E2E tests only" rule is not adopted.
|
|
135
|
+
- no_human's [tamper guard](https://github.com/no-human-ai/no_human): weakening
|
|
136
|
+
a test counts as removing it.
|
|
137
|
+
- addyosmani/agent-skills'
|
|
138
|
+
[floor guard](https://github.com/addyosmani/agent-skills/blob/main/skills/constraint-driven-development/references/floor-guard.md)
|
|
139
|
+
(MIT): the diff checker.
|
|
140
|
+
- obra/superpowers `writing-good-tests.md`: the mutation check behind
|
|
141
|
+
authoring-gate question 2.
|
|
142
|
+
- omkamal's [pypict skill](https://github.com/omkamal/pypict-claude-skill):
|
|
143
|
+
pairwise coverage.
|
|
144
|
+
|
|
145
|
+
For recorded proof that a UI change works, see michaelshimeles'
|
|
146
|
+
[`evidence-driven-testing`](https://github.com/michaelshimeles/skills/tree/main/evidence-driven-testing).
|
|
@@ -0,0 +1,137 @@
|
|
|
1
|
+
#!/usr/bin/env bun
|
|
2
|
+
// Flag changes that make tests or checkers easier to pass: new suppression
|
|
3
|
+
// comments, added skips or `.only`, deleted test files, and assertions removed
|
|
4
|
+
// from test files that still exist. Diff-scoped: merge base to working tree,
|
|
5
|
+
// untracked files included. Tightening is silent; only loosening is reported.
|
|
6
|
+
// bun floor-guard.ts [--base <ref>] (default: origin/HEAD, then origin/main)
|
|
7
|
+
// Exit 0 clean, 1 findings, 2 the guard could not run. Never read 2 as clean.
|
|
8
|
+
// Adapted from addyosmani/agent-skills constraint-driven-development
|
|
9
|
+
// references/floor-guard.md (MIT).
|
|
10
|
+
import { spawnSync } from "node:child_process";
|
|
11
|
+
import { parseArgs } from "node:util";
|
|
12
|
+
|
|
13
|
+
export type Finding = { rule: string; file: string; text: string };
|
|
14
|
+
|
|
15
|
+
const SUPPRESSIONS =
|
|
16
|
+
/@ts-ignore|@ts-nocheck|@ts-expect-error|eslint-disable|oxlint-disable|biome-ignore|#\s*noqa|#\s*type:\s*ignore|istanbul ignore|c8 ignore|nosemgrep|gitleaks:allow|Stryker disable/;
|
|
17
|
+
const SKIPS =
|
|
18
|
+
/\.(skip|todo|only)\s*\(|\b(xit|xdescribe|xtest)\s*\(|@pytest\.mark\.(skip|xfail)|\bt\.Skip\(/;
|
|
19
|
+
const ASSERTION = /\b(expect|assert\w*|should)\b/;
|
|
20
|
+
|
|
21
|
+
export function isTestFile(path: string): boolean {
|
|
22
|
+
return /\.(test|spec)\.[^/]+$|_test\.[^/]+$|(^|\/)test_[^/]+$|(^|\/)(tests?|__tests__)\//.test(
|
|
23
|
+
path,
|
|
24
|
+
);
|
|
25
|
+
}
|
|
26
|
+
|
|
27
|
+
// Reads a unified diff (`--unified=0` is enough) and returns the loosening moves.
|
|
28
|
+
export function scanDiff(diff: string): Finding[] {
|
|
29
|
+
const added: { file: string; text: string }[] = [];
|
|
30
|
+
const removed: { file: string; text: string }[] = [];
|
|
31
|
+
const deleted = new Set<string>();
|
|
32
|
+
const strip = (p: string) => p.replace(/^[ab]\//, "");
|
|
33
|
+
let file = "";
|
|
34
|
+
let oldFile = "";
|
|
35
|
+
// File headers appear only between `diff --git` and the first `@@`; inside a hunk,
|
|
36
|
+
// an added line such as `++ x` is content, not a header.
|
|
37
|
+
let inHunk = false;
|
|
38
|
+
for (const line of diff.split("\n")) {
|
|
39
|
+
if (line.startsWith("diff ")) {
|
|
40
|
+
inHunk = false;
|
|
41
|
+
} else if (line.startsWith("@@")) {
|
|
42
|
+
inHunk = true;
|
|
43
|
+
} else if (!inHunk && line.startsWith("--- ")) {
|
|
44
|
+
oldFile = strip(line.slice(4));
|
|
45
|
+
} else if (!inHunk && line.startsWith("+++ ")) {
|
|
46
|
+
const newFile = strip(line.slice(4));
|
|
47
|
+
file = newFile === "/dev/null" ? oldFile : newFile;
|
|
48
|
+
if (newFile === "/dev/null") {
|
|
49
|
+
deleted.add(oldFile);
|
|
50
|
+
}
|
|
51
|
+
} else if (line.startsWith("+")) {
|
|
52
|
+
added.push({ file, text: line.slice(1) });
|
|
53
|
+
} else if (line.startsWith("-")) {
|
|
54
|
+
removed.push({ file, text: line.slice(1) });
|
|
55
|
+
}
|
|
56
|
+
}
|
|
57
|
+
|
|
58
|
+
const findings: Finding[] = [];
|
|
59
|
+
const flag = (rule: string, f: string, text: string) =>
|
|
60
|
+
findings.push({ rule, file: f, text: text.trim().slice(0, 120) });
|
|
61
|
+
for (const { file: f, text } of added) {
|
|
62
|
+
if (SUPPRESSIONS.test(text)) {
|
|
63
|
+
flag("silenced-checker", f, text);
|
|
64
|
+
}
|
|
65
|
+
if (isTestFile(f) && SKIPS.test(text)) {
|
|
66
|
+
flag("test-skipped", f, text);
|
|
67
|
+
}
|
|
68
|
+
}
|
|
69
|
+
for (const f of deleted) {
|
|
70
|
+
if (isTestFile(f)) {
|
|
71
|
+
flag("test-deleted", f, "file deleted");
|
|
72
|
+
}
|
|
73
|
+
}
|
|
74
|
+
// An assertion line that reappears in the same file was moved, not removed.
|
|
75
|
+
const kept = new Set(added.map((a) => `${a.file}\0${a.text.trim()}`));
|
|
76
|
+
for (const { file: f, text } of removed) {
|
|
77
|
+
if (!isTestFile(f) || deleted.has(f) || !ASSERTION.test(text)) {
|
|
78
|
+
continue;
|
|
79
|
+
}
|
|
80
|
+
if (!kept.has(`${f}\0${text.trim()}`)) {
|
|
81
|
+
flag("assertion-removed", f, text);
|
|
82
|
+
}
|
|
83
|
+
}
|
|
84
|
+
return findings;
|
|
85
|
+
}
|
|
86
|
+
|
|
87
|
+
function git(args: string[], okStatuses = [0]): string | null {
|
|
88
|
+
const r = spawnSync("git", args, { encoding: "utf8" });
|
|
89
|
+
return r.status !== null && okStatuses.includes(r.status) ? r.stdout : null;
|
|
90
|
+
}
|
|
91
|
+
|
|
92
|
+
function main(): number {
|
|
93
|
+
const bail = (msg: string) => (console.error(`floor-guard: ${msg}`), 2);
|
|
94
|
+
let base: string | undefined;
|
|
95
|
+
try {
|
|
96
|
+
base = parseArgs({ options: { base: { type: "string" } } }).values.base;
|
|
97
|
+
} catch (error) {
|
|
98
|
+
return bail(error instanceof Error ? error.message : String(error));
|
|
99
|
+
}
|
|
100
|
+
const bases = base ? [base] : ["origin/HEAD", "origin/main"];
|
|
101
|
+
let mergeBase: string | undefined;
|
|
102
|
+
for (const b of bases) {
|
|
103
|
+
mergeBase = git(["merge-base", b, "HEAD"])?.trim();
|
|
104
|
+
if (mergeBase) {
|
|
105
|
+
break;
|
|
106
|
+
}
|
|
107
|
+
}
|
|
108
|
+
if (!mergeBase) {
|
|
109
|
+
return bail(`no merge base against ${bases.join(" or ")}`);
|
|
110
|
+
}
|
|
111
|
+
const tracked = git(["diff", "--unified=0", mergeBase, "--"]);
|
|
112
|
+
const untracked = git(["ls-files", "--others", "--exclude-standard"]);
|
|
113
|
+
if (tracked === null || untracked === null) {
|
|
114
|
+
return bail("could not read the diff");
|
|
115
|
+
}
|
|
116
|
+
let diff = tracked;
|
|
117
|
+
for (const f of untracked.split("\n").filter(Boolean)) {
|
|
118
|
+
// --no-index exits 1 when the sides differ, which is the normal case here.
|
|
119
|
+
const d = git(["diff", "--no-index", "--unified=0", "/dev/null", f], [0, 1]);
|
|
120
|
+
if (d === null) {
|
|
121
|
+
return bail(`could not diff untracked file ${f}`);
|
|
122
|
+
}
|
|
123
|
+
diff += `\n${d}`;
|
|
124
|
+
}
|
|
125
|
+
const findings = scanDiff(diff);
|
|
126
|
+
for (const f of findings) {
|
|
127
|
+
console.log(`${f.rule}\t${f.file}\t${f.text}`);
|
|
128
|
+
}
|
|
129
|
+
if (findings.length === 0) {
|
|
130
|
+
console.log("floor-guard: clean");
|
|
131
|
+
}
|
|
132
|
+
return findings.length ? 1 : 0;
|
|
133
|
+
}
|
|
134
|
+
|
|
135
|
+
if (import.meta.main) {
|
|
136
|
+
process.exit(main());
|
|
137
|
+
}
|
|
@@ -0,0 +1,61 @@
|
|
|
1
|
+
---
|
|
2
|
+
name: hr-what-next
|
|
3
|
+
description: "Reconcile remaining work and recommend priorities. Use for next, next?, what's next, what remains, backlog reviews, full-session audits of tasks and unanswered or past questions, and equivalent requests. Do not use for go or continue, which retain their acceptance/continuation meaning, or progress/ETA-only requests."
|
|
4
|
+
---
|
|
5
|
+
|
|
6
|
+
# What next
|
|
7
|
+
|
|
8
|
+
Turn the requested scope into an evidence-based inventory and next decision.
|
|
9
|
+
Before reporting, read the bundled [reporting procedure](references/reporting.md).
|
|
10
|
+
Use it with the governing continuation and offer rules; this request does
|
|
11
|
+
not cancel selected work or authorize a new task.
|
|
12
|
+
|
|
13
|
+
Before a session-completion claim, apply the governing § Finishing work's
|
|
14
|
+
full-session gate even when the request was only a short "next?". Save the
|
|
15
|
+
completed state before the completion message; a report alone does not do so.
|
|
16
|
+
|
|
17
|
+
1. Choose the review scope from the request and its context. For a short
|
|
18
|
+
"next?", check the current task, its ledger and latest results, plus this
|
|
19
|
+
floor whatever the scope: every question from an earlier offer in this
|
|
20
|
+
conversation that the user has not answered, every owned uncommitted file,
|
|
21
|
+
unpushed commit or held checkout, and the number of other live ledger items
|
|
22
|
+
(deferred, unselected, blocked or follow-up) with a link to the ledger.
|
|
23
|
+
Report each floor item, or state that the floor is empty. While any floor
|
|
24
|
+
item remains, do not say that nothing is left or that nothing needs the
|
|
25
|
+
user; re-present the unanswered questions as an offer instead. When asked
|
|
26
|
+
for all current and past items, review the available session transcript,
|
|
27
|
+
relevant plans, task lists, handoffs and linked follow-ups. Name source
|
|
28
|
+
ranges and missing, inaccessible or truncated records. Sweep other
|
|
29
|
+
sessions' records only within the requested project and scope.
|
|
30
|
+
2. Trace requests, unanswered questions, commitments, offered alternatives
|
|
31
|
+
and findings to their latest disposition. Reconcile duplicate, superseded
|
|
32
|
+
and stale rows with completion or replacement evidence. Keep owners,
|
|
33
|
+
deferred triggers and other sessions' context visible. An old task
|
|
34
|
+
description alone does not establish current activity or ownership.
|
|
35
|
+
3. Preserve the latest selected scope and valid unanswered offer in the
|
|
36
|
+
durable ledger. Distinguish done, authorized unfinished, unselected,
|
|
37
|
+
blocked, deferred and other-owner items. A completed implementation does
|
|
38
|
+
not complete required checks or landing; deferral does not mean done.
|
|
39
|
+
4. Rank remaining items toward the current goal and explicit priorities.
|
|
40
|
+
Explain the objective and weigh expected impact, next-decision value,
|
|
41
|
+
urgency, dependencies, effort and evidence confidence. Keep priority,
|
|
42
|
+
readiness and authority separate. Label unknown gains rather than
|
|
43
|
+
inventing scores or measurements.
|
|
44
|
+
5. Lead with what is complete, what remains and the next unfinished selected
|
|
45
|
+
step. Show one row per remaining item with rank, state, expected impact
|
|
46
|
+
and its reason, next action or decision, and owner/source where needed.
|
|
47
|
+
For a full audit, put the full individual table in a durable report
|
|
48
|
+
and link it beside the immediate decisions. Answer whether items are
|
|
49
|
+
accounted for separately from whether selected work is complete.
|
|
50
|
+
6. Continue work that can advance under existing authorization. Ask only for
|
|
51
|
+
unresolved choices using the governing offer format. Preserve schedules
|
|
52
|
+
and ownership; this audit grants no authority to start, transfer, publish
|
|
53
|
+
or clean up work merely because it appears in the inventory.
|
|
54
|
+
|
|
55
|
+
For a full audit, save a mapping from reviewed source records to items or
|
|
56
|
+
reviewed context-only dispositions. If `hr-handoff` and its reconciliation
|
|
57
|
+
resources are available, reuse its `references/reconciliation.md` procedure
|
|
58
|
+
and `scripts/check-reconciliation.mjs` checker. Otherwise retain the mapping
|
|
59
|
+
and coverage gaps without claiming a mechanical check. A passing checker
|
|
60
|
+
accounts for supplied records; it does not prove every promise was understood
|
|
61
|
+
or that unavailable history contains no other work.
|
|
@@ -0,0 +1,68 @@
|
|
|
1
|
+
## Reporting
|
|
2
|
+
|
|
3
|
+
Lead with the answer or the concrete result. Show what is complete and what
|
|
4
|
+
remains, and separate measured facts from unverified claims. Use numbered steps
|
|
5
|
+
for actions the user must perform.
|
|
6
|
+
|
|
7
|
+
During long work, give frequent useful progress updates with completed evidence,
|
|
8
|
+
the current action and what remains. Show clock-time forecasts in the user's
|
|
9
|
+
local timezone. Use the timezone provided by the user or session environment;
|
|
10
|
+
ask if neither establishes it.
|
|
11
|
+
|
|
12
|
+
Use a visual when it makes a change, behavior or decision clearer; keep a short
|
|
13
|
+
text explanation beside it. For visible interface changes, prefer actual
|
|
14
|
+
before/after captures with comparable content, viewport and state when available.
|
|
15
|
+
Label mockups and simulated behavior as illustrations, not verification. Use
|
|
16
|
+
interaction when exploring states or alternatives helps the reader, and provide
|
|
17
|
+
an accessible text or static equivalent. Use the host's available tools within
|
|
18
|
+
existing browser and task authorization.
|
|
19
|
+
|
|
20
|
+
Use a Markdown table when comparing items on common criteria or reporting
|
|
21
|
+
repeated records with useful shared fields. When asked about benefits,
|
|
22
|
+
tradeoffs or how a proposal differs from current behavior, use a compact
|
|
23
|
+
table for multiple items. Explain one item per row. For changes, show current
|
|
24
|
+
and proposed behavior and why the difference matters. Include relevant
|
|
25
|
+
tradeoffs and evidence or uncertainty; label unknowns rather than inventing
|
|
26
|
+
gains. Keep columns consistent and cells short. Label missing or unverified values and put units in headings. Put
|
|
27
|
+
explanations and caveats beside the table. Split wide tables or use lists when
|
|
28
|
+
long cells obscure the comparison. Preserve § Offers and any enabled offer format.
|
|
29
|
+
|
|
30
|
+
When asked for a backlog, research list or remaining work, check the current
|
|
31
|
+
session and relevant task records within the requested scope. Reconcile
|
|
32
|
+
completed, superseded and duplicate items before reporting what remains.
|
|
33
|
+
State which records were checked and label incomplete coverage.
|
|
34
|
+
|
|
35
|
+
Show one row per remaining item in priority order. Use compact columns for
|
|
36
|
+
rank, item, state, expected impact with its priority reason, and next action
|
|
37
|
+
or decision. Include owners and source links when needed to distinguish work.
|
|
38
|
+
Keep blocked, deferred, unstarted and research items visible with their
|
|
39
|
+
conditions; priority does not authorize starting them.
|
|
40
|
+
|
|
41
|
+
State the ranking objective from the current task's goal and explicit user
|
|
42
|
+
priorities. Recent work informs that objective; explain any inferred goal.
|
|
43
|
+
Weigh expected contribution to the goal and how much the next action helps
|
|
44
|
+
make the next decision, accounting for urgency, dependencies, effort and
|
|
45
|
+
confidence in the evidence. For performance work, use relevant latency,
|
|
46
|
+
throughput or resource measures. For fixes, weigh severity and affected users.
|
|
47
|
+
For enhancements, weigh user value and progress toward acceptance criteria.
|
|
48
|
+
For research, name the uncertainty or decision the work could resolve.
|
|
49
|
+
Label expected gains and unknowns; do not invent measurements or scores.
|
|
50
|
+
Keep priority separate from readiness, and preserve § Finishing work's
|
|
51
|
+
requirements for continuing authorized work and making offers.
|
|
52
|
+
|
|
53
|
+
Put the answer, and anything the user must read or act on, in the reply's text
|
|
54
|
+
after its last tool call. Text written between tool calls can be collapsed or
|
|
55
|
+
lost. When the reply ends with a question card, that text goes after every
|
|
56
|
+
other tool call, right before the card.
|
|
57
|
+
|
|
58
|
+
Verify work with completed checks and their output. Confirm each check's exit status or final
|
|
59
|
+
result before claiming a pass, and do not hide failures by filtering output. Report changes,
|
|
60
|
+
verification, failed or unrun checks and remaining uncertainty. At task or session closeout,
|
|
61
|
+
save reusable lessons with their condition, action and evidence in the project's record or notes.
|
|
62
|
+
Link existing rules or checks. When none emerged, no lesson entry is needed.
|
|
63
|
+
|
|
64
|
+
Name each choice made in passing that costs the user something if missed.
|
|
65
|
+
That covers a tradeoff, a default picked for them, a step you did not
|
|
66
|
+
highlight and a result that may be off, but not routine plumbing. Describe
|
|
67
|
+
it in words the user would still recognize a week later, not in names coined
|
|
68
|
+
during the work.
|
|
@@ -0,0 +1,46 @@
|
|
|
1
|
+
# Source notices
|
|
2
|
+
|
|
3
|
+
This notice accompanies the hr-writing-for-agents bundle when copied on its own.
|
|
4
|
+
|
|
5
|
+
## mattpocock/skills
|
|
6
|
+
|
|
7
|
+
Source: https://github.com/mattpocock/skills (compared at revision `d81f3a1`)
|
|
8
|
+
|
|
9
|
+
- `skills/hr-writing-for-agents/`: adapted from `skills/productivity/writing-for-agents/`.
|
|
10
|
+
|
|
11
|
+
Copyright (c) 2026 Matt Pocock
|
|
12
|
+
|
|
13
|
+
## obra/superpowers
|
|
14
|
+
|
|
15
|
+
Source: https://github.com/obra/superpowers (compared at revision `8ca22db`)
|
|
16
|
+
|
|
17
|
+
- `skills/hr-writing-for-agents/SKILL.md`: the instruction-form table is adapted
|
|
18
|
+
from `writing-skills`.
|
|
19
|
+
|
|
20
|
+
Copyright (c) 2025 Jesse Vincent
|
|
21
|
+
|
|
22
|
+
The source's wording tests found that a recipe beat a prohibition for shape failures; the instruction-form table preserves that approach.
|
|
23
|
+
|
|
24
|
+
## house-rules and MIT permission notice
|
|
25
|
+
|
|
26
|
+
MIT License
|
|
27
|
+
|
|
28
|
+
Copyright (c) 2026 Aaron Queen
|
|
29
|
+
|
|
30
|
+
Permission is hereby granted, free of charge, to any person obtaining a copy
|
|
31
|
+
of this software and associated documentation files (the "Software"), to deal
|
|
32
|
+
in the Software without restriction, including without limitation the rights
|
|
33
|
+
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
|
34
|
+
copies of the Software, and to permit persons to whom the Software is
|
|
35
|
+
furnished to do so, subject to the following conditions:
|
|
36
|
+
|
|
37
|
+
The above copyright notice and this permission notice shall be included in all
|
|
38
|
+
copies or substantial portions of the Software.
|
|
39
|
+
|
|
40
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
|
41
|
+
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
|
42
|
+
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
|
43
|
+
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
|
44
|
+
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
|
45
|
+
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
|
46
|
+
SOFTWARE.
|