Skip to content

Commit bbebf04

Browse files
committed
Add strict dogfood verification
1 parent 43d6828 commit bbebf04

11 files changed

Lines changed: 69 additions & 8 deletions

File tree

README.md

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -44,7 +44,7 @@ feishu-bot browser open --url "<authorization_url>"
4444
feishu-bot oauth token --code <code> --code-verifier <code_verifier> --save-env --env-file private/local.env
4545
feishu-bot oauth refresh --save-env --env-file private/local.env
4646
feishu-bot oauth user-info
47-
feishu-bot dogfood verify --module task --module search --auto-refresh-user-token
47+
feishu-bot dogfood verify --module task --module search --auto-refresh-user-token --strict
4848
```
4949

5050
## Code layout

docs/AI-USAGE.md

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -22,7 +22,7 @@ Use `--json` for machine parsing:
2222
```bash
2323
feishu-bot --json manifest
2424
feishu-bot --json dogfood verify --module message --include-response
25-
feishu-bot --json dogfood verify --module task --module search --auto-refresh-user-token
25+
feishu-bot --json dogfood verify --module task --module search --auto-refresh-user-token --strict
2626
```
2727

2828
For automation, read `manifest.workflow_layer` first. It contains the default

docs/DOGFOOD.md

Lines changed: 5 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -19,14 +19,18 @@ the JSON result instead of treating exit code 0 as success.
1919
When user-token probes report `expired_user_token`, automation may run:
2020

2121
```bash
22-
feishu-bot dogfood verify --module task --module search --auto-refresh-user-token --json
22+
feishu-bot dogfood verify --module task --module search --auto-refresh-user-token --strict --json
2323
```
2424

2525
This refreshes `FEISHU_USER_ACCESS_TOKEN` with `FEISHU_REFRESH_TOKEN`, saves the
2626
new tokens to `FEISHU_ENV_FILE`/`LARK_ENV_FILE` or `private/local.env`, updates
2727
the in-memory client token, and retries the expired probes. It is intentionally
2828
opt-in because it writes local credentials.
2929

30+
Use `--strict` in automation when the command should exit non-zero unless every
31+
selected probe is usable after optional retries. Usable statuses are `ok` and
32+
`no_data`.
33+
3034
For normal project reporting, prefer the workflow layer after the relevant
3135
module probes pass:
3236

src/app/cli/part01.rs

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -187,6 +187,12 @@ pub(in crate::app) struct DogfoodVerifyArgs {
187187
)]
188188
pub(in crate::app) auto_refresh_user_token: bool,
189189

190+
#[arg(
191+
long,
192+
help = "Exit non-zero when any probe is not usable. Usable statuses are ok and no_data."
193+
)]
194+
pub(in crate::app) strict: bool,
195+
190196
#[arg(
191197
long,
192198
help = "Env file for --auto-refresh-user-token; defaults to FEISHU_ENV_FILE/LARK_ENV_FILE or private/local.env"

src/app/dogfood.rs

Lines changed: 19 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -19,13 +19,31 @@ pub(super) async fn run_dogfood_command(
1919
command: DogfoodCommand,
2020
raw_json: bool,
2121
) -> Result<()> {
22+
if let DogfoodCommand::Verify(args) = command {
23+
let strict = args.strict;
24+
let data = verify_dogfood(api, args).await?;
25+
let strict_passed = dogfood_verify_strict_passed(&data);
26+
print_response(raw_json, "dogfood completed", data)?;
27+
if strict && !strict_passed {
28+
std::process::exit(1);
29+
}
30+
return Ok(());
31+
}
32+
2233
let data = match command {
2334
DogfoodCommand::Publish(args) => publish_dogfood(api, args).await?,
24-
DogfoodCommand::Verify(args) => verify_dogfood(api, args).await?,
35+
DogfoodCommand::Verify(_) => unreachable!("verify is handled before dispatch"),
2536
};
2637
print_response(raw_json, "dogfood completed", data)
2738
}
2839

40+
pub(in crate::app) fn dogfood_verify_strict_passed(data: &Value) -> bool {
41+
data.pointer("/data/summary/not_ok")
42+
.and_then(Value::as_u64)
43+
.unwrap_or(1)
44+
== 0
45+
}
46+
2947
async fn run_dogfood_message_loop_probe(
3048
api: &mut FeishuClient,
3149
to: Option<String>,

src/app/dogfood/read.rs

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -93,6 +93,7 @@ pub(super) async fn verify_dogfood(
9393
"include_response": args.include_response,
9494
"module_filter": args.module,
9595
"auto_refresh_user_token": args.auto_refresh_user_token,
96+
"strict": args.strict,
9697
},
9798
"environment": {
9899
"base_url": api.config.base_url,

src/app/help/entry.rs

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -112,7 +112,7 @@ pub(in crate::app) const DOGFOOD_AFTER_HELP: &str = r##"AI-safe dogfood workflow
112112
feishu-bot dogfood verify --write --module doc --module base --module task
113113
feishu-bot dogfood verify --write --module board --include-response
114114
feishu-bot dogfood verify --send-loop-check --to "$FEISHU_USER_ID"
115-
feishu-bot dogfood verify --module task --module search --auto-refresh-user-token
115+
feishu-bot dogfood verify --module task --module search --auto-refresh-user-token --strict
116116
117117
This is the preferred final step after adding a new CLI capability. It creates
118118
one standalone docx, writes the content, reads the doc back, attempts Wiki when
@@ -126,7 +126,8 @@ as ok, no_data, missing_scope, missing_user_token, expired_user_token,
126126
missing_helpdesk_config, upstream_api_error, or api_error.
127127
Default probes are read-only; --write and --send-loop-check intentionally create
128128
real Feishu data. --auto-refresh-user-token intentionally refreshes and saves
129-
the user token before retrying expired user-token probes. Failed probes include
129+
the user token before retrying expired user-token probes. --strict exits non-zero
130+
when any probe is still not usable after retries. Failed probes include
130131
remediation JSON with grant URLs, browser commands, required env vars, and rerun
131132
commands for the next AI step.
132133
"##;

src/app/manifest.rs

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -111,7 +111,8 @@ pub(super) fn build_manifest() -> Result<Value> {
111111
"feishu-bot office report --project \"AI Project\" --title \"Capability Demo\" --file demo.md --base-record --pin --json",
112112
"feishu-bot office inbox --project \"AI Project\" --from-now --json",
113113
"feishu-bot office search --project \"AI Project\" --query \"decision\" --json",
114-
"feishu-bot dogfood verify --module message --json"
114+
"feishu-bot dogfood verify --module message --json",
115+
"feishu-bot dogfood verify --module task --module search --auto-refresh-user-token --strict --json"
115116
],
116117
"local_safe_commands": [
117118
"feishu-bot office list --json",

src/app/manifest/modules/workflow.rs

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -72,7 +72,7 @@ pub(in crate::app) fn workflow_manifest_modules() -> Vec<Value> {
7272
"examples": [
7373
"feishu-bot dogfood verify",
7474
"feishu-bot dogfood verify --module calendar --module task --include-response",
75-
"feishu-bot dogfood verify --module task --module search --auto-refresh-user-token",
75+
"feishu-bot dogfood verify --module task --module search --auto-refresh-user-token --strict",
7676
"feishu-bot dogfood verify --write --module doc --module base --module task",
7777
"feishu-bot dogfood verify --write --module board --include-response",
7878
"feishu-bot dogfood publish --title \"Base role v2 demo\" --file dogfood/demo.md",
@@ -82,6 +82,7 @@ pub(in crate::app) fn workflow_manifest_modules() -> Vec<Value> {
8282
"known_permission_edges": [
8383
"dogfood verify exits successfully even when probes fail; inspect data.summary and per-probe status.",
8484
"--auto-refresh-user-token refreshes FEISHU_USER_ACCESS_TOKEN with FEISHU_REFRESH_TOKEN, saves it to FEISHU_ENV_FILE/LARK_ENV_FILE or private/local.env, and retries expired user-token probes.",
85+
"--strict exits non-zero when any probe remains outside the usable statuses ok/no_data after optional retries.",
8586
"Failed dogfood verify probes include remediation JSON with grant URLs, browser commands, env vars, and rerun commands.",
8687
"dogfood verify defaults to read-only probes. --write and --send-loop-check intentionally create Feishu data.",
8788
"Defaults to FEISHU_USER_ID for delivery and returns an error if no receiver is configured.",

src/app/tests/dogfood.rs

Lines changed: 21 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -9,13 +9,15 @@ fn parses_dogfood_auto_refresh_args_for_ai() {
99
"--module",
1010
"task",
1111
"--auto-refresh-user-token",
12+
"--strict",
1213
"--refresh-env-file",
1314
"private/local.env",
1415
]);
1516
match cli.command {
1617
Commands::Dogfood(DogfoodCommand::Verify(args)) => {
1718
assert_eq!(args.module, vec!["task"]);
1819
assert!(args.auto_refresh_user_token);
20+
assert!(args.strict);
1921
assert_eq!(
2022
args.refresh_env_file.unwrap(),
2123
PathBuf::from("private/local.env")
@@ -25,6 +27,25 @@ fn parses_dogfood_auto_refresh_args_for_ai() {
2527
}
2628
}
2729

30+
#[test]
31+
fn evaluates_dogfood_strict_summary() {
32+
assert!(dogfood_verify_strict_passed(&json!({
33+
"data": {
34+
"summary": {
35+
"not_ok": 0
36+
}
37+
}
38+
})));
39+
assert!(!dogfood_verify_strict_passed(&json!({
40+
"data": {
41+
"summary": {
42+
"not_ok": 1
43+
}
44+
}
45+
})));
46+
assert!(!dogfood_verify_strict_passed(&json!({})));
47+
}
48+
2849
#[test]
2950
fn detects_loop_check_probe_content() {
3051
let probe = probe_value(Ok(json!({

0 commit comments

Comments
 (0)