Skip to content

Commit d309e5b

Browse files
djm81cursoragentgithub-code-quality[bot]
authored
Finalize and archive debug log change (#161)
* perf: optimize startup performance with metadata tracking and update command (#142) * feat: implement backlog field mapping and refinement improvements - Add FieldMapper abstract base class with canonical field names - Implement GitHubFieldMapper and AdoFieldMapper - Add custom field mapping support with YAML templates - Add field validation in refinement (story_points, business_value, priority) - Add comprehensive unit and integration tests (42 tests) - Add custom field mapping documentation - Fix custom_field_mapping parameter connection - Add early validation for custom mapping files Implements OpenSpec change: improve-backlog-field-mapping-and-refinement * perf: optimize startup performance with metadata tracking and update command - Add metadata management module for tracking version and check timestamps - Optimize startup checks to only run when needed: - Template checks: Only after version changes detected - Version checks: Limited to once per day (24h threshold) - Add --skip-checks flag for CI/CD environments - Add new 'specfact update' command for manual update checking and installation - Add comprehensive unit and integration tests (35 tests, all passing) - Update startup_checks to use metadata for conditional execution - Ensure backward compatibility (first-time users still get all checks) Performance Impact: - Startup time: Reduced from several seconds to < 1-2 seconds - Network requests: Reduced from every startup to once per day - File system operations: Reduced from every startup to only after version changes Fixes #140 Implements OpenSpec change: optimize-startup-performance * feat: request offline_access scope for Azure DevOps refresh tokens - Add offline_access scope to Azure DevOps OAuth requests - Refresh tokens now last 90 days (vs 1 hour for access tokens) - Automatic token refresh via persistent cache (no re-authentication needed) - Update documentation to reflect 90-day refresh token lifetime This addresses the issue where tokens were expiring too quickly. Refresh tokens obtained via offline_access scope enable automatic token renewal for 90 days without user interaction. Fixes token lifetime limitation issue * feat: improve CLI UX with banner control and upgrade command - Change banner to hidden by default, shown on first run or with --banner flag - Add simple version line (SpecFact CLI - vXYZ) for regular use - Rename 'update' command to 'upgrade' to avoid confusion - Update documentation for new banner behavior and upgrade command - Update startup checks message to reference 'specfact upgrade' * fix: suppress version line in test mode and fix field mapping issues - Suppress version line output in test mode and for help/version commands to prevent test failures - Fix ADO custom field mapping to honor --custom-field-mapping on writeback - Fix GitHub issue body updates to prevent duplicate sections - Ensure proper type handling for story points and business value calculations * Fix failed tests * chore: bump version to 0.26.7 and update changelog - Fixed adapter token validation tests (ADO and GitHub) - Resolved test timeout issues (commit history, AST parsing, Semgrep) - Improved test file discovery to exclude virtual environments - Added file size limits for AST parsing to prevent timeouts --------- Co-authored-by: Dominikus Nold <djm81@users.noreply.github.com> * fix: add missing ADO field mappings and assignee display (#145) * fix: add missing ADO field mappings and assignee display - Add Microsoft.VSTS.Common.AcceptanceCriteria to default field mappings - Update AdoFieldMapper to support multiple field name alternatives - Fix assignee extraction to include displayName, uniqueName, and mail - Add assignee display in preview output - Add interactive template mapping command (specfact backlog map-fields) - Update specfact init to copy backlog field mapping templates - Extend documentation with step-by-step guides Fixes #144 * test: add unit tests for ADO field mapping and assignee fixes - Add tests for Microsoft.VSTS.Common.AcceptanceCriteria field extraction - Add tests for multiple field name alternatives - Add tests for assignee extraction with displayName, uniqueName, mail - Add tests for assignee filtering with multiple identifiers - Add tests for assignee display in preview output - Add tests for interactive mapping command - Add tests for template copying in init command - Update existing tests to match new assignee extraction behavior * docs: update init command docstring to mention template copying * docs: update documentation for ADO field mapping and interactive mapping features - Update authentication guide with ADO token resolution priority - Update custom field mapping guide with interactive mapping details - Update backlog refinement guide with progress indicators and required field display - Update Azure DevOps adapter guide with field mapping improvements - Update command reference with map-fields command documentation - Update troubleshooting guide with ADO-specific issues - Update README files with new features - Update getting started guide with template initialization Co-authored-by: Cursor <cursoragent@cursor.com> * fix: address review findings for ADO field mapping - Prefer System.* fields over Microsoft.VSTS.Common.* when writing updates (fixes issue where PATCH requests could fail for Scrum templates) - Preserve existing work_item_type_mappings when saving field mappings (prevents silent erasure of custom work item type mappings) Fixes review comments: - P1: Prefer System.AcceptanceCriteria when writing updates - P2: Preserve existing work_item_type_mappings on save Co-authored-by: Cursor <cursoragent@cursor.com> --------- Co-authored-by: Dominikus Nold <djm81@users.noreply.github.com> Co-authored-by: Cursor <cursoragent@cursor.com> * fix: mitigate code scanning vulnerabilities (#148) * fix: mitigate code scanning vulnerabilities - Fix ReDoS vulnerability in github_mapper.py by replacing regex with line-by-line processing - Fix incomplete URL sanitization in github.py, bridge_sync.py, and ado.py using proper URL parsing - Add explicit permissions blocks to 7 GitHub Actions jobs following least-privilege model Resolves all 13 code scanning findings: - 1 ReDoS error - 5 URL sanitization warnings - 7 missing workflow permissions warnings Fixes #147 Co-authored-by: Cursor <cursoragent@cursor.com> * fix: accept GitHub SSH host aliases in repo detection Accept ssh.github.com (port 443) in addition to github.com when detecting GitHub repositories via SSH remotes. This ensures repositories using git@ssh.github.com:owner/repo.git are properly detected as GitHub repos. Addresses review feedback on PR #148 Co-authored-by: Cursor <cursoragent@cursor.com> * fix: prevent async cleanup issues in test mode Remove manual Live display cleanup that could cause EOFError. The _safe_progress_display function already handles test mode by skipping progress display, so direct save path is sufficient. Fixes test_unlock_section failure with EOFError/ValueError. Co-authored-by: Cursor <cursoragent@cursor.com> --------- Co-authored-by: Dominikus Nold <djm81@users.noreply.github.com> Co-authored-by: Cursor <cursoragent@cursor.com> * fix: detect GitHub remotes using ssh:// and git:// URLs Extend URL pattern matching to support ssh://git@github.com/owner/repo.git and git://github.com/owner/repo.git formats in addition to existing https?:// and scp-style git@host:path URLs. This fixes a regression where these valid GitHub URL formats were not detected, causing detect() to return false for repos using these schemes. Addresses review feedback on PR #149 Co-authored-by: Cursor <cursoragent@cursor.com> * chore: bump version to 0.26.9 and update changelog - Update version from 0.26.8 to 0.26.9 - Add changelog entry for GitHub remote detection fix and code scanning fixes Co-authored-by: Cursor <cursoragent@cursor.com> * fix: compare GitHub SSH hostnames case-insensitively Lowercase host_part before comparison to handle mixed-case hostnames like git@GitHub.com:org/repo.git. This restores the case-insensitive behavior from the previous config_content.lower() check and prevents regression where valid GitHub repos with mixed-case hostnames would not be detected. Addresses review feedback on PR #150 Co-authored-by: Cursor <cursoragent@cursor.com> * Add openspec and workflow commands for transparency * Add specs from openspec * Remove aisp change which wasn't implemented * Fix openspec gitignore pattern * Update gitignore * Update contribution standards to use openspec for SDD * Migrate to new opsx openspec commands * Migrate workflow and openspec config * fix: bump version to 0.26.10 for PyPI publish - Sync version across pyproject.toml, setup.py, src/__init__.py, src/specfact_cli/__init__.py - Add CHANGELOG entry for 0.26.10 (fixes incorrect version publish issue) Co-authored-by: Cursor <cursoragent@cursor.com> * Update version and changelog * Add canonical user-friendly workitem url for ado workitems * Update to support OSPX * feat(backlog): implement refine --import-from-tmp and fix type-check (#156) * feat(backlog): implement --import-from-tmp for refine export/import round-trip - Add _parse_refined_export_markdown() to parse export-format markdown (ID, Body, Acceptance Criteria, optional title/metrics) - Import branch: read file, match by ID, update items; --write calls adapter.update_backlog_item() - Remove 'Import functionality pending implementation' message - Unit tests for parser (single item, AC/metrics, header-only, blocks without ID) - Bump version to 0.26.11 and sync across pyproject.toml, setup.py, src/__init__.py, src/specfact_cli/__init__.py - OpenSpec change: implement-backlog-refine-import-from-tmp (proposal, tasks, spec delta) Fixes #155 Co-authored-by: Cursor <cursoragent@cursor.com> * Fix type check issues --------- Co-authored-by: Dominikus Nold <djm81@users.noreply.github.com> Co-authored-by: Cursor <cursoragent@cursor.com> * feat: debug logs under ~/.specfact/logs and release 0.26.13 (#159) * feat: add debug logs under ~/.specfact/logs with operation metadata - User-level log dir: get_specfact_home_logs_dir() (~/.specfact/logs, 0o755) - debug_print() routes to console and rotating specfact-debug.log when --debug - debug_log_operation() for structured metadata (ADO, GitHub, backlog, init) - CLI init_debug_log_file() when --debug; help text updated Closes #158 OpenSpec change: add-debug-logs-specfact-home Co-authored-by: Cursor <cursoragent@cursor.com> * Add debug logging for selected commands at first * release: 0.26.13 - debug log parity for upgrade, versions and changelog - Log upgrade success (up to date) to ~/.specfact/logs/specfact-debug.log - Bump version to 0.26.13; sync pyproject.toml, setup.py, src/__init__.py, specfact_cli/__init__.py - CHANGELOG: 0.26.13 Fixed entry for upgrade debug parity Co-authored-by: Cursor <cursoragent@cursor.com> * Remove pr markdown --------- Co-authored-by: Dominikus Nold <djm81@users.noreply.github.com> Co-authored-by: Cursor <cursoragent@cursor.com> * Potential fix for pull request finding 'Empty except' Co-authored-by: Copilot Autofix powered by AI <223894421+github-code-quality[bot]@users.noreply.github.com> Signed-off-by: Dom <39115308+djm81@users.noreply.github.com> * Fix unused variable review * Fix unused variable review * Fix type and test errors * Finalize change * Change for debug logs archived --------- Signed-off-by: Dom <39115308+djm81@users.noreply.github.com> Co-authored-by: Dominikus Nold <djm81@users.noreply.github.com> Co-authored-by: Cursor <cursoragent@cursor.com> Co-authored-by: Copilot Autofix powered by AI <223894421+github-code-quality[bot]@users.noreply.github.com>
1 parent 9b8234f commit d309e5b

File tree

6 files changed

+133
-2
lines changed

6 files changed

+133
-2
lines changed

openspec/changes/add-debug-logs-specfact-home/CHANGE_VALIDATION.md renamed to openspec/changes/archive/2026-01-29-add-debug-logs-specfact-home/CHANGE_VALIDATION.md

File renamed without changes.

openspec/changes/add-debug-logs-specfact-home/design.md renamed to openspec/changes/archive/2026-01-29-add-debug-logs-specfact-home/design.md

File renamed without changes.

openspec/changes/add-debug-logs-specfact-home/proposal.md renamed to openspec/changes/archive/2026-01-29-add-debug-logs-specfact-home/proposal.md

File renamed without changes.

openspec/changes/add-debug-logs-specfact-home/specs/debug-logging/spec.md renamed to openspec/changes/archive/2026-01-29-add-debug-logs-specfact-home/specs/debug-logging/spec.md

File renamed without changes.

openspec/changes/add-debug-logs-specfact-home/tasks.md renamed to openspec/changes/archive/2026-01-29-add-debug-logs-specfact-home/tasks.md

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -31,7 +31,7 @@
3131
- [x] 4.1.3 In `src/specfact_cli/commands/backlog_commands.py`, when debug is on, log file read/write for export/import (path, prepared/finished/failed, status, error).
3232
- [x] 4.1.4 In `src/specfact_cli/commands/init.py`, when debug is on, ensure template resolution steps are also written to debug log (in addition to existing `debug_print()`); add debug_log_operation for template resolution status with caller.
3333
- [x] 4.1.5 Run `hatch run format` and `hatch run type-check`
34-
- [ ] 4.1.6 Apply the **debug log standard** consistently to remaining command modules and adapters: analyze, contract_cmd, drift, enforce, generate, import_cmd, migrate, plan, project_cmd, repro, sdd, spec, sync, update, validate. For each: log started/prepared → attempt (if multi-step) → success or failed with reason/error; include all context needed for anomaly analysis and bug reports (operation, target, status, error, extra: payload/response/reason sanitized). File ops: prepared → finished/failed. API ops: attempt → success/failed with payload, response, reason. No single-line INFO-style entries; every significant operation must have full context (see design “Debug log standard” and auth azure-devops reference).
34+
- [x] 4.1.6 Apply the **debug log standard** consistently to remaining command modules and adapters: analyze, contract_cmd, drift, enforce, generate, import_cmd, migrate, plan, project_cmd, repro, sdd, spec, sync, update, validate. For each: log started/prepared → attempt (if multi-step) → success or failed with reason/error; include all context needed for anomaly analysis and bug reports (operation, target, status, error, extra: payload/response/reason sanitized). File ops: prepared → finished/failed. API ops: attempt → success/failed with payload, response, reason. No single-line INFO-style entries; every significant operation must have full context (see design “Debug log standard” and auth azure-devops reference).
3535

3636
## 5. Tests and quality
3737

@@ -46,4 +46,4 @@
4646
- [x] 6.1.2 Update versions and increase patch version. Sync versions across `pyproject.toml`, `setup.py`, `src/__init__.py`, and `src/specfact_cli/__init__.py`.
4747
- [x] 6.1.3 Update CHANGELOG.md with new behavior and use the new patch version from 6.1.2.
4848
- [x] 6.1.4 Add `docs/reference/debug-logging.md` (user and developer reference); link from `docs/reference/commands.md`, `docs/reference/README.md`, `docs/reference/directory-structure.md`, `docs/guides/troubleshooting.md`, and `README.md`.
49-
- [ ] 6.1.5 Push branch and create Pull Request: `git push -u origin feature/add-debug-logs-specfact-home` then `gh pr create --base dev --title "feat: add debug logs under ~/.specfact/logs" --body "Closes #158. OpenSpec change: add-debug-logs-specfact-home."` (or use GitHub web UI).
49+
- [x] 6.1.5 Push branch and create Pull Request: `git push -u origin feature/add-debug-logs-specfact-home` then `gh pr create --base dev --title "feat: add debug logs under ~/.specfact/logs" --body "Closes #158. OpenSpec change: add-debug-logs-specfact-home."` (or use GitHub web UI).
Lines changed: 131 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,131 @@
1+
# debug-logging Specification
2+
3+
## Purpose
4+
TBD - created by archiving change add-debug-logs-specfact-home. Update Purpose after archive.
5+
## Requirements
6+
### Requirement: User-level debug log directory
7+
8+
The system SHALL provide a user-level directory for debug logs when debug mode is enabled.
9+
10+
#### Scenario: Resolve ~/.specfact/logs
11+
12+
- **GIVEN** debug mode may be enabled
13+
- **WHEN** `get_specfact_home_logs_dir()` is called
14+
- **THEN** returns path equivalent to `os.path.expanduser("~/.specfact/logs")`
15+
- **AND** creates the directory with `os.makedirs(..., mode=0o755, exist_ok=True)` on first use
16+
17+
#### Scenario: No directory when debug is off
18+
19+
- **GIVEN** debug mode is disabled
20+
- **WHEN** no debug log has been written in this run
21+
- **THEN** `~/.specfact/logs` is not required to exist
22+
- **AND** `get_specfact_home_logs_dir()` may still return the path for callers that need it
23+
24+
### Requirement: Debug output routing
25+
26+
The system SHALL route debug output to both console and a debug log file when debug mode is enabled.
27+
28+
#### Scenario: debug_print writes to console and file when debug on
29+
30+
- **GIVEN** debug mode is enabled and debug log file is initialized
31+
- **WHEN** `debug_print(...)` is called
32+
- **THEN** output is written to the configured Rich console (current behavior)
33+
- **AND** the same content is appended to the debug log file under `~/.specfact/logs`
34+
35+
#### Scenario: debug_print console-only when debug off
36+
37+
- **GIVEN** debug mode is disabled
38+
- **WHEN** `debug_print(...)` is called
39+
- **THEN** no output is produced (current behavior)
40+
- **AND** no debug log file is written
41+
42+
### Requirement: Structured operation metadata
43+
44+
The system SHALL support logging structured operation metadata when debug mode is enabled.
45+
46+
#### Scenario: debug_log_operation no-op when debug off
47+
48+
- **GIVEN** debug mode is disabled
49+
- **WHEN** `debug_log_operation(operation=..., target=..., status=..., error=...)` is called
50+
- **THEN** no log file write occurs
51+
- **AND** no console output is produced
52+
53+
#### Scenario: debug_log_operation writes metadata when debug on
54+
55+
- **GIVEN** debug mode is enabled and debug log file is initialized
56+
- **WHEN** `debug_log_operation(operation="api_request", target=url_redacted, status=200, error=None)` is called
57+
- **THEN** a structured log line (or block) is written to the debug log file
58+
- **AND** the line includes operation, target, status, and optionally error and extra fields
59+
- **AND** sensitive values in target or extra are redacted (e.g. via LoggerSetup.redact_secrets)
60+
61+
#### Scenario: Adapters log API metadata when debug on
62+
63+
- **GIVEN** debug mode is enabled
64+
- **WHEN** an adapter performs an API request (e.g. ADO WIQL, Work Items PATCH, GitHub REST)
65+
- **THEN** the adapter logs operation metadata (operation type, URL redacted, method, status code)
66+
- **AND** on failure, logs error snippet or response body (redacted)
67+
- **AND** does not log full request/response bodies that may contain secrets
68+
69+
### Requirement: Debug log standard (consistent pattern for anomaly analysis and bug reports)
70+
71+
The system SHALL apply a consistent debug log pattern for every significant operation when debug mode is enabled, so that logs support anomaly analysis, unexpected error/failure diagnosis, reporting, and bug reports (production-tool quality).
72+
73+
#### Scenario: Every significant operation has started, progress, and outcome
74+
75+
- **GIVEN** debug mode is enabled
76+
- **WHEN** a significant operation is performed (auth flow, file I/O, API call, template resolution, or any operation that can fail or affect behavior)
77+
- **THEN** the implementation logs at least: **started/prepared** (once at begin), **attempt** (for each distinct step if multi-step), and **outcome** (exactly once: success with reason/method/cache or failed with error and reason)
78+
- **AND** no operation is represented by only a single INFO-style line without outcome and reason
79+
- **AND** structured lines include operation, target (redacted), status, and when applicable error, extra (payload/response/reason sanitized), caller
80+
81+
#### Scenario: Reference implementation
82+
83+
- **GIVEN** the auth azure-devops flow
84+
- **WHEN** debug mode is enabled and the user runs the OAuth flow
85+
- **THEN** the debug log contains: started → cache_prepared → attempt (interactive_browser) → success or fallback (with reason) → attempt (device_code) → success or failed (with error/reason) → success (token_stored with method/cache)
86+
- **AND** a reader can determine from the log alone whether the flow succeeded or failed and why
87+
88+
### Requirement: Debug log context (timestamp, caller, file/API details)
89+
90+
The system SHALL include context in every debug log line when debug mode is enabled.
91+
92+
#### Scenario: Timestamp on every line
93+
94+
- **GIVEN** debug mode is enabled and debug log file is initialized
95+
- **WHEN** any line is written to the debug log file (via debug_print or debug_log_operation)
96+
- **THEN** the line is prefixed with a timestamp (e.g. `%(asctime)s | %(message)s` with datefmt `%Y-%m-%d %H:%M:%S`)
97+
98+
#### Scenario: Caller (module/method) in structured lines
99+
100+
- **GIVEN** debug mode is enabled
101+
- **WHEN** `debug_log_operation(..., caller=...)` is called with a caller string (e.g. `module:function`)
102+
- **THEN** the structured log line includes the caller in the payload
103+
- **AND** call sites may infer caller via inspect or pass explicitly
104+
105+
#### Scenario: File operations log prepared / finished / failed
106+
107+
- **GIVEN** debug mode is enabled
108+
- **WHEN** a command or adapter performs file IO (read/write)
109+
- **THEN** it logs operation metadata with status prepared/started before the operation
110+
- **AND** logs again with status finished or failed and error/reason when applicable
111+
- **AND** target is the path (redacted if sensitive); extra may include size, mime, etc.
112+
113+
#### Scenario: API operations log operation, URL, payload (sanitized), response, status, error, reason
114+
115+
- **GIVEN** debug mode is enabled
116+
- **WHEN** an adapter performs an API request
117+
- **THEN** it logs operation metadata with operation type, target (URL redacted), status (HTTP or success/failure)
118+
- **AND** extra includes payload (sanitized via LoggerSetup.redact_secrets), response (sanitized), and reason when applicable
119+
- **AND** on failure, error and reason are included
120+
121+
### Requirement: Backward compatibility
122+
123+
The system SHALL preserve existing behavior when debug mode is disabled.
124+
125+
#### Scenario: get_runtime_logs_dir unchanged
126+
127+
- **GIVEN** any mode
128+
- **WHEN** `get_runtime_logs_dir()` is called
129+
- **THEN** returns the same path as before (repo-relative logs or /app/logs in Docker)
130+
- **AND** behavior of LoggerSetup and existing loggers is unchanged
131+

0 commit comments

Comments
 (0)