@kensio/skills 1.13.1

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,183 @@
1
+ # Mechanics behind the modelling rules
2
+
3
+ The numbers and patterns the [SKILL.md](../SKILL.md) rules rest on, collected from the DynamoDB
4
+ developer guide. Read this when the question turns on cost, throughput or size. Fetch the linked
5
+ pages when a decision rests on an exact figure, because quotas move.
6
+
7
+ ## Partitions and throughput
8
+
9
+ A table is stored in partitions, each backed by SSD and replicated across Availability Zones. AWS
10
+ manages them and never exposes them directly. More partitions appear when provisioned throughput
11
+ rises past what the current ones serve, and when an existing partition fills.
12
+
13
+ DynamoDB hashes the partition key to choose the partition. Items sharing a partition key value form
14
+ an **item collection**, held together and sorted by sort key, which is what makes a range query over
15
+ one collection cheap. Where the table carries no local secondary index, DynamoDB splits an item
16
+ collection across as many partitions as it needs, and there is no ceiling on the number of distinct
17
+ sort key values under one partition key.
18
+
19
+ **Every partition serves 3,000 read units and 1,000 write units per second.** One read unit is one
20
+ strongly consistent read of an item up to 4 KB, or two eventually consistent reads. One write unit
21
+ is one write of an item up to 1 KB. Item size multiplies this. A 20 KB item costs 5 read units per
22
+ consistent read, which puts the ceiling at 600 reads per second against that one item.
23
+
24
+ Source
25
+ [Partitions and data distribution](https://docs.aws.amazon.com/amazondynamodb/latest/developerguide/HowItWorks.Partitions.html)
26
+ and
27
+ [Best practices for partition keys](https://docs.aws.amazon.com/amazondynamodb/latest/developerguide/bp-partition-key-design.html).
28
+
29
+ ## Choosing a partition key that spreads
30
+
31
+ Throughput efficiency rises with the ratio of partition key values accessed to partition key values
32
+ that exist. The AWS comparison:
33
+
34
+ | Partition key value | Uniformity |
35
+ | --------------------------------------------------------------- | ---------- |
36
+ | User id, in an application with many users | Good |
37
+ | Status code, where few codes exist | Bad |
38
+ | Creation date rounded to a day, hour or minute | Bad |
39
+ | Device id, where devices are accessed at similar intervals | Good |
40
+ | Device id, where one device is far more popular than the others | Bad |
41
+
42
+ The date case is the one that catches people. Every item created today lands on one partition key
43
+ value and therefore one physical partition.
44
+
45
+ A table small enough to fit in a single partition, allowing for growth, and whose throughput stays
46
+ inside one partition's limits, will not throttle whatever the key looks like.
47
+
48
+ Source
49
+ [Designing partition keys to distribute your workload](https://docs.aws.amazon.com/amazondynamodb/latest/developerguide/bp-partition-key-uniform-load.html).
50
+
51
+ ## Write sharding
52
+
53
+ Where the natural key concentrates writes, widen the key space by appending a suffix.
54
+
55
+ **Random suffix.** Append a random number in a fixed range, giving `2026-07-09.1` through
56
+ `2026-07-09.200`. Writes spread evenly. Reading one item back becomes impossible without knowing
57
+ which suffix it took, and reading the whole day means one `Query` per suffix followed by a merge.
58
+
59
+ **Calculated suffix.** Derive the suffix from an attribute the reader already holds, such as the sum
60
+ of the UTF-8 code points of an order id modulo 200 plus 1. Writes spread the same way, and a
61
+ `GetItem` for a known order still works because the suffix is recomputable. Reading the whole day
62
+ still costs one `Query` per suffix.
63
+
64
+ A GSI can be sharded the same way to make selective queries parallel.
65
+
66
+ Source
67
+ [Using write sharding](https://docs.aws.amazon.com/amazondynamodb/latest/developerguide/bp-partition-key-sharding.html).
68
+
69
+ ## Sort key patterns
70
+
71
+ **Hierarchy.** A composite sort key defines one-to-many relationships queryable at any level, using
72
+ `begins_with`, `between`, `>` and `<`. The AWS example is
73
+ `[country]#[region]#[state]#[county]#[city]#[neighborhood]`.
74
+
75
+ **Version history.** Keep two copies of every item. One carries a `v0_` sort key prefix and holds
76
+ the current version, and each revision is written under the next number up (`v1_`, `v2_` and so on)
77
+ with its contents also copied over `v0_`. The current version is then a query on the `v0_` prefix,
78
+ and the history is the rest of the partition.
79
+
80
+ Source
81
+ [Best practices for sort keys](https://docs.aws.amazon.com/amazondynamodb/latest/developerguide/bp-sort-keys.html).
82
+
83
+ ## Secondary indexes
84
+
85
+ A table gets 20 global secondary indexes (default quota) and 5 local secondary indexes. AWS says
86
+ global indexes are usually the more useful of the two.
87
+
88
+ **Keep the number to a minimum.** An index that is seldom queried adds storage and I/O cost and buys
89
+ no performance.
90
+
91
+ **Choose projections deliberately.** A smaller index costs less and outperforms the base table by
92
+ more. Project the attributes the queries actually return. `ALL` removes every fetch and in most
93
+ cases doubles storage and write cost. Where an index entry is under 1 KB the projection is free up
94
+ to that point, because writes round up.
95
+
96
+ **Avoid fetches on the read path.** Querying an LSI for an attribute it does not project makes
97
+ DynamoDB read the whole item from the table, adding latency and I/O. Attributes queried occasionally
98
+ have a habit of becoming attributes queried always.
99
+
100
+ **Watch LSI item collections.** An item collection covers the table items and every LSI item sharing
101
+ a partition key, and it cannot exceed 10 GB. Writes fail once it does. Pass
102
+ `ReturnItemCollectionMetrics` on writes and alarm before the limit. An LSI cannot be deleted after
103
+ creation, which makes the decision to add one permanent.
104
+
105
+ Source
106
+ [General guidelines for secondary indexes](https://docs.aws.amazon.com/amazondynamodb/latest/developerguide/bp-indexes-general.html).
107
+
108
+ ## Large items
109
+
110
+ The item size limit is 400 KB, and exceeding it fails the write with a `ValidationException`. Pass
111
+ `ReturnConsumedCapacity` on writes and alarm on items approaching the limit.
112
+
113
+ Three ways out, in the order worth trying:
114
+
115
+ - **Vertical partitioning.** Break the item into several items under one partition key, ordered by
116
+ sort key. This is the single-table answer and keeps everything queryable.
117
+ - **Compression.** GZIP or LZO into a `Binary` attribute. A compressed attribute cannot be filtered
118
+ or queried on.
119
+ - **S3.** Store the payload as an object and the object key in the item, with the item's primary key
120
+ in the S3 object metadata pointing back. No transaction spans the two, so the application owns the
121
+ cleanup of orphaned objects.
122
+
123
+ Source
124
+ [Best practices for storing large items](https://docs.aws.amazon.com/amazondynamodb/latest/developerguide/bp-use-s3-too.html).
125
+
126
+ ## What a Scan actually costs
127
+
128
+ A `Scan` reads the whole table or index and then discards what the filter rejects. It slows as the
129
+ table grows.
130
+
131
+ A single 1 MB page of 4 KB items costs 128 eventually consistent read units, or 256 strongly
132
+ consistent. That arrives as one spike, and it lands on one partition, because the items a scan reads
133
+ sit next to each other. Requests sharing that partition throttle.
134
+
135
+ Where a scan is needed:
136
+
137
+ - Set `Limit` to shrink the page, which spreads the cost and leaves gaps for other traffic.
138
+ - Use parallel segments once the table passes about 20 GB, starting at roughly one segment per 2 GB,
139
+ and only where the provisioned read capacity is not already busy.
140
+ - Retry throttled requests with exponential backoff.
141
+
142
+ Source
143
+ [Best practices for querying and scanning](https://docs.aws.amazon.com/amazondynamodb/latest/developerguide/bp-query-scan.html).
144
+
145
+ ## Adjacency lists and the materialized graph
146
+
147
+ Top-level entities become partition keys, and each relationship becomes an item in the partition
148
+ whose sort key is the id at the other end. Data duplication stays minimal and the forward query is a
149
+ plain `Query`.
150
+
151
+ The reverse direction comes from an **inverted index**, a global secondary index whose partition key
152
+ is the table's sort key.
153
+
154
+ The materialized graph pattern extends this. Edge items carry `Type` and `Target` attributes
155
+ composed into a `TypeTarget` key, one overloaded GSI indexes a `Data` attribute holding dates,
156
+ names, places and skills, and a second GSI on `TypeTarget` answers reverse lookups. Aggregations
157
+ large enough to run hot (everyone born on one date, everyone with one skill) want sharding across
158
+ logical partitions.
159
+
160
+ Multi-hop traversal at millisecond latency is Amazon Neptune's job. AWS says so on the many-to-many
161
+ page itself.
162
+
163
+ Source
164
+ [Best practices for many-to-many relationships](https://docs.aws.amazon.com/amazondynamodb/latest/developerguide/bp-adjacency-graphs.html).
165
+
166
+ ## AWS's own trade-off lists
167
+
168
+ Worth reading in full at
169
+ [Data modeling foundations](https://docs.aws.amazon.com/amazondynamodb/latest/developerguide/data-modeling-foundations.html),
170
+ because they are the most honest account of the cost of single-table design.
171
+
172
+ What AWS counts against single-table design. The learning curve is steep because the design runs
173
+ opposite to relational instinct, whole-table settings (backup, encryption, table class) apply to
174
+ every entity at once, streams carry every change whether or not a consumer wants it, GraphQL is
175
+ harder to implement, and higher-level SDK mappers struggle with one response holding several
176
+ classes.
177
+
178
+ What AWS counts for it. Data locality, fewer read units and fewer round trips, one set of
179
+ permissions and alarms, one key to rotate, capacity averaged across entities, and traffic that
180
+ smooths as patterns aggregate.
181
+
182
+ AWS's summary of when multiple tables are the right answer is short. Where the access patterns never
183
+ query several entities together, multiple tables are good and sufficient.
@@ -0,0 +1,260 @@
1
+ ---
2
+ name: github-issue-drafting
3
+ description: Draft a GitHub issue from a short note or a rough idea, grounding every claim about the code in the repository the issue will be filed against, splitting work that is really two issues, and filing it with `gh` once the user has approved the draft. Use when turning a to-do item, a Slack message, a code TODO, a failing test or a bug report into an issue, when asked to "write up an issue for" something, to "raise", "file" or "open an issue", when asked whether something should be one issue or several, and when tidying the titles, types or labels of issues that already exist.
4
+ license: Apache-2.0
5
+ metadata:
6
+ version: "1.13.1"
7
+ ---
8
+
9
+ # GitHub issue drafting
10
+
11
+ A short note ("fix the retry backoff", "SSM params", "the CLI hangs on empty input") carries enough
12
+ for whoever wrote it and too little for anyone else, including the same person in six months. The
13
+ job is an issue a reader can act on without asking what was meant, with every claim about the code
14
+ checked against the code.
15
+
16
+ ## Process
17
+
18
+ 1. **Get the note.** Use the text passed in as the skill argument. Ask the user for it if none
19
+ arrived. A note can come from anywhere (a to-do app, a chat message, a `TODO` comment, a stack
20
+ trace, a support thread) and the source changes nothing about the drafting.
21
+
22
+ 2. **Work out which repository this belongs to, and how it files issues.** `gh repo view` names the
23
+ repository behind the working directory. Confirm with the user where the working directory is
24
+ ambiguous or where the issue belongs somewhere else. Then read how this project already works:
25
+
26
+ - `.github/ISSUE_TEMPLATE/` and `CONTRIBUTING.md`, if present. **A repository's own template wins
27
+ over the structure in this skill.** Fill in that template and follow its wording.
28
+ - `gh issue list --limit 10` and one or two full issues (`gh issue view <n>`) for the house
29
+ register, the section headings in use, and how long a typical issue runs.
30
+
31
+ 3. **Investigate before drafting.** See
32
+ [Ground the draft in the repository](#ground-the-draft-in-the-repository).
33
+
34
+ 4. **Decide whether it is one issue or several.** See
35
+ [One note is often more than one issue](#one-note-is-often-more-than-one-issue).
36
+
37
+ 5. **Draft it**, separating what step 3 confirmed from what remains an assumption.
38
+
39
+ 6. **Present the draft in chat as markdown, and stop.** Filing is the user's call. List any open
40
+ questions under the draft so they can be answered before anything is posted.
41
+
42
+ 7. **File it with `gh` only after the user has explicitly asked.** See
43
+ [Filing the issue](#filing-the-issue).
44
+
45
+ ## Ground the draft in the repository
46
+
47
+ The failure mode that matters is invention. A feature called missing when it half exists,
48
+ architecture nobody built, acceptance criteria assuming decisions nobody has made. A note is too
49
+ short to carry that context. The repository has to supply it.
50
+
51
+ Budget a handful of tool calls for this. A full audit is more than the draft needs.
52
+
53
+ - **Locate the area.** Grep for the nouns and identifiers in the note. A `README`, an architecture
54
+ doc or the directory layout usually points at the right subtree in one step.
55
+ - **Read the code that would change, and its tests.** Half-built is the common case, and it is the
56
+ case that embarrasses the issue.
57
+ - **Read what the docs already promise.** A behaviour documented as supported and a behaviour
58
+ actually supported are different facts, and the gap between them is sometimes the issue.
59
+ - **Check the history.** `git log --oneline -20` for work in flight, and
60
+ `git log --oneline --all --grep="<keyword>"` for work already done under another name.
61
+ - **Search the tracker, including closed issues.** `gh issue list --state all --search "<keyword>"`.
62
+ A near duplicate is usually worth a comment on the existing issue. Say so and let the user pick.
63
+ Where `gh` is missing or unauthenticated, skip this quietly and never claim to have checked.
64
+
65
+ Carry the unresolved parts forward. Anything step 3 failed to settle belongs in the draft as an
66
+ explicit question or a stated assumption, and in chat as something for the user to answer.
67
+
68
+ ## One note is often more than one issue
69
+
70
+ A note is written in one breath. The work it names frequently spans several pull requests, and filed
71
+ whole it becomes one enormous branch that is hard to review and hard to stop halfway.
72
+
73
+ So before drafting, look for a seam that yields **independently shippable** issues. Seams that
74
+ usually work, roughly in build order:
75
+
76
+ - **A usable surface first, whatever sits on top of it second.** The library function is useful on
77
+ its own. The CLI flag, the config key or the framework integration exposing it reads better as a
78
+ follow-up that links back.
79
+ - **A piece blocked on something unbuilt.** Work waiting on another feature is its own issue, with
80
+ the dependency named, and not a caveat buried in this one.
81
+ - **A distinct usage mode.** The same capability reached at runtime and at build time is two
82
+ features with two sets of tests.
83
+ - **A bug fix and the hardening around it.** Ship the fix. File the class of problem separately.
84
+
85
+ Three seams produce issues nobody can ship alone. One issue per function or endpoint, implementation
86
+ split from its tests, and docs as their own issue. Docs belong with the behaviour they describe.
87
+
88
+ Two or three issues is the usual answer where a split is warranted. Five is over-slicing, and a
89
+ small self-contained note stays one issue. Where a split happens, say so in chat and present the set
90
+ together, each one naming its dependency and using **Out of scope** to hand work to the others.
91
+
92
+ ## Drafting rules
93
+
94
+ - **Keep it short, and shorter than feels right.** Roughly 200 to 350 words of prose plus at most
95
+ one example. Three or four sections at most, and no more than six acceptance criteria. Cut any
96
+ section that fails to help a reader understand, implement, test or evaluate the change.
97
+ - **The design discussion in chat is not the issue.** Working a note through produces rejected
98
+ alternatives, trade-offs and cost estimates, and almost none of it belongs in the body. Record the
99
+ decision and one sentence of reason. Where the discussion settled something genuinely surprising,
100
+ one short paragraph earns its place.
101
+ - **Never invent behaviour, architecture, supported APIs or acceptance criteria.** Where step 3 left
102
+ something unconfirmed, write it as a question or a stated assumption.
103
+ - **Scrub anything private before it goes anywhere public.** Notes and stack traces carry customer
104
+ names, internal hostnames, internal ticket ids, paths with a username in them, tokens and API
105
+ keys. A public issue is publication. Redact by default and ask about anything borderline.
106
+ - **Write to the problem, and to the observable behaviour that would fix it.** An issue is not a
107
+ pull request description, and a detailed implementation plan belongs in it only where step 3
108
+ turned up a constraint the implementer would otherwise miss.
109
+ - **Prefer one concrete example** (a command, a config snippet, a failing assertion, the exact error
110
+ text) over a paragraph of description.
111
+ - **A bug needs the version, the environment, the steps, the expected result and the actual
112
+ result.** Anything absent is a question for the user, and a bug report missing them wastes the
113
+ first reply.
114
+ - **Leave the process fields alone.** No assignees, milestones, estimates, or wording implying that
115
+ the issue is approved or scheduled. Type and labels are set at filing time.
116
+ - **When in doubt, cut.** Erring long is the more common failure. Somebody re-reading this in six
117
+ months needs the problem, the intended behaviour, and enough grounding to trust both.
118
+
119
+ ### Prose
120
+
121
+ Load the `technical-prose-style` and `avoid-ai-writing` skills before drafting where they are
122
+ installed, and run whatever check they ship over the body. Where neither is available, aim for one
123
+ claim per sentence, present tense, no em dashes, no marketing adjectives, and one name kept for one
124
+ thing.
125
+
126
+ ## Structure
127
+
128
+ Use the repository's own issue template where it has one. Otherwise draw from the sections below,
129
+ taking only those this particular note needs. Most issues use three or four. **Problem** and
130
+ **Desired behaviour** are the two that nearly always earn their place. Reach for **Current
131
+ behaviour** where what exists today would surprise a reader, and for **Implementation notes** only
132
+ where step 3 turned up a real constraint.
133
+
134
+ ```markdown
135
+ # Title
136
+
137
+ ## Problem
138
+
139
+ The concrete limitation, missing capability or user need.
140
+
141
+ ## Current behaviour
142
+
143
+ What happens today, grounded in what the repository actually shows. Omit where unknown.
144
+
145
+ ## Desired behaviour
146
+
147
+ The observable behaviour that should exist once this is implemented.
148
+
149
+ ## Example
150
+
151
+ A command, config, request or expected result. Include it only where it clarifies something.
152
+
153
+ ## Acceptance criteria
154
+
155
+ Testable checklist items.
156
+
157
+ ## Out of scope
158
+
159
+ Related work that should not be assumed to be included.
160
+
161
+ ## Implementation notes
162
+
163
+ Grounded constraints from the investigation. Omit the section entirely where there are none.
164
+ ```
165
+
166
+ For a bug, replace the middle three with **Steps to reproduce**, **Expected result**, **Actual
167
+ result** and **Environment** (version, runtime, operating system, anything version-pinned that
168
+ matters).
169
+
170
+ ## Titles people can find
171
+
172
+ Issues get indexed, by GitHub's search and by search engines, and they surface far more readily than
173
+ pull requests do. For a public repository the title and the opening paragraph are the whole search
174
+ snippet, and they do nearly all the work of getting the issue in front of the person who has the
175
+ problem.
176
+
177
+ - **Write the words a user would type.** Internal shorthand and internal abbreviations describe the
178
+ problem to people who already know it. Spell them out.
179
+ - **Keep the term that makes the project distinctive**, even while cutting shorthand around it. The
180
+ two look like the same edit and are opposites. An abbreviation nobody searches for should go. The
181
+ one accurate word separating this project from every other page about the same topic should stay,
182
+ because a title without it competes with the upstream documentation and loses.
183
+ - **Front-load.** Search snippets truncate around 60 characters, so anything load-bearing goes
184
+ early.
185
+ - **Generic verbs are weak alone.** "add", "support", "fix" are fine where the sentence wants them
186
+ anyway. They differentiate nothing on their own, and forcing one in is where a title starts
187
+ sounding written for a crawler.
188
+ - **Keep it subtle.** An issue that reads as search filler makes a project look automated, and costs
189
+ more credibility than the traffic is worth. Aim for a title a developer would have written anyway,
190
+ which happens to use the words someone with this problem would search for.
191
+ - **Be honest about the size of the prize.** On a small repository these titles win long-tail
192
+ queries. That makes the work worth doing and never worth distorting a title for.
193
+
194
+ `SSR hydration bug in the DS button` becomes
195
+ `Design system button loses its click handler after server-side rendering`. The second expands the
196
+ shorthand nobody searches for, keeps the words that place the problem, and adds nothing that is
197
+ untrue of the bug.
198
+
199
+ On a private repository the audience is the team, and all of this reduces to one rule. Say what the
200
+ problem is in plain words.
201
+
202
+ ## Filing the issue
203
+
204
+ Only once the user has explicitly asked.
205
+
206
+ Write the body to a file and pass it with `--body-file`, so quoting and backticks survive intact:
207
+
208
+ ```bash
209
+ gh issue create --repo <owner>/<repo> --title "<title>" --body-file <path> --label <label>
210
+ ```
211
+
212
+ **Do not hard-wrap the body.** This is the one formatting trap. GitHub renders issue and comment
213
+ Markdown with the GFM hard-line-break extension, so every newline inside a paragraph becomes a
214
+ `<br>`. A repository whose prose style wraps at 80 or 100 columns will produce visibly ragged output
215
+ when that habit reaches an issue body. Write each paragraph and each list item as one long line.
216
+ Blank lines between blocks still separate paragraphs, and code fences and list structure are
217
+ unaffected.
218
+
219
+ **Labels.** Read `gh label list` and pick from what exists. A label passed to `gh` that the
220
+ repository lacks fails the whole command.
221
+
222
+ **Type,** where the organisation has issue types configured. `--type` takes one of them (`Bug`,
223
+ `Feature` and `Task` are the GitHub defaults). Its value is in-repo filtering and a readable issue
224
+ list. Where the flag or the type is rejected, drop it and carry on.
225
+
226
+ **Think before applying `good first issue` or `help wanted`.** GitHub surfaces both in its
227
+ contributor-discovery UI, and third-party sites scrape them to list approachable open-source work.
228
+ For a project actively recruiting contributors that is the point. For a solo maintainer it invites
229
+ drive-by pull requests that cost more to review than they return. `CONTRIBUTING.md` and the existing
230
+ issues usually say which kind of project this is. Where it stays unclear, leave both off and mention
231
+ it.
232
+
233
+ **Skip Projects and date fields** unless the user asks for them. They are planning tools with
234
+ recurring upkeep and no search benefit. Milestones are the lighter option for grouping.
235
+
236
+ Where several issues came out of one note, file them in dependency order and put each preceding URL
237
+ into the issue that depends on it.
238
+
239
+ After filing, report the URL and state plainly which type and labels were applied.
240
+
241
+ ## Revisiting existing issues
242
+
243
+ The same thinking applies to issues that already exist, whether retitling or backfilling a missing
244
+ type or label. Closed issues are worth including. They stay indexed, and a closed issue describing a
245
+ capability that now exists is often exactly what a searcher wants.
246
+
247
+ Retitling is cheap and low-risk (the URL survives, GitHub keeps the edit history, nobody gets
248
+ notified) and it is still a public edit. Propose the full set in chat and get an explicit go-ahead
249
+ before running any `gh issue edit`. A table of current against proposed makes the set easy to scan
250
+ and easy to reject one row at a time.
251
+
252
+ Two things to watch in bulk:
253
+
254
+ - **A run of near-identical titles is a real cost.** One formula applied across five issues makes
255
+ the list scannable and reads as a deliberate series. A shared long prefix is also the first thing
256
+ a sceptical reader notices. Accept it where the issues genuinely are one series, and vary the
257
+ phrasing on a couple where the run gets long.
258
+ - **The bodies are usually the bigger win.** The opening paragraph becomes the search snippet, so a
259
+ retitled issue still opening with internal shorthand has had half the job done. Rewriting the
260
+ first sentence of **Problem** often beats the title edit.