Skip to content

Close four of the gaps the coverage manifest recorded - #86

Merged
giordano-lucas merged 2 commits into
mainfrom
feat/close-coverage-gaps
Aug 31, 2026
Merged

Close four of the gaps the coverage manifest recorded#86
giordano-lucas merged 2 commits into
mainfrom
feat/close-coverage-gaps

Conversation

@giordano-lucas

@giordano-lucas giordano-lucas commented Aug 31, 2026

Copy link
Copy Markdown
Member

#85 and nottelabs/notte-skills#42 have merged; this is now based on main and carries only its own two commits.

Why

The manifest #85 introduced listed five endpoints as "not exposed yet". Four are worth having, so they're commands now and the skip lines are gone — the file working as intended, as a list of decisions to revisit rather than a place gaps go to be forgotten. profiles duplicate stays listed; it's already proposed in #53.

notte personas update --persona-id <id> --name "checkout tester"
notte profiles cookies --profile-id <id>
notte profiles cookies-set --profile-id <id> --file cookies.json
notte usage logs [--endpoint /sessions/start] [--page N]
  • personas update is generated: PATCH /personas/{persona_id} is a JSON body behind a $ref, so it needed an endpointMap entry and nothing else.
  • profiles cookies-set accepts either shape a cookies file comes in — a bare array (Playwright's storageState, the browser extensions) or an object with a cookies key. Making the caller reshape their own export first would be a papercut for no reason. --source-format and --mode are sent only when passed.
  • usage logs exposes --endpoint, --only-current-token and --include-system alongside the shared pagination flags. only_active is deliberately left out: it's the generic listing filter, and a request log is never active or inactive.

--instructions--run-instructions

The field documents a function for whoever calls it — how long a run takes, what each variable means, which sites it trips over. I had described it as configuration for the self-healing agent, which is what the bare name reads like and is not what it is. Renamed, with the help text and both repos' docs rewritten:

notte functions configure --run-instructions \
  "Takes ~3 min, so call it async. Hits a captcha on the login page every few runs.
   \`query\` is the search term, \`max_items\` caps the results at 50."

The API field is untouched — only the flag is renamed, through a new command-scoped override in the generator so the name stays declared in one place. Free to do: v0.0.37 predates #84, so this flag has never shipped in a release. notte page scrape --instructions is a different flag and is untouched.

Checker fix

The skill check now also requires documentation for a command that both runs and has subcommands. notte usage becomes one in this PR, and the old leaf-only rule would have let it slip out of the check the moment it grew usage logs.

Verification

  • personas update renames a real persona on staging and reads back (persona deleted afterwards)
  • The other three are covered by mock-server tests asserting the actual request: PATCH method and body, both cookie file shapes, and that unpassed filters aren't sent
  • make check-endpoints✓ 94 endpoints, 32 recorded exceptions (was 36)
  • make check-skills against the updated skills branch → ✓ 90 commands

usage logs could not be verified live. /usage/logs returns 503 Service temporarily unavailable after ~25s to plain curl on staging, before any of this code is involved — worth a look independently of this PR.

🤖 Generated with Claude Code

@greptile-apps

greptile-apps Bot commented Aug 31, 2026

Copy link
Copy Markdown

Greptile Summary

The PR exposes persona updates, profile cookie import/export, and usage-log retrieval while renaming the function metadata flag to --run-instructions.

  • Adds generated and hand-written command wiring for the newly exposed API endpoints.
  • Accepts wrapped and bare-array cookie exports, with validation preventing accidental cookie clearing.
  • Extends endpoint, documentation, generator, and coverage-checker tests.

Confidence Score: 5/5

The PR appears safe to merge.

No blocking failure remains.

Important Files Changed

Filename Overview
internal/cmd/profiles.go Adds profile cookie retrieval and import commands, including support for both documented file shapes and validation against empty cookie sets.
internal/cmd/coveragegaps_test.go Adds mock-server coverage for persona updates, profile cookie operations, empty cookie validation, and usage-log filters.
internal/cmd/usage.go Adds the usage logs subcommand with pagination and optional request filters.
internal/cmd/personas.go Adds and wires the persona update command.
scripts/gen-flags/parser.go Extends flag generation to support command-scoped flag-name overrides.
scripts/checkcoverage/skills.go Updates documentation coverage checks to include runnable commands that also have subcommands.

Reviews (3): Last reviewed commit: "fix: refuse an empty cookie set instead ..." | Re-trigger Greptile

Comment thread internal/cmd/profiles.go
@giordano-lucas
giordano-lucas force-pushed the feat/close-coverage-gaps branch from 88c5caa to e294251 Compare August 31, 2026 12:19
@giordano-lucas

Copy link
Copy Markdown
Member Author

@greptile review

giordano-lucas and others added 2 commits August 31, 2026 15:02
The manifest #85 introduced listed five endpoints as "not exposed yet". Four of
them are worth having, so they are commands now and the skip lines are gone -
which is the file working as intended, as a list of decisions to revisit rather
than a place gaps go to be forgotten. `profiles duplicate` stays listed: it is
already proposed in #53.

  notte personas update --persona-id <id> --name ...
  notte profiles cookies --profile-id <id>
  notte profiles cookies-set --profile-id <id> --file cookies.json
  notte usage logs [--endpoint ...] [--page N] [--page-size N]

`personas update` is generated: PATCH /personas/{persona_id} is a JSON body
behind a $ref, so it needed an endpointMap entry and nothing else.

`profiles cookies-set` accepts either shape a cookies file comes in - a bare
array, which is what Playwright's storageState and the browser extensions
write, or an object with a `cookies` key. Making the caller reshape their own
export first would be a papercut for no reason. --source-format and --mode are
sent only when passed.

`usage logs` exposes --endpoint, --only-current-token and --include-system
alongside the shared pagination flags. only_active is deliberately left out: it
is the generic listing filter and a request log is never active or inactive.

Two corrections come with them.

--instructions on `functions configure` is renamed --run-instructions, and its
help and both repositories' docs are rewritten. The field documents a function
for whoever calls it - how long a run takes, what each variable means, which
sites it trips over - and I had described it as configuration for the
self-healing agent, which is what the bare name reads like and is not what it
is. The API field is untouched; only the flag is renamed, through a new
command-scoped override in the generator so the name stays declared in one
place. Free to rename: v0.0.37 predates #84, so the flag has never shipped.

The skill checker now also requires documentation for a command that both runs
and has subcommands. `notte usage` is one as of this change, and the old
leaf-only rule would have let it slip out of the check the moment it grew
`usage logs`.

Verified against us-staging: `personas update` renames and reads back; the
other three are covered by mock-server tests asserting the request. `usage
logs` could not be verified live - /usage/logs returns 503 after ~25s to plain
curl on staging, before any of this code is involved.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
Greptile catch. `[]` parses fine as an array, so the bare-array branch sent an
empty cookie list - and --mode defaults to replace, so the API would have
emptied the profile. The wrapped-object branch already refused this; now both
do, through one error so they cannot drift apart again.

The test covers every shape that means "no cookies": a bare `[]`, a wrapped
empty list, an object with no cookies key, and whitespace. Each asserts nothing
reached the API, not just that an error came back.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
@giordano-lucas
giordano-lucas force-pushed the feat/close-coverage-gaps branch from e294251 to 98ede21 Compare August 31, 2026 13:02
@giordano-lucas
giordano-lucas changed the base branch from feat/coverage-guards to main August 31, 2026 13:03
@giordano-lucas
giordano-lucas merged commit 5cb1e2e into main Aug 31, 2026
4 checks passed
giordano-lucas added a commit that referenced this pull request Aug 31, 2026
#86 sat on main-facing review for a while with zero checks on it, and the
reason was not a failure - it was that nothing had ever run. It was based on
feat/coverage-guards, so the `branches: [main]` filter (which matches the PR's
base, not its head) kept both workflows off it entirely. Retargeting with
`gh pr edit 86 --base main` should have fixed that and did not: a `pull_request`
trigger with no `types:` defaults to [opened, synchronize, reopened], and
retargeting fires `edited`. `gh pr close 86 && gh pr reopen 86` was what
finally got a run, because `reopened` is in the default set.

The failure mode is what makes this worth fixing rather than remembering. A
skipped check is loud; an empty checks list is not. The PR page showed no
checks at all, which reads as "nothing to report" rather than "nothing looked".

So `edited` joins the types on CI and Integration Tests. Release is untouched -
it triggers on `v*` tag pushes only and has no pull_request trigger to get
wrong.

`edited` also fires on every title and description edit, and a prose fix
costing a ~7 minute integration run against real staging is a bad trade, so
each job carries `github.event.action != 'edited' || github.event.changes.base
!= null`. `changes.base` is in the payload only when the base moved - the
documented shape is base.ref.from and base.sha.from, verified against octokit's
pull_request$edited schema rather than assumed - so a retitle sends
changes.title, the guard skips, and a skipped job costs no minutes. On push
there is no `action` at all, so the guard is a no-op there.

`branches: [main]` stays. Dropping it would give stacked PRs CI while they
still point at their parent, but it would also run the full matrix twice for
every one of them - once against the parent and again after the retarget -
and the second run is the one that matters, since it is the only one that
tests the merge against what will actually be merged into. With `edited`
wired up that run now happens on its own. The gap that remains is real: a
stacked PR gets no signal until it is retargeted, and lefthook plus
`workflow_dispatch` on the integration workflow are the cover for that in the
meantime.

Deliberately not done: `workflow_dispatch` on CI. It looks like the obvious
mitigation for the paragraph above and is not one - a dispatched run builds
the branch head rather than refs/pull/N/merge, and its result does not attach
to the PR, so it would answer a different question than the one being asked.

Co-authored-by: Claude Opus 5 (1M context) <noreply@anthropic.com>
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant