nemo-cli 0.0.1__tar.gz → 0.1.0__tar.gz
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.
- nemo_cli-0.1.0/.claude/skills/close-session/SKILL.md +37 -0
- nemo_cli-0.1.0/.claude/skills/issue-new/SKILL.md +63 -0
- nemo_cli-0.1.0/.claude/skills/issue-start/SKILL.md +39 -0
- nemo_cli-0.1.0/.claude/skills/review-pr/SKILL.md +115 -0
- {nemo_cli-0.0.1 → nemo_cli-0.1.0}/.claude/skills/start-session/SKILL.md +14 -0
- {nemo_cli-0.0.1 → nemo_cli-0.1.0}/.claude/skills/validate-context/SKILL.md +10 -2
- nemo_cli-0.1.0/.github/ISSUE_TEMPLATE/bug_report.md +29 -0
- nemo_cli-0.1.0/.github/ISSUE_TEMPLATE/config.yml +5 -0
- nemo_cli-0.1.0/.github/ISSUE_TEMPLATE/feature_request.md +23 -0
- nemo_cli-0.1.0/.github/ISSUE_TEMPLATE/work-unit.md +44 -0
- nemo_cli-0.1.0/.github/PULL_REQUEST_TEMPLATE.md +43 -0
- nemo_cli-0.1.0/.github/workflows/ci.yml +170 -0
- {nemo_cli-0.0.1 → nemo_cli-0.1.0}/.github/workflows/publish.yml +5 -5
- {nemo_cli-0.0.1 → nemo_cli-0.1.0}/CHANGELOG.md +41 -1
- {nemo_cli-0.0.1 → nemo_cli-0.1.0}/CLAUDE.md +36 -22
- nemo_cli-0.1.0/CONTRIBUTING.md +47 -0
- {nemo_cli-0.0.1 → nemo_cli-0.1.0}/PKG-INFO +50 -42
- {nemo_cli-0.0.1 → nemo_cli-0.1.0}/README.md +48 -40
- nemo_cli-0.1.0/SECURITY.md +50 -0
- {nemo_cli-0.0.1 → nemo_cli-0.1.0}/docs/ARCHITECTURE.md +25 -17
- {nemo_cli-0.0.1 → nemo_cli-0.1.0}/docs/CONVENTIONS.md +49 -14
- {nemo_cli-0.0.1 → nemo_cli-0.1.0}/docs/STACK.md +7 -6
- {nemo_cli-0.0.1 → nemo_cli-0.1.0}/docs/decisions/005-github-flow-branching.md +5 -3
- nemo_cli-0.1.0/docs/decisions/013-adr-before-implementing.md +60 -0
- nemo_cli-0.1.0/docs/decisions/014-english-as-context-language.md +54 -0
- nemo_cli-0.1.0/docs/decisions/015-skills-over-slash-commands.md +59 -0
- nemo_cli-0.1.0/docs/decisions/016-document-corrections-not-fixes.md +52 -0
- nemo_cli-0.1.0/docs/decisions/017-atomic-task-instructions.md +58 -0
- nemo_cli-0.1.0/docs/decisions/018-session-close-ritual.md +59 -0
- nemo_cli-0.1.0/docs/decisions/019-short-sessions-over-long.md +59 -0
- nemo_cli-0.1.0/docs/decisions/020-pr-review-against-context.md +63 -0
- nemo_cli-0.1.0/docs/decisions/021-work-units-external-tracker.md +75 -0
- nemo_cli-0.1.0/docs/decisions/022-no-ai-attribution.md +55 -0
- nemo_cli-0.1.0/docs/decisions/023-continuous-integration.md +62 -0
- nemo_cli-0.1.0/docs/decisions/024-repository-governance.md +64 -0
- nemo_cli-0.1.0/docs/decisions/025-interactive-login.md +85 -0
- nemo_cli-0.1.0/docs/decisions/026-auth-session-layer.md +74 -0
- nemo_cli-0.1.0/docs/decisions/027-auth-command-group.md +63 -0
- nemo_cli-0.1.0/docs/decisions/_index.md +42 -0
- nemo_cli-0.1.0/docs/session-flow.md +145 -0
- {nemo_cli-0.0.1 → nemo_cli-0.1.0}/pyproject.toml +2 -2
- nemo_cli-0.1.0/src/nemo_cli/__init__.py +1 -0
- nemo_cli-0.1.0/src/nemo_cli/api/client.py +77 -0
- {nemo_cli-0.0.1 → nemo_cli-0.1.0}/src/nemo_cli/auth/jwt.py +5 -0
- {nemo_cli-0.0.1 → nemo_cli-0.1.0}/src/nemo_cli/auth/service.py +9 -4
- nemo_cli-0.1.0/src/nemo_cli/auth/session.py +50 -0
- {nemo_cli-0.0.1 → nemo_cli-0.1.0}/src/nemo_cli/cli.py +2 -6
- nemo_cli-0.1.0/src/nemo_cli/commands/auth.py +22 -0
- nemo_cli-0.1.0/src/nemo_cli/commands/login.py +27 -0
- nemo_cli-0.1.0/src/nemo_cli/commands/status.py +29 -0
- nemo_cli-0.1.0/src/nemo_cli/config.py +1 -0
- {nemo_cli-0.0.1 → nemo_cli-0.1.0}/tests/api/test_client.py +48 -109
- {nemo_cli-0.0.1 → nemo_cli-0.1.0}/tests/auth/test_service.py +19 -36
- nemo_cli-0.1.0/tests/auth/test_session.py +62 -0
- nemo_cli-0.1.0/tests/commands/test_auth_commands.py +111 -0
- {nemo_cli-0.0.1 → nemo_cli-0.1.0}/tests/conftest.py +24 -11
- {nemo_cli-0.0.1 → nemo_cli-0.1.0}/tests/test_cli.py +2 -2
- nemo_cli-0.1.0/tests/test_config.py +10 -0
- nemo_cli-0.0.1/.env.example +0 -2
- nemo_cli-0.0.1/docs/decisions/_index.md +0 -15
- nemo_cli-0.0.1/src/nemo_cli/__init__.py +0 -1
- nemo_cli-0.0.1/src/nemo_cli/api/client.py +0 -81
- nemo_cli-0.0.1/src/nemo_cli/commands/login.py +0 -15
- nemo_cli-0.0.1/src/nemo_cli/commands/whoami.py +0 -18
- nemo_cli-0.0.1/src/nemo_cli/config.py +0 -24
- nemo_cli-0.0.1/tests/commands/test_auth_commands.py +0 -99
- nemo_cli-0.0.1/tests/test_config.py +0 -85
- {nemo_cli-0.0.1 → nemo_cli-0.1.0}/.claude/skills/new-decision/SKILL.md +0 -0
- {nemo_cli-0.0.1 → nemo_cli-0.1.0}/.claude/skills/status/SKILL.md +0 -0
- {nemo_cli-0.0.1 → nemo_cli-0.1.0}/.gitignore +0 -0
- {nemo_cli-0.0.1 → nemo_cli-0.1.0}/LICENSE +0 -0
- {nemo_cli-0.0.1 → nemo_cli-0.1.0}/context-first-development.md +0 -0
- {nemo_cli-0.0.1 → nemo_cli-0.1.0}/docs/decisions/001-initial-architecture.md +0 -0
- {nemo_cli-0.0.1 → nemo_cli-0.1.0}/docs/decisions/002-tech-stack.md +0 -0
- {nemo_cli-0.0.1 → nemo_cli-0.1.0}/docs/decisions/003-token-authentication.md +0 -0
- {nemo_cli-0.0.1 → nemo_cli-0.1.0}/docs/decisions/004-switch-to-python-stack.md +0 -0
- {nemo_cli-0.0.1 → nemo_cli-0.1.0}/docs/decisions/006-instruments-domain.md +0 -0
- {nemo_cli-0.0.1 → nemo_cli-0.1.0}/docs/decisions/007-versioning-and-changelog.md +0 -0
- {nemo_cli-0.0.1 → nemo_cli-0.1.0}/docs/decisions/008-portfolio-domain.md +0 -0
- {nemo_cli-0.0.1 → nemo_cli-0.1.0}/docs/decisions/010-instrument-price-history.md +0 -0
- {nemo_cli-0.0.1 → nemo_cli-0.1.0}/docs/decisions/011-portfolio-movements.md +0 -0
- {nemo_cli-0.0.1 → nemo_cli-0.1.0}/docs/decisions/012-refresh-token-flow.md +0 -0
- {nemo_cli-0.0.1 → nemo_cli-0.1.0}/scripts/verify_reactive_fallback.py +0 -0
- {nemo_cli-0.0.1 → nemo_cli-0.1.0}/scripts/verify_refresh.py +0 -0
- {nemo_cli-0.0.1 → nemo_cli-0.1.0}/src/nemo_cli/__main__.py +0 -0
- {nemo_cli-0.0.1 → nemo_cli-0.1.0}/src/nemo_cli/api/__init__.py +0 -0
- {nemo_cli-0.0.1 → nemo_cli-0.1.0}/src/nemo_cli/auth/__init__.py +0 -0
- {nemo_cli-0.0.1 → nemo_cli-0.1.0}/src/nemo_cli/auth/token_store.py +0 -0
- {nemo_cli-0.0.1 → nemo_cli-0.1.0}/src/nemo_cli/commands/__init__.py +0 -0
- {nemo_cli-0.0.1 → nemo_cli-0.1.0}/src/nemo_cli/commands/instruments.py +0 -0
- {nemo_cli-0.0.1 → nemo_cli-0.1.0}/src/nemo_cli/commands/logout.py +0 -0
- {nemo_cli-0.0.1 → nemo_cli-0.1.0}/src/nemo_cli/commands/portfolio.py +0 -0
- {nemo_cli-0.0.1 → nemo_cli-0.1.0}/src/nemo_cli/instruments/__init__.py +0 -0
- {nemo_cli-0.0.1 → nemo_cli-0.1.0}/src/nemo_cli/instruments/international.py +0 -0
- {nemo_cli-0.0.1 → nemo_cli-0.1.0}/src/nemo_cli/instruments/local.py +0 -0
- {nemo_cli-0.0.1 → nemo_cli-0.1.0}/src/nemo_cli/instruments/prices.py +0 -0
- {nemo_cli-0.0.1 → nemo_cli-0.1.0}/src/nemo_cli/portfolio/__init__.py +0 -0
- {nemo_cli-0.0.1 → nemo_cli-0.1.0}/src/nemo_cli/portfolio/movements.py +0 -0
- {nemo_cli-0.0.1 → nemo_cli-0.1.0}/src/nemo_cli/portfolio/summary.py +0 -0
- {nemo_cli-0.0.1 → nemo_cli-0.1.0}/tests/__init__.py +0 -0
- {nemo_cli-0.0.1 → nemo_cli-0.1.0}/tests/api/__init__.py +0 -0
- {nemo_cli-0.0.1 → nemo_cli-0.1.0}/tests/auth/__init__.py +0 -0
- {nemo_cli-0.0.1 → nemo_cli-0.1.0}/tests/auth/test_jwt.py +0 -0
- {nemo_cli-0.0.1 → nemo_cli-0.1.0}/tests/auth/test_token_store.py +0 -0
- {nemo_cli-0.0.1 → nemo_cli-0.1.0}/tests/commands/__init__.py +0 -0
- {nemo_cli-0.0.1 → nemo_cli-0.1.0}/tests/commands/test_instruments_commands.py +0 -0
- {nemo_cli-0.0.1 → nemo_cli-0.1.0}/tests/commands/test_portfolio_commands.py +0 -0
- {nemo_cli-0.0.1 → nemo_cli-0.1.0}/tests/instruments/__init__.py +0 -0
- {nemo_cli-0.0.1 → nemo_cli-0.1.0}/tests/instruments/test_international.py +0 -0
- {nemo_cli-0.0.1 → nemo_cli-0.1.0}/tests/instruments/test_local.py +0 -0
- {nemo_cli-0.0.1 → nemo_cli-0.1.0}/tests/instruments/test_prices.py +0 -0
- {nemo_cli-0.0.1 → nemo_cli-0.1.0}/tests/portfolio/__init__.py +0 -0
- {nemo_cli-0.0.1 → nemo_cli-0.1.0}/tests/portfolio/test_movements.py +0 -0
- {nemo_cli-0.0.1 → nemo_cli-0.1.0}/tests/portfolio/test_summary.py +0 -0
|
@@ -0,0 +1,37 @@
|
|
|
1
|
+
---
|
|
2
|
+
description: Close a CFD session by running the non-negotiable session-close ritual — update docs/CURRENT_STATUS.md, capture any clarified convention or informal decision, and produce a PR-ready summary. Use when the user says "close session", "wrap up", "we're done for today", or invokes the CFD session-close ritual. Implements ADR-018.
|
|
3
|
+
---
|
|
4
|
+
|
|
5
|
+
Run the Context-First Development session-close ritual (ADR-018). This is
|
|
6
|
+
**non-negotiable** — a session that ends without step 1 leaves the next session
|
|
7
|
+
with stale context. Do all of the following, in order:
|
|
8
|
+
|
|
9
|
+
1. **Update `docs/CURRENT_STATUS.md`:**
|
|
10
|
+
- Move completed items from "In Progress" to "Recently Completed".
|
|
11
|
+
- Add anything still pending or newly surfaced this session.
|
|
12
|
+
- Update "Known Issues / Open Questions" if anything new appeared.
|
|
13
|
+
- Re-rank "Next Priorities".
|
|
14
|
+
- Update the "Last updated" date to today.
|
|
15
|
+
- If work was tracked as a GitHub issue (ADR-021), reference it by `#N`.
|
|
16
|
+
|
|
17
|
+
2. **Update `docs/CONVENTIONS.md`** if any convention was clarified or a pattern
|
|
18
|
+
was corrected this session (ADR-016). Do not leave corrections only in chat
|
|
19
|
+
history — they will be lost next session.
|
|
20
|
+
|
|
21
|
+
3. **If a significant decision was made informally** (in chat, in passing),
|
|
22
|
+
propose creating an ADR via the `new-decision` skill before closing
|
|
23
|
+
(ADR-013). Do not let an implicit decision ship undocumented.
|
|
24
|
+
|
|
25
|
+
4. **Ship `docs/` context changes in the same commit/PR as the session's code.**
|
|
26
|
+
Exception specific to this project: `docs/CURRENT_STATUS.md` is local-only
|
|
27
|
+
(gitignored), so it is updated locally every session but never travels in a
|
|
28
|
+
PR — only `CONVENTIONS.md` and ADRs do.
|
|
29
|
+
|
|
30
|
+
Do **not** end the session without completing step 1.
|
|
31
|
+
|
|
32
|
+
After completing the ritual, output a one-paragraph session summary suitable for
|
|
33
|
+
pasting into a PR description (Spanish is fine here per ADR-014 — PR descriptions
|
|
34
|
+
are not reloaded into context).
|
|
35
|
+
|
|
36
|
+
If a PR was opened from this session, the natural next step is the `review-pr`
|
|
37
|
+
skill — it cross-checks the diff against the project's checklist (ADR-020).
|
|
@@ -0,0 +1,63 @@
|
|
|
1
|
+
---
|
|
2
|
+
description: Create a self-sufficient nemo-cli unit of work as a GitHub Issue with the fixed CFD body template (Context, Target, ADRs to load, Acceptance criteria, Reproduction, Estimated sessions). Use when the user asks to "open an issue", "create a work item", "plan a task", or describes new work to be tracked. Implements ADR-021.
|
|
3
|
+
---
|
|
4
|
+
|
|
5
|
+
Guide the user through creating a GitHub Issue with the fixed body template from
|
|
6
|
+
ADR-021. The completeness of this issue determines how cheaply the next session
|
|
7
|
+
starts — be thorough here. Ask, in order, and confirm each answer:
|
|
8
|
+
|
|
9
|
+
1. **Type.** `feature` | `fix` | `chore` | `spike` | `docs`.
|
|
10
|
+
2. **Title.** Imperative, ≤ 80 chars, English (ADR-014). e.g. "Add `nemo
|
|
11
|
+
portfolio export` command".
|
|
12
|
+
3. **Context.** 2–4 sentences: the trigger and the user-visible outcome.
|
|
13
|
+
4. **Target location.** Concrete paths. For a new subcommand, name the module
|
|
14
|
+
and proposed file (e.g. `src/nemo_cli/commands/<verb>.py` — new file —
|
|
15
|
+
registered in `src/nemo_cli/cli.py`).
|
|
16
|
+
5. **Pattern to mirror.** An existing file the implementation should copy in
|
|
17
|
+
shape and naming (e.g. `src/nemo_cli/commands/instruments.py`). Flag
|
|
18
|
+
explicitly if no analog exists.
|
|
19
|
+
6. **ADRs to load.** ADR numbers the agent must read first. If a needed decision
|
|
20
|
+
is not yet an ADR, **STOP and run the `new-decision` skill** — implementing
|
|
21
|
+
an undocumented decision is forbidden by ADR-013.
|
|
22
|
+
7. **Acceptance criteria (DoD).** Markdown `[ ]` items covering all three of:
|
|
23
|
+
behaviour at the end, tests (kind + location under `tests/` mirroring the
|
|
24
|
+
package tree, `respx`/`CliRunner` per CONVENTIONS, coverage ≥ 95%), and docs
|
|
25
|
+
updated (CONVENTIONS, ADRs, README, CHANGELOG per ADR-007).
|
|
26
|
+
8. **Reproduction steps.** `fix` only — a minimal repro the agent can run.
|
|
27
|
+
9. **Estimated sessions.** `1` | `2–3` | `4+`. If > 1, **propose decomposing
|
|
28
|
+
into sub-issues before continuing** (ADR-019).
|
|
29
|
+
10. **Labels.** The type plus any component (`auth`, `instruments`, `portfolio`,
|
|
30
|
+
`api`, `ci`, …).
|
|
31
|
+
|
|
32
|
+
Then generate the body using the fixed template — do not change section order or
|
|
33
|
+
names; `issue-start` parses by header:
|
|
34
|
+
|
|
35
|
+
```markdown
|
|
36
|
+
## Context
|
|
37
|
+
<step 3>
|
|
38
|
+
|
|
39
|
+
## Target
|
|
40
|
+
- Files / dirs: <step 4>
|
|
41
|
+
- Pattern to mirror: <step 5>
|
|
42
|
+
|
|
43
|
+
## ADRs to load
|
|
44
|
+
- [ADR-NNN](docs/decisions/NNN-*.md)
|
|
45
|
+
|
|
46
|
+
## Acceptance criteria
|
|
47
|
+
- [ ] <step 7>
|
|
48
|
+
|
|
49
|
+
## Reproduction (fixes only)
|
|
50
|
+
<step 8 — OR omit this section entirely if not a fix>
|
|
51
|
+
|
|
52
|
+
## Estimated sessions
|
|
53
|
+
<step 9>
|
|
54
|
+
```
|
|
55
|
+
|
|
56
|
+
Then create it:
|
|
57
|
+
|
|
58
|
+
```bash
|
|
59
|
+
gh issue create --title "<step 2>" --body "<body above>" --label "<type>,<labels>"
|
|
60
|
+
```
|
|
61
|
+
|
|
62
|
+
Output the issue URL when done. English for the issue body (ADR-014); the issue
|
|
63
|
+
comment thread may be Spanish.
|
|
@@ -0,0 +1,39 @@
|
|
|
1
|
+
---
|
|
2
|
+
description: Pick up a nemo-cli GitHub Issue as the focus of this session — fetch it, parse its fixed CFD sections, pre-load the ADRs it names, skim the pattern to mirror, and summarize the objective and acceptance checklist without scanning target files. Use when the user says "start issue", "work on #N", "pick up", or passes an issue number. Implements ADR-021.
|
|
3
|
+
---
|
|
4
|
+
|
|
5
|
+
Pick up a tracker issue as this session's focus (ADR-021). Orient from the issue
|
|
6
|
+
body and its ADRs — do not scan code at this step.
|
|
7
|
+
|
|
8
|
+
1. **Fetch the issue.** The user passes a number; if not, ask which.
|
|
9
|
+
|
|
10
|
+
```bash
|
|
11
|
+
gh issue view <n>
|
|
12
|
+
```
|
|
13
|
+
|
|
14
|
+
2. **Parse the fixed sections** (ADR-021): `Context`, `Target`, `ADRs to load`,
|
|
15
|
+
`Acceptance criteria`, `Reproduction` (fixes only), `Estimated sessions`. If
|
|
16
|
+
a required section is missing, **STOP** — tell the user the issue is
|
|
17
|
+
malformed and propose fixing it via `gh issue edit <n>`. Do not infer.
|
|
18
|
+
|
|
19
|
+
3. **Read each ADR listed in `ADRs to load`** from `docs/decisions/`. These set
|
|
20
|
+
the constraints the implementation must satisfy.
|
|
21
|
+
|
|
22
|
+
4. **Read the `Pattern to mirror` file ONCE for shape.** Skim, don't study — the
|
|
23
|
+
goal is to know what the produced code should look like.
|
|
24
|
+
|
|
25
|
+
5. **Do NOT read the `Target` files yet.** They are where the work *goes*, not
|
|
26
|
+
where context comes *from*; reading them now is wasted tokens.
|
|
27
|
+
|
|
28
|
+
6. **Summarize for the user:**
|
|
29
|
+
- **Objective** (one line, from `Context`).
|
|
30
|
+
- **Acceptance checklist** (verbatim from `Acceptance criteria` — the DoD).
|
|
31
|
+
- **ADRs loaded** and what each constrains.
|
|
32
|
+
- **Target paths** you will write to.
|
|
33
|
+
- **Pattern to mirror.**
|
|
34
|
+
|
|
35
|
+
7. Ask: **"Ready to start?"** If `Estimated sessions` > 1, remind the user the
|
|
36
|
+
issue should be decomposed and offer to split it via `issue-new` (ADR-019).
|
|
37
|
+
|
|
38
|
+
**Token discipline:** the issue body + ADRs are the spec. Code reading happens
|
|
39
|
+
when implementation starts, not during orientation.
|
|
@@ -0,0 +1,115 @@
|
|
|
1
|
+
---
|
|
2
|
+
description: Review a nemo-cli Pull Request against the project's curated checklist — sourced from the ADRs, CONVENTIONS.md, and any linked issue's acceptance criteria — instead of re-discovering intent from code. Use when the user asks to "review PR", "review this branch", "check my PR", or passes a PR number. Implements ADR-020.
|
|
3
|
+
---
|
|
4
|
+
|
|
5
|
+
Review a PR against the project's context (ADR-020), not by re-discovering its
|
|
6
|
+
intent from code. The agenda comes from the indices; read source to the depth
|
|
7
|
+
the checklist demands.
|
|
8
|
+
|
|
9
|
+
## 1. Identify the PR
|
|
10
|
+
|
|
11
|
+
The user passes a PR number. If not, infer from the current branch:
|
|
12
|
+
|
|
13
|
+
```bash
|
|
14
|
+
gh pr status --json number --jq '.currentBranch.number'
|
|
15
|
+
```
|
|
16
|
+
|
|
17
|
+
If still none, ask.
|
|
18
|
+
|
|
19
|
+
## 2. Fetch PR metadata + diff + commit story
|
|
20
|
+
|
|
21
|
+
```bash
|
|
22
|
+
gh pr view <n> --json baseRefName,headRefName,title,body,labels,commits,closingIssuesReferences
|
|
23
|
+
gh pr diff <n>
|
|
24
|
+
git log <base>..<head> --pretty=format:%s
|
|
25
|
+
```
|
|
26
|
+
|
|
27
|
+
## 3. Load the agenda
|
|
28
|
+
|
|
29
|
+
- `docs/CONVENTIONS.md`
|
|
30
|
+
- `docs/decisions/_index.md`, plus every ADR named in the PR body or a linked
|
|
31
|
+
issue.
|
|
32
|
+
- The linked issue body via `gh issue view <issue-n>` if one exists (ADR-021):
|
|
33
|
+
extract the acceptance-criteria checklist and the "ADRs to load" list.
|
|
34
|
+
- `.github/PULL_REQUEST_TEMPLATE.md` if present.
|
|
35
|
+
|
|
36
|
+
## 4. Read changed files to the depth the agenda demands
|
|
37
|
+
|
|
38
|
+
For nemo-cli this means **reading changed source files in full** — strict
|
|
39
|
+
`pyright` and the `api_request()` boundary rule require verifying call sites,
|
|
40
|
+
types, and that no handler or service calls `httpx` directly. This is
|
|
41
|
+
verification against known rules, not discovery.
|
|
42
|
+
|
|
43
|
+
## 5. Apply the checklist
|
|
44
|
+
|
|
45
|
+
### Workflow (ADR-005, ADR-014)
|
|
46
|
+
|
|
47
|
+
- Branch name follows `<type>/<slug>` (`feat`/`fix`/`docs`/`chore`/`refactor`/`test`).
|
|
48
|
+
- Base branch is `main`; merge will be a squash with a Conventional-Commits title.
|
|
49
|
+
- PR title is Conventional Commits and English.
|
|
50
|
+
- PR body references `Closes #<n>` when an issue exists (ADR-021).
|
|
51
|
+
- **No AI-attribution metadata** anywhere — no `Co-Authored-By:` trailer and no
|
|
52
|
+
"Generated with …" line, in any commit or the PR body (ADR-022). Flag any that
|
|
53
|
+
appear.
|
|
54
|
+
|
|
55
|
+
### HTTP boundary (ADR-003, critical rule)
|
|
56
|
+
|
|
57
|
+
- All Vector-portal HTTP goes through `api_request()` in
|
|
58
|
+
`src/nemo_cli/api/client.py`. No `httpx.request(...)` in command handlers or
|
|
59
|
+
services. Only allowed exception: `nemo_cli.auth.service.sign_in`.
|
|
60
|
+
- Endpoint paths passed to `api_request()` are relative (e.g. `/shared/...`).
|
|
61
|
+
- A new slow endpoint overrides `timeout=` at the service layer and adds a row
|
|
62
|
+
to the Timeouts table in `CONVENTIONS.md` — the global default is unchanged.
|
|
63
|
+
|
|
64
|
+
### Conventions (CONVENTIONS.md)
|
|
65
|
+
|
|
66
|
+
- Only `nemo_cli.config` reads `os.environ`.
|
|
67
|
+
- Imports are absolute; new subcommand = one module exporting one verb function,
|
|
68
|
+
registered in `cli.py`.
|
|
69
|
+
- Response shapes are typed at the call site (TypedDict/dataclass), not in a
|
|
70
|
+
global types module.
|
|
71
|
+
- Errors: command handlers print a red one-line message to stderr and raise
|
|
72
|
+
`typer.Exit(code=1)`; library code raises `RuntimeError`.
|
|
73
|
+
- A `--json` flag, when added, echoes the request scope + typed result.
|
|
74
|
+
|
|
75
|
+
### Types
|
|
76
|
+
|
|
77
|
+
- `pyright` strict passes; explicit return types on public functions; PEP-604
|
|
78
|
+
unions (`str | None`); no `Any`.
|
|
79
|
+
|
|
80
|
+
### Testing (CONVENTIONS.md)
|
|
81
|
+
|
|
82
|
+
- HTTP mocked via `respx`; CLI tested via `CliRunner`; tests mirror the package
|
|
83
|
+
tree; private helpers tested directly; coverage stays ≥ 95%.
|
|
84
|
+
|
|
85
|
+
### Decisions & docs drift
|
|
86
|
+
|
|
87
|
+
- Any new significant decision has an ADR in this PR (ADR-013); `_index.md`
|
|
88
|
+
updated.
|
|
89
|
+
- A clarified convention is captured in `CONVENTIONS.md` (ADR-016).
|
|
90
|
+
- A user-facing change has a `CHANGELOG.md` entry (ADR-007).
|
|
91
|
+
- Each acceptance-criteria `[ ]` from the linked issue is implemented; no
|
|
92
|
+
out-of-scope changes.
|
|
93
|
+
|
|
94
|
+
## 6. Output a structured review
|
|
95
|
+
|
|
96
|
+
```text
|
|
97
|
+
## Critical (must fix before merge)
|
|
98
|
+
- <file>:<line> — <issue> — citation: <ADR-N / CONVENTIONS line>. Suggested fix: <…>.
|
|
99
|
+
|
|
100
|
+
## Suggestions (should fix)
|
|
101
|
+
- <file>:<line> — <issue> — citation.
|
|
102
|
+
|
|
103
|
+
## Nits
|
|
104
|
+
- <file>:<line> — <issue>.
|
|
105
|
+
|
|
106
|
+
## Summary
|
|
107
|
+
- Overall assessment, AC coverage X/Y, architecture compliance ✓/⚠/✗.
|
|
108
|
+
```
|
|
109
|
+
|
|
110
|
+
## Rules
|
|
111
|
+
|
|
112
|
+
- **Do NOT auto-fix.** Report only; the author fixes next session.
|
|
113
|
+
- If the checklist needs a rule not yet in an ADR or `CONVENTIONS.md`, surface
|
|
114
|
+
it as a finding ("missing convention for X") and propose `new-decision` — do
|
|
115
|
+
not silently invent it.
|
|
@@ -8,10 +8,24 @@ files, in order, and do not scan source code unless a follow-up question require
|
|
|
8
8
|
1. `docs/CURRENT_STATUS.md` — what is in progress, what is blocked, what is next.
|
|
9
9
|
2. `docs/decisions/_index.md` — recent decisions that may affect the next change.
|
|
10
10
|
|
|
11
|
+
3. **If `CURRENT_STATUS.md` references in-progress work by issue number** (e.g.
|
|
12
|
+
`#142`), load that unit of work (ADR-021):
|
|
13
|
+
|
|
14
|
+
```bash
|
|
15
|
+
gh issue view <n>
|
|
16
|
+
```
|
|
17
|
+
|
|
18
|
+
Then read each ADR the issue lists under "ADRs to load" from
|
|
19
|
+
`docs/decisions/`. Do **not** read the files in the issue's "Target" section —
|
|
20
|
+
those are where the work goes, not where context comes from. If no issue is
|
|
21
|
+
referenced, skip this step and orient from `CURRENT_STATUS.md` alone.
|
|
22
|
+
|
|
11
23
|
Then produce a brief (≤ 8 lines) summary covering:
|
|
12
24
|
|
|
13
25
|
- What was being worked on in the previous session.
|
|
14
26
|
- What is currently blocked and why.
|
|
27
|
+
- The objective and acceptance checklist of the in-progress issue, if one was
|
|
28
|
+
loaded in step 3.
|
|
15
29
|
- What the next priority should be, based on `CURRENT_STATUS.md` and any open
|
|
16
30
|
questions noted there.
|
|
17
31
|
|
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
---
|
|
2
|
-
description: Audit CFD context-file integrity — verify CLAUDE.md size, @-references resolve, ADR index consistency, no duplicated context, and CURRENT_STATUS.md freshness. Use when the user asks to "validate context", "audit docs", or check whether the CFD scaffolding is healthy.
|
|
2
|
+
description: Audit CFD context-file integrity — verify CLAUDE.md size, @-references resolve, ADR index consistency, no duplicated context, English-only model context, skill-set consistency, and CURRENT_STATUS.md freshness. Use when the user asks to "validate context", "audit docs", or check whether the CFD scaffolding is healthy.
|
|
3
3
|
---
|
|
4
4
|
|
|
5
5
|
Run a CFD context-integrity check. Do not modify files; just report findings.
|
|
@@ -18,7 +18,15 @@ Checks to perform:
|
|
|
18
18
|
`docs/STACK.md` only (not also expanded inside `CLAUDE.md` or `ARCHITECTURE.md`),
|
|
19
19
|
and that decision rationale is in the relevant ADR (not duplicated in
|
|
20
20
|
`ARCHITECTURE.md`).
|
|
21
|
-
5.
|
|
21
|
+
5. **English-only model context (ADR-014).** Spot-check that `CLAUDE.md` and
|
|
22
|
+
`docs/**/*.md` (including ADRs and `.claude/skills/**/SKILL.md`) are written in
|
|
23
|
+
English. Flag any model-facing file whose prose is predominantly another
|
|
24
|
+
language. (PR descriptions and chat are exempt — they are not in this tree.)
|
|
25
|
+
6. **Skill-set consistency (ADR-015).** Every procedure listed in the
|
|
26
|
+
`docs/CONVENTIONS.md` "CFD workflow (Skills)" table has a matching
|
|
27
|
+
`.claude/skills/<name>/SKILL.md`, and every skill directory appears in that
|
|
28
|
+
table. Flag any mismatch in either direction.
|
|
29
|
+
7. **`CURRENT_STATUS.md` freshness.** Look at the `Last updated:` line. If it is
|
|
22
30
|
more than two working days behind today's date, flag it.
|
|
23
31
|
|
|
24
32
|
Output a short report grouped by check, with `✓` / `✗` and a one-line note for each.
|
|
@@ -0,0 +1,29 @@
|
|
|
1
|
+
---
|
|
2
|
+
name: Bug report
|
|
3
|
+
about: Something in nemo-cli behaves incorrectly
|
|
4
|
+
title: "fix: "
|
|
5
|
+
labels: [bug]
|
|
6
|
+
---
|
|
7
|
+
|
|
8
|
+
> ⚠️ **Never paste real credentials, bearer tokens, JWTs, RUTs, or real
|
|
9
|
+
> portfolio amounts.** Redact or use synthetic values.
|
|
10
|
+
|
|
11
|
+
## What happened
|
|
12
|
+
|
|
13
|
+
<!-- A clear description of the bug and the command you ran. -->
|
|
14
|
+
|
|
15
|
+
## Steps to reproduce
|
|
16
|
+
|
|
17
|
+
1. <!-- e.g. `nemo portfolio summary --json` -->
|
|
18
|
+
2.
|
|
19
|
+
|
|
20
|
+
## Expected vs. actual
|
|
21
|
+
|
|
22
|
+
- **Expected:**
|
|
23
|
+
- **Actual:** <!-- include the error message, redacted -->
|
|
24
|
+
|
|
25
|
+
## Environment
|
|
26
|
+
|
|
27
|
+
- `nemo --version`:
|
|
28
|
+
- Python version:
|
|
29
|
+
- OS:
|
|
@@ -0,0 +1,23 @@
|
|
|
1
|
+
---
|
|
2
|
+
name: Feature request
|
|
3
|
+
about: Suggest a new command, flag, or capability
|
|
4
|
+
title: "feat: "
|
|
5
|
+
labels: [enhancement]
|
|
6
|
+
---
|
|
7
|
+
|
|
8
|
+
## Problem
|
|
9
|
+
|
|
10
|
+
<!-- What are you trying to do that nemo-cli doesn't support today? -->
|
|
11
|
+
|
|
12
|
+
## Proposed solution
|
|
13
|
+
|
|
14
|
+
<!-- The command / flag / behaviour you'd like. e.g. a new subcommand,
|
|
15
|
+
a `--json` field, a new portal endpoint. -->
|
|
16
|
+
|
|
17
|
+
## Scope
|
|
18
|
+
|
|
19
|
+
<!-- Which domain does this touch? auth / instruments / portfolio / output / other -->
|
|
20
|
+
|
|
21
|
+
## Alternatives considered
|
|
22
|
+
|
|
23
|
+
<!-- Workarounds you've tried or other approaches. -->
|
|
@@ -0,0 +1,44 @@
|
|
|
1
|
+
---
|
|
2
|
+
name: Work unit (maintainer)
|
|
3
|
+
about: Internal maintainer work unit (per ADR-021). Contributors — use Bug report or Feature request instead.
|
|
4
|
+
title: ""
|
|
5
|
+
labels: []
|
|
6
|
+
---
|
|
7
|
+
|
|
8
|
+
<!-- Do NOT delete any section. The `issue-start` skill parses by section header.
|
|
9
|
+
If a section truly does not apply (e.g. Reproduction on a feature),
|
|
10
|
+
remove ONLY that section. -->
|
|
11
|
+
|
|
12
|
+
## Context
|
|
13
|
+
|
|
14
|
+
<!-- 2–4 sentences: what is the trigger, what is the user-visible outcome. -->
|
|
15
|
+
|
|
16
|
+
## Target
|
|
17
|
+
|
|
18
|
+
- Files / dirs: <!-- concrete paths; mark `new file` if net-new -->
|
|
19
|
+
- Pattern to mirror: <!-- existing file the implementation should mirror in shape/naming, e.g. src/nemo_cli/portfolio/summary.py -->
|
|
20
|
+
|
|
21
|
+
## ADRs to load
|
|
22
|
+
|
|
23
|
+
<!-- ADR numbers the agent must read before starting. Link each one. -->
|
|
24
|
+
|
|
25
|
+
- [ADR-NNN](docs/decisions/NNN-*.md)
|
|
26
|
+
|
|
27
|
+
## Acceptance criteria
|
|
28
|
+
|
|
29
|
+
<!-- Definition of Done — reused verbatim in the PR description. -->
|
|
30
|
+
|
|
31
|
+
- [ ] <!-- Behavior: what works at the end (concrete CLI output / library API) -->
|
|
32
|
+
- [ ] <!-- Tests: which tests/ files exist; respx-mocked, no real network -->
|
|
33
|
+
- [ ] <!-- Documentation: which of CONVENTIONS / STACK / ARCHITECTURE / CHANGELOG / new ADR is updated -->
|
|
34
|
+
|
|
35
|
+
## Reproduction (fixes only)
|
|
36
|
+
|
|
37
|
+
<!-- ONLY for `fix` issues. Minimal repro the agent can run. Remove this
|
|
38
|
+
section entirely if not a fix. Never paste real credentials or RUTs. -->
|
|
39
|
+
|
|
40
|
+
## Estimated sessions
|
|
41
|
+
|
|
42
|
+
<!-- 1 | 2–3 | 4+. If > 1, decompose into sub-issues before starting (ADR-019). -->
|
|
43
|
+
|
|
44
|
+
1
|
|
@@ -0,0 +1,43 @@
|
|
|
1
|
+
<!-- Keep this template's sections — the `review-pr` skill (ADR-020) parses them. -->
|
|
2
|
+
|
|
3
|
+
## Summary
|
|
4
|
+
|
|
5
|
+
<!-- 1-3 sentences: what the PR changes and why. -->
|
|
6
|
+
|
|
7
|
+
## Linked issue
|
|
8
|
+
|
|
9
|
+
Closes #<!-- N -->
|
|
10
|
+
|
|
11
|
+
<!-- If no linked issue, replace this section with a justification.
|
|
12
|
+
Most non-trivial work should track an issue per ADR-021. -->
|
|
13
|
+
|
|
14
|
+
## Acceptance criteria
|
|
15
|
+
|
|
16
|
+
<!-- Copy verbatim from the issue body. Tick boxes as items land. -->
|
|
17
|
+
|
|
18
|
+
- [ ] <!-- behavior -->
|
|
19
|
+
- [ ] <!-- tests -->
|
|
20
|
+
- [ ] <!-- documentation -->
|
|
21
|
+
|
|
22
|
+
## ADRs touched
|
|
23
|
+
|
|
24
|
+
<!-- ADRs this PR depends on, supersedes, or amends. If you introduced a new
|
|
25
|
+
decision, link the new ADR file. If none, write "none". -->
|
|
26
|
+
|
|
27
|
+
- ADR-NNN
|
|
28
|
+
|
|
29
|
+
## Test plan
|
|
30
|
+
|
|
31
|
+
<!-- Concrete commands a reviewer can run. HTTP is respx-mocked; no real
|
|
32
|
+
network or real credentials, ever (CONVENTIONS.md § Testing). -->
|
|
33
|
+
|
|
34
|
+
```bash
|
|
35
|
+
pytest
|
|
36
|
+
ruff check .
|
|
37
|
+
pyright
|
|
38
|
+
```
|
|
39
|
+
|
|
40
|
+
## Notes for the reviewer
|
|
41
|
+
|
|
42
|
+
<!-- Anything non-obvious in the diff, deferred follow-ups, captured response
|
|
43
|
+
shapes for a new endpoint, etc. No AI-attribution footer in commits (ADR-022). -->
|
|
@@ -0,0 +1,170 @@
|
|
|
1
|
+
name: CI
|
|
2
|
+
|
|
3
|
+
on:
|
|
4
|
+
pull_request:
|
|
5
|
+
branches: [main]
|
|
6
|
+
push:
|
|
7
|
+
branches: [main]
|
|
8
|
+
|
|
9
|
+
permissions:
|
|
10
|
+
contents: read
|
|
11
|
+
|
|
12
|
+
concurrency:
|
|
13
|
+
group: ${{ github.workflow }}-${{ github.ref }}
|
|
14
|
+
cancel-in-progress: true
|
|
15
|
+
|
|
16
|
+
jobs:
|
|
17
|
+
tests:
|
|
18
|
+
name: Tests + Lint (py${{ matrix.python-version }})
|
|
19
|
+
runs-on: ubuntu-latest
|
|
20
|
+
strategy:
|
|
21
|
+
fail-fast: false
|
|
22
|
+
matrix:
|
|
23
|
+
python-version: ['3.11', '3.12', '3.13']
|
|
24
|
+
steps:
|
|
25
|
+
- uses: actions/checkout@df4cb1c069e1874edd31b4311f1884172cec0e10 # v6.0.3
|
|
26
|
+
|
|
27
|
+
- name: Set up Python ${{ matrix.python-version }}
|
|
28
|
+
uses: actions/setup-python@a309ff8b426b58ec0e2a45f0f869d46889d02405 # v6.2.0
|
|
29
|
+
with:
|
|
30
|
+
python-version: ${{ matrix.python-version }}
|
|
31
|
+
cache: pip
|
|
32
|
+
|
|
33
|
+
- name: Install (editable + dev extras)
|
|
34
|
+
run: python -m pip install --upgrade pip && pip install -e .[dev]
|
|
35
|
+
|
|
36
|
+
- name: pytest (coverage gate >= 95%)
|
|
37
|
+
run: pytest --cov=nemo_cli --cov-report=term-missing --cov-fail-under=95
|
|
38
|
+
|
|
39
|
+
- name: ruff check
|
|
40
|
+
run: ruff check .
|
|
41
|
+
|
|
42
|
+
types:
|
|
43
|
+
name: Types (pyright strict)
|
|
44
|
+
runs-on: ubuntu-latest
|
|
45
|
+
steps:
|
|
46
|
+
- uses: actions/checkout@df4cb1c069e1874edd31b4311f1884172cec0e10 # v6.0.3
|
|
47
|
+
|
|
48
|
+
- name: Set up Python
|
|
49
|
+
uses: actions/setup-python@a309ff8b426b58ec0e2a45f0f869d46889d02405 # v6.2.0
|
|
50
|
+
with:
|
|
51
|
+
python-version: '3.12'
|
|
52
|
+
cache: pip
|
|
53
|
+
|
|
54
|
+
- name: Install (editable + dev extras)
|
|
55
|
+
run: python -m pip install --upgrade pip && pip install -e .[dev]
|
|
56
|
+
|
|
57
|
+
- name: pyright
|
|
58
|
+
run: pyright
|
|
59
|
+
|
|
60
|
+
validate-context:
|
|
61
|
+
name: Validate context (ADRs + api_request boundary + PII)
|
|
62
|
+
runs-on: ubuntu-latest
|
|
63
|
+
steps:
|
|
64
|
+
- uses: actions/checkout@df4cb1c069e1874edd31b4311f1884172cec0e10 # v6.0.3
|
|
65
|
+
|
|
66
|
+
- name: ADR index integrity
|
|
67
|
+
# Every docs/decisions/NNN-*.md must be listed in _index.md, and every
|
|
68
|
+
# link from _index.md must point to a real file (the /validate-context
|
|
69
|
+
# skill, check #3).
|
|
70
|
+
run: |
|
|
71
|
+
set -euo pipefail
|
|
72
|
+
fail=0
|
|
73
|
+
for f in docs/decisions/[0-9]*.md; do
|
|
74
|
+
name=$(basename "$f")
|
|
75
|
+
if ! grep -q "$name" docs/decisions/_index.md; then
|
|
76
|
+
echo "::error file=docs/decisions/_index.md::ADR $name exists on disk but is not listed in the index."
|
|
77
|
+
fail=1
|
|
78
|
+
fi
|
|
79
|
+
done
|
|
80
|
+
while IFS= read -r ref; do
|
|
81
|
+
if [ -n "$ref" ] && [ ! -f "$ref" ]; then
|
|
82
|
+
echo "::error file=docs/decisions/_index.md::Index links to a missing file: $ref"
|
|
83
|
+
fail=1
|
|
84
|
+
fi
|
|
85
|
+
done < <(grep -oE 'docs/decisions/[0-9]+-[a-zA-Z0-9-]+\.md' docs/decisions/_index.md | sort -u)
|
|
86
|
+
exit $fail
|
|
87
|
+
|
|
88
|
+
- name: ADR completeness (5 mandatory sections)
|
|
89
|
+
# House ADR format: Status, Context, Decision, Alternatives Considered,
|
|
90
|
+
# Consequences (Date is also present but not gated here).
|
|
91
|
+
run: |
|
|
92
|
+
set -euo pipefail
|
|
93
|
+
fail=0
|
|
94
|
+
for f in docs/decisions/[0-9]*.md; do
|
|
95
|
+
for section in '## Status' '## Context' '## Decision' '## Alternatives Considered' '## Consequences'; do
|
|
96
|
+
if ! grep -qxF "$section" "$f"; then
|
|
97
|
+
echo "::error file=$f::Missing required ADR section '$section'."
|
|
98
|
+
fail=1
|
|
99
|
+
fi
|
|
100
|
+
done
|
|
101
|
+
done
|
|
102
|
+
exit $fail
|
|
103
|
+
|
|
104
|
+
- name: CLAUDE.md is an index (<= 150 lines)
|
|
105
|
+
run: |
|
|
106
|
+
set -euo pipefail
|
|
107
|
+
lines=$(wc -l < CLAUDE.md)
|
|
108
|
+
if [ "$lines" -gt 150 ]; then
|
|
109
|
+
echo "::error file=CLAUDE.md::CLAUDE.md is $lines lines (> 150) — it must stay an index of @-references, not a long-form doc."
|
|
110
|
+
exit 1
|
|
111
|
+
fi
|
|
112
|
+
echo "CLAUDE.md: $lines lines (<= 150)."
|
|
113
|
+
|
|
114
|
+
- name: CLAUDE.md @-references resolve
|
|
115
|
+
run: |
|
|
116
|
+
set -euo pipefail
|
|
117
|
+
fail=0
|
|
118
|
+
for ref in $(grep -oE '@[A-Za-z0-9_./-]+' CLAUDE.md | sed 's/^@//'); do
|
|
119
|
+
if [ ! -e "$ref" ]; then
|
|
120
|
+
echo "::error file=CLAUDE.md::@-reference does not resolve: $ref"
|
|
121
|
+
fail=1
|
|
122
|
+
fi
|
|
123
|
+
done
|
|
124
|
+
exit $fail
|
|
125
|
+
|
|
126
|
+
- name: Skill-set consistency (ADR-015)
|
|
127
|
+
# Every skill under .claude/skills/ is listed in the CONVENTIONS
|
|
128
|
+
# "CFD workflow (Skills)" table, and vice versa.
|
|
129
|
+
run: |
|
|
130
|
+
set -euo pipefail
|
|
131
|
+
section=$(awk '/^## CFD workflow/{f=1} f&&/^## /&&!/CFD workflow/{exit} f' docs/CONVENTIONS.md)
|
|
132
|
+
dirs=$(ls -1 .claude/skills | sort)
|
|
133
|
+
table=$(printf '%s\n' "$section" | grep -oE '`[a-z][a-z-]+`' | tr -d '`' | sort -u)
|
|
134
|
+
if ! diff <(printf '%s\n' "$dirs") <(printf '%s\n' "$table") >/dev/null; then
|
|
135
|
+
echo "::error file=docs/CONVENTIONS.md::Skill set mismatch between .claude/skills/ and the CONVENTIONS 'CFD workflow' table:"
|
|
136
|
+
diff <(printf '%s\n' "$dirs") <(printf '%s\n' "$table") || true
|
|
137
|
+
exit 1
|
|
138
|
+
fi
|
|
139
|
+
echo "Skill set consistent."
|
|
140
|
+
|
|
141
|
+
- name: api_request() boundary (ADR-003)
|
|
142
|
+
# All Vector-portal HTTP must go through api_request(); the only files
|
|
143
|
+
# allowed to touch httpx directly are the client and the auth bootstrap.
|
|
144
|
+
run: |
|
|
145
|
+
set -euo pipefail
|
|
146
|
+
if git grep -nE 'httpx\.(request|get|post|put|delete|patch|stream|Client|AsyncClient)' -- 'src/' ':!src/nemo_cli/api/client.py' ':!src/nemo_cli/auth/service.py'; then
|
|
147
|
+
echo "::error::Direct httpx use outside api_request()/sign_in — ADR-003 forbids. Route the call through api_request() in src/nemo_cli/api/client.py."
|
|
148
|
+
exit 1
|
|
149
|
+
fi
|
|
150
|
+
echo "ADR-003 guard: no direct httpx use outside the allowed files."
|
|
151
|
+
|
|
152
|
+
- name: PII guard (no real RUTs in tracked files)
|
|
153
|
+
# CONVENTIONS forbids real PII in committed files. The synthetic dummy
|
|
154
|
+
# RUT (12.345.678-*) is allowed in tests/docs. Real RUT digit-bodies
|
|
155
|
+
# live in the PII_RUT_DENYLIST secret (pipe-separated 8-digit bodies, no
|
|
156
|
+
# dots/DV) — kept out of this public file. On forks the secret is unset
|
|
157
|
+
# and this step is skipped.
|
|
158
|
+
env:
|
|
159
|
+
PII_RUT_DENYLIST: ${{ secrets.PII_RUT_DENYLIST }}
|
|
160
|
+
run: |
|
|
161
|
+
set -euo pipefail
|
|
162
|
+
if [ -z "${PII_RUT_DENYLIST:-}" ]; then
|
|
163
|
+
echo "PII guard: no denylist secret configured (fork or unset) — skipping."
|
|
164
|
+
exit 0
|
|
165
|
+
fi
|
|
166
|
+
if git grep -nE "$PII_RUT_DENYLIST" -- src/ tests/ docs/ pyproject.toml; then
|
|
167
|
+
echo "::error::Real RUT digits found in tracked files — PII leak per CONVENTIONS. Use a synthetic value (e.g. 12.345.678-0)."
|
|
168
|
+
exit 1
|
|
169
|
+
fi
|
|
170
|
+
echo "PII guard: no forbidden RUT digits found."
|
|
@@ -12,10 +12,10 @@ jobs:
|
|
|
12
12
|
runs-on: ubuntu-latest
|
|
13
13
|
steps:
|
|
14
14
|
- name: Checkout
|
|
15
|
-
uses: actions/checkout@
|
|
15
|
+
uses: actions/checkout@df4cb1c069e1874edd31b4311f1884172cec0e10 # v6.0.3
|
|
16
16
|
|
|
17
17
|
- name: Set up Python
|
|
18
|
-
uses: actions/setup-python@
|
|
18
|
+
uses: actions/setup-python@a309ff8b426b58ec0e2a45f0f869d46889d02405 # v6.2.0
|
|
19
19
|
with:
|
|
20
20
|
python-version: '3.12'
|
|
21
21
|
|
|
@@ -26,7 +26,7 @@ jobs:
|
|
|
26
26
|
run: python -m build
|
|
27
27
|
|
|
28
28
|
- name: Upload artifacts
|
|
29
|
-
uses: actions/upload-artifact@
|
|
29
|
+
uses: actions/upload-artifact@043fb46d1a93c77aae656e7c1c64a875d1fc6a0a # v7.0.1
|
|
30
30
|
with:
|
|
31
31
|
name: python-package-distributions
|
|
32
32
|
path: dist/
|
|
@@ -42,7 +42,7 @@ jobs:
|
|
|
42
42
|
id-token: write
|
|
43
43
|
steps:
|
|
44
44
|
- name: Download artifacts
|
|
45
|
-
uses: actions/download-artifact@
|
|
45
|
+
uses: actions/download-artifact@3e5f45b2cfb9172054b4087a40e8e0b5a5461e7c # v8.0.1
|
|
46
46
|
with:
|
|
47
47
|
name: python-package-distributions
|
|
48
48
|
path: dist/
|
|
@@ -64,7 +64,7 @@ jobs:
|
|
|
64
64
|
id-token: write
|
|
65
65
|
steps:
|
|
66
66
|
- name: Download artifacts
|
|
67
|
-
uses: actions/download-artifact@
|
|
67
|
+
uses: actions/download-artifact@3e5f45b2cfb9172054b4087a40e8e0b5a5461e7c # v8.0.1
|
|
68
68
|
with:
|
|
69
69
|
name: python-package-distributions
|
|
70
70
|
path: dist/
|